В зависимости от вашей проблемы есть четыре вещи.
- Сделать трекер хранения временных файлов.
- Загрузка файлов сразу после выбора пользователем изображения (где-то в хранилище может быть временное расположение) сервер отвечает ссылкой уменьшенного изображения.
- Когда пользовательские сообщения формируются, которые передают только ссылки на эти изображения, тогда сохраняют сообщение с заданными ссылками.
- Эффективно обрабатывать временное местоположение. (Некоторой пакетной обработкой или некоторыми задачами с сельдереем.)
Решение
1. Создайте временное хранилище файлов для файлов, которые загружаются асинхронно.
Ваши временно загруженные файлы будут сохранены в модели TemporaryImage
в temp_folder
в виде следующей структуры.
Обновите models.py
models.py
class TemporaryImage(models.Model):
image = models.ImageField(upload_to="temp_folder/")
reduced_image = models.ImageField(upload_to="temp_thumb_folder/")
image_title = models.CharField(max_length=100, default='')
image_description = models.CharField(max_length=250, default='')
sequence = models.SmallIntegerField(validators=[MaxValueValidator(12), MinValueValidator(1)])
class Post(models.Model):
user = models.ForeignKey(User, related_name='posts')
title = models.CharField(max_length=250, unique=True)
slug = models.SlugField(allow_unicode=True, unique=True, max_length=500)
message = models.TextField()
post_image = models.ImageField()
class Extra (models.Model): #(Images)
post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='post_extra')
image = models.ImageField(upload_to='images/', blank=True, null=True, default='')
image_thumbnail = models.ImageField(upload_to='images/', blank=True, null=True, default='')
image_title = models.CharField(max_length=100, default='')
image_description = models.CharField(max_length=250, default='')
sequence = models.SmallIntegerField(validators=[MaxValueValidator(12), MinValueValidator(1)])
Здесь TemporaryImage
содержит временные загруженные файлы, поле raw_image
представляет исходный загруженный файл, а reduced_image
обозначает миниатюры , которые генерируются после загрузки файла.
Чтобы отправить запрос асинхронного Java-скрипта, вам нужно установить django-restframewrok
, выполнив следующую команду.
pip install djangorestframework
После установки restframework добавьте serializers.py со следующим кодом.
serializers.py
from rest_framework import serializers
class TemporaryImageUploadSerializer(serializers.ModelSerializer):
class Meta:
model = TemporaryImage
field = ('id', 'image',)
def create(self, validated_data):
raw_image = validated_data['raw_image']
# Generate raw image's thumbnail here
thumbnail = generate_thumbnail(raw_image)
validated_data['reduced_image'] = thumbnail
return super(TemporaryImageUploadSerializer, self).create(validated_data)
Этот сериализатор генерирует миниатюру, когда пользователь загружает файл асинхронно. Функция generate_thumbnail
сделает эту работу. Реализацию этого метода можно найти по здесь .
Добавьте этот сериализатор в viewset , как показано ниже
apis.py
from rest_framework.generics import CreateAPIView, DestroyAPIView
from .serializers import TemporaryImageUploadSerializer
# This api view is used to create model entry for temporary uploaded file
class TemporaryImageUploadView(CreateAPIView):
serializer_class = TemporaryImageUploadSerializer
queryset = TemporaryImage.objects.all()
class TemporaryImageDeleteView(DestroyAPIView):
lookup_field = 'id'
serializer_class = TemporaryImageUploadSerializer
queryset = TemporaryImage.objects.all()
Этот TemporaryImageUploadViewSet
создает POST
, PUT
, PATCH
, DELETE
методы для ваших загрузок.
Обновите urls.py , как показано ниже
urls.py
from .apis import TemporaryImageUploadView, TemporaryImageDeleteView
urlpatterns = [
...
url(r'^ajax/temp_upload/$', TemporaryImageUploadView.as_view()),
url(r'^ajax/temp_upload/(?P<user_uuid>[0-9]+)/$', TemporaryImageDeleteView.as_view()),
...
]
Это создаст следующие конечные точки для обработки асинхронных загрузок
<domain>/ajax/temp_upload/
POST
<domain>/ajax/temp_upload/{id}/
УДАЛИТЬ
Теперь эти конечные точки готовы к загрузке файлов
2. Загрузка файлов сразу после выбора пользователем изображения
Для этого вам нужно обновить template.py для обработки загрузок iamge, когда пользователь выбирает дополнительные изображения и публикует с помощью поля image
, загружает это в <domain>/ajax/temp_upload/
с помощью метода POST
, это вернет вас следующий образец данных JSON.
{
"id": 12,
"image": "/media/temp_folder/image12.jpg",
"reduced_image": "/media/temp_thumb_folder/image12.jpg",
}
Вы можете просмотреть изображение с помощью клавиши reduced_image
внутри json.
id
- это ссылка на временный загруженный файл, который необходимо сохранить где-то для передачи в форму Post
create. как скрытое поле.
Я не пишу код JavaScript, потому что ответ станет более длинным.
3. Когда формируются сообщения пользователя, которые передают только ссылки на эти изображения.
Загруженные файлы 'id
установлены как скрытое поле на formset
на странице HTML. Для работы с formset вам необходимо выполнить следующие действия.
forms.py
from django import forms
class TempFileForm(forms.ModelForm):
id = forms.HiddenInput()
class Meta:
model = TemporaryImage
fields = ('id',)
def clean(self):
cleaned_data = super().clean()
temp_id = cleaned_data.get("id")
if temp_id and not TemporaryImage.objects.filter(id=temp_id).first():
raise forms.ValidationError("Can not find valida temp file")
Это форма отдельного загруженного временного файла.
Вы можете справиться с этим, используя formset
в Django, как показано ниже
forms.py
from django.core.files.base import ContentFile
@login_required
def post_create(request):
ImageFormSet = formset_factory(TempFileForm, extra=12, max_num=12,
min_num=2)
if request.method == "POST":
form = PostForm(request.POST or None)
formset = ImageFormSet(request.POST or None, request.FILES or None)
if form.is_valid() and formset.is_valid():
instance = form.save(commit=False)
instance.user = request.user
post_image_create(request=request, post=instance) #This function is defined above
instance.save()
for index, f in enumerate(formset.cleaned_data):
try:
temp_photo = TemporaryImage.objects.get(id=f['id'])
photo = Extra(sequence=index+1, post=instance,
image_title=f['image_title'], image_description=f['image_description'])
photo.image.save(ContentFile(temp_photo.image.name,temp_photo.image.file.read()))
# remove temporary stored file
temp_photo.image.file.close()
temp_photo.delete()
photo.save()
except Exception as e:
break
return redirect('posts:single', username=instance.user.username, slug=instance.slug)
else:
form = PostForm()
formset = ImageFormSet(queryset=Extra.objects.none())
context = {
'form': form,
'formset': formset,
}
return render(request, 'posts/post_form.html', context)
Это сохранит сообщение с заданными ссылками (временные загруженные файлы).
4. Эффективно обрабатывать временное местоположение.
Вам необходимо обрабатывать temp_folder
и temp_thumb_folder
, чтобы поддерживать файловую систему в чистоте.
Предположим, пользователь загружает файл и не отправляет почтовую форму, чем вам нужно, чтобы удалить эти файлы.
Я знаю, что ответ стал слишком длинным, чтобы его прочитать, извиняюсь за это, но все же отредактируйте этот пост, если будут какие-то улучшения
Обратитесь https://medium.com/zeitcode/asynchronous-file-uploads-with-django-forms-b741720dc952 к посту, связанному с этим