update relations primarykeyrelatedfield ordering modelserializer framework foreign create python django url filefield

python - relations - Django REST Framework y FileField absolute url



modelserializer django rest framework (7)

He definido una aplicación Django simple que incluye el siguiente modelo:

class Project(models.Model): name = models.CharField(max_length=200) thumbnail = models.FileField(upload_to=''media'', null=True)

(Técnicamente sí, eso podría haber sido un ImageField).

En una plantilla, es bastante fácil incluir el valor MEDIA_URL (debidamente codificado en settings.py) como un prefijo a la URL de la miniatura. Lo siguiente funciona bien:

<div id="thumbnail"><img src="{{ MEDIA_URL }}{{ current_project.thumbnail }}" alt="thumbnail" width="400" height="300" border="0" /></div>

Usando DRF, he definido un descendiente HyperlinkedModelSerializer llamado ProjectSerializer:

class ProjectSerializer(serializers.HyperlinkedModelSerializer): class Meta: model = Project fields = ( ''id'' ,''url'', ''name'', ''thumbnail'')

Y he definido un descendiente ModelViewSet muy directo:

class ProjectViewSet(viewsets.ModelViewSet): queryset = Project.objects.all() serializer_class = ProjectSerializer

Una muestra del JSON resultante se ve así:

{ "id": 1, "url": "http://localhost:8000/api/v1/projects/1/", "name": "Institutional", "thumbnail": "media/institutional_thumb_1.jpg" }

Todavía no he podido averiguar cómo proporcionar un campo de miniaturas que incluya la url completa a la imagen en la representación JSON de mi proyecto.

Pensaría que tendría que crear un campo personalizado en el ProjectSerializer, pero no he tenido éxito.


Gracias, Shavenwarthog. Su referencia de ejemplo y documentación ayudó enormemente. Mi implementación es ligeramente diferente, pero muy cercana a lo que publicaste:

from SomeProject import settings class ProjectSerializer(serializers.HyperlinkedModelSerializer): thumbnail_url = serializers.SerializerMethodField(''get_thumbnail_url'') def get_thumbnail_url(self, obj): return ''%s%s'' % (settings.MEDIA_URL, obj.thumbnail) class Meta: model = Project fields = (''id'', ''url'', ''name'', ''thumbnail_url'')


Me resultó molesto escribir el mismo código para un campo de método serializado. Si ha configurado correctamente el MEDIA_ROOT en su URL de cubeta de S3, puede agregar un campo al serializador como:

class ProjectSerializer(serializers.ModelSerializer): logo_url = serializers.URLField(read_only=True, source=''logo.url'') class Meta: model = Project

logo es un ImageField en el modelo. no debe ser anulable para evitar errores como ValueError: The ''img'' attribute has no file associated with it.

Solo uso .build_absolute_uri en un campo de método de serializador para devolver direcciones URL absolutas que usan otras vistas en mi API. por ejemplo, en mi proyecto hay una URL /webviews/projects/<pk> que muestra un título y un botón que recopila información del usuario (es decir, no es exactamente lo que haría con los sufijos, ya que no es una simple representación de recurso pero incluye algo de lógica en su lugar). el punto final /projects/<pk>/ contiene un campo "webview_url" que se coloca allí, que se genera con SerializerMethodField. no es un medio


No hay necesidad de anulaciones o personalizaciones. DRF lo maneja automáticamente. Echa un vistazo a to_representation method of FileField :

def to_representation(self, value): if not value: return None use_url = getattr(self, ''use_url'', api_settings.UPLOADED_FILES_USE_URL) if use_url: if not getattr(value, ''url'', None): # If the file has not been saved it may not have a URL. return None url = value.url request = self.context.get(''request'', None) if request is not None: return request.build_absolute_uri(url) return url return value.name

Tenga en cuenta que no funcionará si el contexto del serializador no está configurado correctamente. Si está utilizando ViewSet s, no se preocupe, todo se hace de manera silenciosa, pero si está creando una instancia del serializador manualmente, debe pasar la solicitud en el contexto.

context = {''request'': request} serializer = ExampleSerializer(instance, context=context) return Response(serializer.data)

https://www.django-rest-framework.org/community/3.0-announcement/#file-fields-as-urls


Para obtener la url de un archivo que usa FileField, simplemente puede llamar al atributo url del FieldFile (esta es la instancia del archivo, no el campo), usa la clase Storage para determinar la url para este archivo. Es muy sencillo si está utilizando un almacenamiento externo como Amazon S3 o si su almacenamiento cambia.

El get_thumbnail_url sería así.

def get_thumbnail_url(self, obj): return obj.thumbnail.url

También puedes usarlo en la plantilla de esta manera:

{{ current_project.thumbnail.url }}


Prueba SerializerMethodField

Ejemplo (no probado):

class MySerializer(serializers.ModelSerializer): thumbnail_url = serializers.SerializerMethodField(''get_thumbnail_url'') def get_thumbnail_url(self, obj): return self.context[''request''].build_absolute_uri(obj.thumbnail_url)

La solicitud debe estar disponible para el serializador, de modo que pueda crear la URL absoluta completa para usted. Una forma es pasarlo explícitamente cuando se crea el serializador, similar a esto:

serializer = MySerializer(account, context={''request'': request})


Revisa tu configuración.py

ajustes de medios

Tuve el mismo error y encontré que:

MEDIA_URL = ''/ media /'' hizo el truco.

Antes solo tenia:

MEDIA_URL = ''media /''


Simplemente pase el contexto y pase el objeto de solicitud. si estas usando @api_view

serializer = CustomerSerializer(customer, context={"request": request})

Para el usuario de ViewSet, método get_serializer_context

class ProjectViewSet(viewsets.ModelViewSet): queryset = Project.objects.all() serializer_class = ProjectSerializer def get_serializer_context(self): return {''request'': self.request}