Django, разный результат между методом `all()` и методом `all().values()`.

Я столкнулся с проблемой, когда я не могу получить доступ к url некоторого изображения, используя метод values(), но он все еще может быть доступен, если это объект queryset, а не pythonic list:

class MyModel(models.Model): 
    img = models.ImageField(upload_to='media') # the image is stored in aws, hence it will produce a url
    def __str__(self):
      return f"{self.img.url}"

это пример модели, теперь давайте попробуем распечатать это на shell:

>>models.MyModel.objects.all()
<QuerySet[{'img':'https://aws/bucketlist.com/some_img.png'}]>

однако с помощью метода values():

>>models.MyModel.objects.all().values()
<QuerySet[{'img':'media/some_img.png'}]>

как вы можете видеть values() я получаю локальный путь, а не url к aws cloud

обратите внимание, что хранилище aws настроено правильно в django.

settings.py:

DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'

MEDIA_URL = '/media/'  

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


CKEDITOR_UPLOAD_PATH = "/media"

AWS_ACCESS_KEY_ID = os.environ.get('AWS_ACCESS_KEY_ID')  

AWS_SECRET_ACCESS_KEY = os.environ.get('AWS_SECRET_ACCESS_KEY')  

AWS_STORAGE_BUCKET_NAME = os.environ.get('AWS_STORAGE_BUCKET_NAME') 

AWS_S3_FILE_OVERWRITE = False  

AWS_DEFAULT_ACL = None  

DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'   

AWS_S3_REGION_NAME = "ap-southeast-2"  

AWS_S3_ADDRESSING_STYLE = "virtual"

Однако изображения появляются на AWS, и, похоже, все в порядке на стороне облака.

Это одна из мало причин не использовать .values() в первую очередь: это сделает запрос к базе данных, а затем преобразует элементы в словари, и таким образом потеряет всю логику модели, привязанную к ней. Это означает, что .img будет возвращать уже не объект FieldFile, а простую строку, и, таким образом, покажет путь относительно корня медиа, а не весь URL, как это обычно делается через FieldFile.

Ваш MyModelView также вообще не работает с сериализатором: вы просто сделали реализацию get, и поэтому в нем нет логики, которая работает с сериализатором.

Скорее всего, самый простой способ - просто работать с ListAPIView [classy-drf]:

from rest_framework.generics import ListAPIView


class MyModelView(ListAPIView):
    serializer_class = MyModelSerializer
    queryset = models.MyModel.objects.all()

или вы можете использовать метод get_queryset:

from rest_framework.generics import ListAPIView


class MyModelView(ListAPIView):
    serializer_class = MyModelSerializer
    queryset = models.MyModel.objects.all()

    def get_queryset(self, *args, **kwargs):
        data = MyModelSerializer(data=self.request.data)
        if data.is_valid():
            return super().get_queryset(*args, **kwargs).filter(data.data['name'])
        return models.MyModel.objects.none()

    def post(self, request):
        return self.get(request)

Но обычно вы не используете POST-запросы для получения данных, а для создания, обновления или удаления данных. Обычно используется строка запроса для фильтрации набора запросов.

Вернуться на верх