2018-07-13 12:10:39 +00:00
|
|
|
from django.utils.deconstruct import deconstructible
|
|
|
|
|
2017-06-23 21:00:42 +00:00
|
|
|
import os
|
|
|
|
import shutil
|
2018-07-13 12:10:39 +00:00
|
|
|
import uuid
|
|
|
|
|
2018-06-10 08:55:16 +00:00
|
|
|
from urllib.parse import parse_qs, urlencode, urlsplit, urlunsplit
|
2017-06-23 21:00:42 +00:00
|
|
|
|
2018-02-27 16:43:50 +00:00
|
|
|
from django.db import transaction
|
|
|
|
|
2017-06-23 21:00:42 +00:00
|
|
|
|
|
|
|
def rename_file(instance, field_name, new_name, allow_missing_file=False):
|
|
|
|
field = getattr(instance, field_name)
|
|
|
|
current_name, extension = os.path.splitext(field.name)
|
|
|
|
|
2018-06-09 13:36:16 +00:00
|
|
|
new_name_with_extension = "{}{}".format(new_name, extension)
|
2017-06-23 21:00:42 +00:00
|
|
|
try:
|
|
|
|
shutil.move(field.path, new_name_with_extension)
|
|
|
|
except FileNotFoundError:
|
|
|
|
if not allow_missing_file:
|
|
|
|
raise
|
2018-06-09 13:36:16 +00:00
|
|
|
print("Skipped missing file", field.path)
|
2017-06-23 21:00:42 +00:00
|
|
|
initial_path = os.path.dirname(field.name)
|
|
|
|
field.name = os.path.join(initial_path, new_name_with_extension)
|
|
|
|
instance.save()
|
|
|
|
return new_name_with_extension
|
2018-02-27 16:43:50 +00:00
|
|
|
|
|
|
|
|
|
|
|
def on_commit(f, *args, **kwargs):
|
2018-06-09 13:36:16 +00:00
|
|
|
return transaction.on_commit(lambda: f(*args, **kwargs))
|
2018-04-06 15:57:50 +00:00
|
|
|
|
|
|
|
|
|
|
|
def set_query_parameter(url, **kwargs):
|
|
|
|
"""Given a URL, set or replace a query parameter and return the
|
|
|
|
modified URL.
|
|
|
|
|
|
|
|
>>> set_query_parameter('http://example.com?foo=bar&biz=baz', 'foo', 'stuff')
|
|
|
|
'http://example.com?foo=stuff&biz=baz'
|
|
|
|
"""
|
|
|
|
scheme, netloc, path, query_string, fragment = urlsplit(url)
|
|
|
|
query_params = parse_qs(query_string)
|
|
|
|
|
|
|
|
for param_name, param_value in kwargs.items():
|
|
|
|
query_params[param_name] = [param_value]
|
|
|
|
new_query_string = urlencode(query_params, doseq=True)
|
|
|
|
|
|
|
|
return urlunsplit((scheme, netloc, path, new_query_string, fragment))
|
2018-07-13 12:10:39 +00:00
|
|
|
|
|
|
|
|
|
|
|
@deconstructible
|
|
|
|
class ChunkedPath(object):
|
|
|
|
def __init__(self, root, preserve_file_name=True):
|
|
|
|
self.root = root
|
|
|
|
self.preserve_file_name = preserve_file_name
|
|
|
|
|
|
|
|
def __call__(self, instance, filename):
|
|
|
|
uid = str(uuid.uuid4())
|
|
|
|
chunk_size = 2
|
|
|
|
chunks = [uid[i : i + chunk_size] for i in range(0, len(uid), chunk_size)]
|
|
|
|
if self.preserve_file_name:
|
|
|
|
parts = chunks[:3] + [filename]
|
|
|
|
else:
|
|
|
|
ext = os.path.splitext(filename)[1][1:].lower()
|
|
|
|
new_filename = "".join(chunks[3:]) + ".{}".format(ext)
|
|
|
|
parts = chunks[:3] + [new_filename]
|
|
|
|
return os.path.join(self.root, *parts)
|
2018-09-22 12:29:30 +00:00
|
|
|
|
|
|
|
|
|
|
|
def chunk_queryset(source_qs, chunk_size):
|
|
|
|
"""
|
|
|
|
From https://github.com/peopledoc/django-chunkator/blob/master/chunkator/__init__.py
|
|
|
|
"""
|
|
|
|
pk = None
|
|
|
|
# In django 1.9, _fields is always present and `None` if 'values()' is used
|
|
|
|
# In Django 1.8 and below, _fields will only be present if using `values()`
|
|
|
|
has_fields = hasattr(source_qs, "_fields") and source_qs._fields
|
|
|
|
if has_fields:
|
|
|
|
if "pk" not in source_qs._fields:
|
|
|
|
raise ValueError("The values() call must include the `pk` field")
|
|
|
|
|
|
|
|
field = source_qs.model._meta.pk
|
|
|
|
# set the correct field name:
|
|
|
|
# for ForeignKeys, we want to use `model_id` field, and not `model`,
|
|
|
|
# to bypass default ordering on related model
|
|
|
|
order_by_field = field.attname
|
|
|
|
|
|
|
|
source_qs = source_qs.order_by(order_by_field)
|
|
|
|
queryset = source_qs
|
|
|
|
while True:
|
|
|
|
if pk:
|
|
|
|
queryset = source_qs.filter(pk__gt=pk)
|
|
|
|
page = queryset[:chunk_size]
|
|
|
|
page = list(page)
|
|
|
|
nb_items = len(page)
|
|
|
|
|
|
|
|
if nb_items == 0:
|
|
|
|
return
|
|
|
|
|
|
|
|
last_item = page[-1]
|
|
|
|
# source_qs._fields exists *and* is not none when using "values()"
|
|
|
|
if has_fields:
|
|
|
|
pk = last_item["pk"]
|
|
|
|
else:
|
|
|
|
pk = last_item.pk
|
|
|
|
|
|
|
|
yield page
|
|
|
|
|
|
|
|
if nb_items < chunk_size:
|
|
|
|
return
|