Восстановление URL-адреса поля изображения Django/DRF из функции F()

У меня есть пример использования, где я пытаюсь переопределить URL изображения, если оно существует в нашей базе данных.

Вот секция набора запросов, из которой берется ImageField через F() запрос.

preferred_profile_photo=Case(
            When(
                # agent not exists
                Q(agent__id__isnull=False),
                then=F("agent__profile__profile_photo"),
            ),
            default=Value(None, output_field=ImageField()),
        )

Case-When разрешается правильно, но проблема в том, что значение, возвращаемое из F("agent__profile__profile_photo"), не является URL, который может быть использован пользовательским интерфейсом. Вместо этого это что-то вроде: "agentphoto/09bd7dc0-62f6-49ab-blah-6c57b23029d7/profile/1665342685--77e51d9c5asdf345364f774d0b2def48.jpeg"

Обычно я получаю URL через agent.profile.profile_photo.url, но при попытке выполнить preferred_profile_photo.url я получаю следующее: AttributeError: 'str' object has no attribute 'url'.

Я пробовал обернуть в Value(..., output_field=ImageField()) безрезультатно.

Суть заключается в получении url из ImageField после преобразования из F()

Для справки, я использую storages.backends.s3boto3.S3Boto3Storage.

Благодарю за любую помощь!

Django не хранит полный URL в БД. Он строит абсолютный URL на уровне кода. Цитата из docs:

Все, что будет храниться в вашей базе данных, это путь к файлу (относительно MEDIA_ROOT).

Для получения полного URL ваших файлов вы можете использовать метод build_absolute_uri(). Например, вы можете сделать это на уровне сериализатора:

class YourSerializer(ModelSerializer):
    preferred_profile_photo = serializers.SerializerMethodField()

    class Meta:
        model = YourModel
        fields = [
            'preferred_profile_photo',
        ]

    def get_preferred_profile_photo(self, obj):
        request = self.context.get('request')
        return request.build_absolute_uri(obj.preferred_profile_photo)

Я смог реализовать это, используя некоторую информацию из этого поста.

Вот вспомогательная функция, которую я использовал для реализации:

from django.core.files.storage import get_storage_class
def get_media_storage_url(file_name: str) -> str:
    """Takes the postgres stored ImageField value and converts it to
    the proper S3 backend URL. For use cases, where calling .url on the
    photo field is not feasible.

    Args:
        file_name (str): the value of the ImageField

    Returns:
        str: the full URL of the object usable by the UI
    """
    media_storage = get_storage_class()()
    return media_storage.url(name=file_name)
Вернуться на верх