Фреймворк Django Rest не обновляет поле изображения с помощью UpdateAPIView

#python-3.x #django #django-rest-framework

#python-3.x #django #django-rest-framework

Вопрос:

Все остальные поля обновляются правильно, кроме ImageField, который также не выдает никаких ошибок. В базе данных я вижу, что URL-адрес изображения обновляется, но в файловой системе изменений в media/ папке нет. Когда я использую модель, admin.site.register все работает отлично (следовательно, я должен был правильно настроить MEDIA_ROOT и MEDIA_URL), и я вижу файл, загруженный в media папку.

views.py

 class ProfileView(generics.UpdateAPIView, generics.RetrieveAPIView):
    queryset = Profile.objects.all()
    serializer_class = ProfileSerializer
    authentication_classes = [TokenAuthentication]
    permission_classes = [IsAuthenticated]

    def put(self, request):
        print(request.data)
        print(request.FILES)
        p = Profile.objects.get(user=request.user)
        serializer = ProfileSerializer(p)
        serializer.update(p, request.data, request.user)
        return Response(serializer.data)
    
    def get(self, request):
        p = Profile.objects.get(user=request.user)
        serializer = ProfileSerializer(p)
        return Response(serializer.data)
 

models.py

 class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    firstName = models.CharField(max_length=50)
    lastName = models.CharField(max_length=50)
    dob = models.DateField(null=True, blank=True)
    desc = models.CharField(max_length=500)
    genderChoices = [('M', 'Male'), ('F', 'Female')]
    gender = models.CharField(choices=genderChoices, max_length=1)
    image = models.ImageField(blank=True, null=True)

    def __str__(self):
        return self.firstName   " "   self.lastName

 

serializers.py

 class ProfileSerializer(serializers.ModelSerializer):
    class Meta:
        model = Profile
        fields = ('firstName', 'lastName', 'dob', 'desc', 'gender', 'image', )
    
    #TODO: write validators
    def update(self, instance, validated_data, user):
        p = Profile.objects.filter(user=user)
        p.update(
            firstName=validated_data['firstName'],
            lastName=validated_data['lastName'],
            dob=validated_data['dob'],
            gender=validated_data['gender'],
            image=validated_data['image'],
        )
 

Я использую Postman для тестирования, и это ответ, который я получаю, с URL-адресом изображения, который не существует при его посещении.

https://i.imgur.com/ujzbc95.png

Ответ №1:

Это потому, что вы используете QuerySet.update метод для обновления своего изображения. Этот метод предназначен для обновления всего набора запросов. Этот метод выполняет запись непосредственно в базу данных, поэтому он пропускает много «волшебства», которое обычно происходит в фоновом режиме при вызове Model.save метода. В частности, он пропускает всю обработку файла, включая сохранение этого файла в MEDIA_ROOT каталоге. Используйте Model.save вместо этого или обработайте сохранение файла в нужном месте вручную.

Кроме того, вам не нужно извлекать пользователя в этом методе, так как ваш сериализатор уже был вызван с profile в качестве аргумента, поэтому он должен быть доступен self.instance внутри вашего метода обновления.

Комментарии:

1. А, понял. На днях у меня были небольшие проблемы, когда я пытался использовать Profile.objects.get метод with update и прочитал, что он работает только с набором запросов, если я правильно помню. Другой способ — сделать это вручную p.field = value , а затем p.save() правильно?

2. Да, но сериализаторы DRF должны выполнять всю работу за вас, если вы используете их правильно.

Ответ №2:

установить ==> pip установить подушку

в settings.py добавить :

 import os

MEDIA_URL = "/media/" 
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
 

в urls.py добавить:

 from django.conf import settings
from django.conf.urls.static import static



if settings.DEBUG:
   urlpatterns  = static(settings.MEDIA_URL,document_root=settings.MEDIA_ROOT)
 

в моделях.py добавить:

 image = models.ImageField(blank=True, null=True, upload_to='images')
 

в apiview добавьте context={«запрос»:запрос}:

 def get(self, request):
    p = Profile.objects.get(user=request.user)
    serializer = ProfileSerializer(p, context={"request":request})
    return Response(serializer.data)