Django REST Framework et FileField absolute url
j'ai défini une application Django simple qui inclut le modèle suivant:
class Project(models.Model):
name = models.CharField(max_length=200)
thumbnail = models.FileField(upload_to='media', null=True)
(techniquement, oui, ça aurait pu être un champ D'image.)
dans un modèle, il est assez facile d'inclure la valeur MEDIA_URL (dûment codée dans settings.py) comme préfixe de L'URL de la vignette. Le suivant fonctionne très bien:
<div id="thumbnail"><img src="{{ MEDIA_URL }}{{ current_project.thumbnail }}" alt="thumbnail" width="400" height="300" border="0" /></div>
en utilisant DRF, j'ai défini une descendante hyperliée de Modelserializer appelée ProjectSerializer:
class ProjectSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Project
fields = ( 'id' ,'url', 'name', 'thumbnail')
Et j'ai défini un très simple modelviewset descendant:
class ProjectViewSet(viewsets.ModelViewSet):
queryset = Project.objects.all()
serializer_class = ProjectSerializer
un échantillon du JSON résultant ressemble à ceci:
{
"id": 1,
"url": "http://localhost:8000/api/v1/projects/1/",
"name": "Institutional",
"thumbnail": "media/institutional_thumb_1.jpg"
}
Je n'ai pas encore été capable de trouver comment fournir un champ miniature qui inclut l'url complète de l'image dans la représentation JSON de mon projet.
je pense que j'aurais besoin de créer un champ personnalisé dans le ProjectSerializer, mais n'ont pas été réussies.
7 réponses
Exemple (non testé):
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 requête doit être disponible pour le serialiseur, de sorte qu'il peut construire L'URL absolue complète pour vous. Une façon est de transmettre explicitement dans lorsque le sérialiseur est créé, comme ceci:
serializer = MySerializer(account, context={'request': request})
Merci, shavenwarthog. Votre exemple et votre référence documentaire ont énormément aidé. Mon application est un peu différent, mais très proche de ce que vous avez posté:
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')
Pour obtenir l'url d'un fichier qui utilise FileField, vous pouvez simplement appeler l'url de l'attribut de la FieldFile (c'est le fichier exemple pas le terrain), d'utiliser la classe de Stockage pour déterminer l'url de ce fichier. C'est très simple si vous utilisez un stockage externe comme Amazon S3 ou si votre stockage change.
Le get_thumbnail_url serait comme ça.
def get_thumbnail_url(self, obj):
return obj.thumbnail.url
Vous pouvez également l'utiliser dans le modèle de cette façon:
{{ current_project.thumbnail.url }}
j'ai trouvé ennuyeux d'écrire le même code pour un champ de méthode sérialisé.
Si vous avez positionné correctement le MEDIA_ROOT
pour votre S3 seau URL, vous pouvez ajouter un champ à la sérialiseur de la forme:
class ProjectSerializer(serializers.ModelSerializer):
logo_url = serializers.URLField(read_only=True, source='logo.url')
class Meta:
model = Project
le logo est un champ D'image dans le modèle. il ne doit pas être nul pour éviter des erreurs comme ValueError: The 'img' attribute has no file associated with it.
je n'utilise .build_absolute_uri
dans un champ de méthode serializer pour retourner les URL absolues qui utilisent d'autres vues dans mon API. par exemple, dans mon projet il y a une URL /webviews/projects/<pk>
que shows, un titre et un bouton qui recueille certaines entrées de l'utilisateur (c'est-à-dire pas exactement ce que vous feriez avec des suffixes, car ce n'est pas une représentation simple de la ressource mais inclut une certaine logique à la place). le point de fin /projects/<pk>/
contient un champ "webview_url" qui est généré avec SerializerMethodField. c'est pas les médias.
il suffit de passer le contexte et passer l'objet request. si vous utilisez @api_view
serializer = CustomerSerializer(customer, context={"request": request})
Pour ViewSet utilisateur get_serializer_context méthode
class ProjectViewSet(viewsets.ModelViewSet):
queryset = Project.objects.all()
serializer_class = ProjectSerializer
def get_serializer_context(self):
return {'request': self.request}
Vérifiez que vous settings.py
paramètres des médias.
j'ai eu la même erreur et a constaté que:
MEDIA_URL = ' / media/' a fait le tour.
avant j'avais seulement:
MEDIA_URL = ' media/'
Pas besoin de remplacements ou des personnalisations. La FONDATION gère automatiquement. Jetez un oeil à to_representation
méthode 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
notez que cela ne fonctionnera pas si le contexte du sérialiseur n'est pas défini correctement. Si vous utilisez ViewSet
s, pas de soucis, tout se fait en silence, mais si vous êtes à l'instanciation de la sérialiseur manuellement, vous devez passer dans la demande dans le cadre.
context = {'request': request}
serializer = ExampleSerializer(instance, context=context)
return Response(serializer.data)
http://www.django-rest-framework.org/topics/3.0-announcement/#file-fields-as-urls