次のモデルを含む単純なDjango=アプリを定義しました。
class Project(models.Model):
name = models.CharField(max_length=200)
thumbnail = models.FileField(upload_to='media', null=True)
(技術的にははい、それはImageFieldかもしれません。)
テンプレートでは、MEDIA_URL値(settings.pyで適切にコード化されている)をサムネイルURLのプレフィックスとして含めるのは簡単です。以下が正常に機能します。
<div id="thumbnail"><img src="{{ MEDIA_URL }}{{ current_project.thumbnail }}" alt="thumbnail" width="400" height="300" border="0" /></div>
DRFを使用して、ProjectSerializerというHyperlinkedModelSerializerの子孫を定義しました。
class ProjectSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Project
fields = ( 'id' ,'url', 'name', 'thumbnail')
そして、私は非常に簡単なModelViewSetの子孫を定義しました:
class ProjectViewSet(viewsets.ModelViewSet):
queryset = Project.objects.all()
serializer_class = ProjectSerializer
結果のJSONのサンプルは次のようになります。
{
"id": 1,
"url": "http://localhost:8000/api/v1/projects/1/",
"name": "Institutional",
"thumbnail": "media/institutional_thumb_1.jpg"
}
プロジェクトのJSON表現の画像への完全なURLを含むサムネイルフィールドを提供する方法をまだ理解できていません。
ProjectSerializerでカスタムフィールドを作成する必要があると思いますが、成功していません。
例(未テスト):
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)
シリアライザーがリクエストを利用できるようにして、完全な絶対URLを作成できるようにします。 1つの方法は、次のように、シリアライザーの作成時に明示的に渡すことです。
serializer = MySerializer(account, context={'request': request})
ありがとう、shavenwarthog。あなたの例とドキュメントのリファレンスは非常に役立ちました。私の実装は少し異なりますが、あなたが投稿したものに非常に近いです:
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')
FileFieldを使用するファイルのURLを取得するには、FieldFile(これはフィールドではなくファイルインスタンスです)のurl属性を呼び出すだけで、Storageクラスを使用してこのファイルのURLを決定できます。 Amazon S3のような外部ストレージを使用している場合、またはストレージが変更された場合、非常に簡単です。
Get_thumbnail_urlは次のようになります。
def get_thumbnail_url(self, obj):
return obj.thumbnail.url
テンプレートで次のように使用することもできます。
{{ current_project.thumbnail.url }}
シリアル化されたメソッドフィールドに同じコードを書くのは面倒です。 _MEDIA_ROOT
_をS3バケットURLに正しく設定した場合、次のようなフィールドをシリアライザーに追加できます。
_class ProjectSerializer(serializers.ModelSerializer):
logo_url = serializers.URLField(read_only=True, source='logo.url')
class Meta:
model = Project
_
ロゴはモデル内のImageFieldです。 _ValueError: The 'img' attribute has no file associated with it.
_のようなエラーを回避するために、null可能であってはなりません
APIの他のビューを使用する絶対URLを返すために、シリアライザーメソッドフィールドで_.build_absolute_uri
_のみを使用します。たとえば、私のプロジェクトでは、URL _/webviews/projects/<pk>
_が表示され、タイトルとユーザー入力を収集するボタンがあります(つまり、リソースの単なる表現ではなく、代わりにいくつかのロジック)。エンドポイント_/projects/<pk>/
_には、「webview_url」フィールドが含まれ、SerializerMethodFieldで生成されます。メディアではありません。
オーバーライドやカスタマイズの必要はありません。 DRFが自動的に処理します。を見てみましょう to_representation
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
シリアライザーのコンテキストが適切に設定されていない場合は機能しないことに注意してください。 ViewSet
sを使用している場合、心配はありませんが、すべてが静かに行われますが、シリアライザーを手動でインスタンス化する場合は、コンテキストでリクエストを渡す必要があります。
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
コンテキストを渡し、リクエストオブジェクトを渡すだけです。 @api_viewを使用している場合
serializer = CustomerSerializer(customer, context={"request": request})
ViewSetユーザーのget_serializer_contextメソッドの場合
class ProjectViewSet(viewsets.ModelViewSet):
queryset = Project.objects.all()
serializer_class = ProjectSerializer
def get_serializer_context(self):
return {'request': self.request}
Settings.pyを確認してください
メディア設定。
私は同じエラーがあり、それを見つけました:
MEDIA_URL = '/ media /'はトリックを行いました。
私が持っていた前に:
MEDIA_URL = 'media /'
私の場合、to_representationメソッドのオーバーライドは正しく機能します。
# models.py
class DailyLove(models.Model):
content = models.CharField(max_length=1000)
pic = models.FileField(upload_to='upload/api/media/DailyLove/')
date = models.DateTimeField(auto_created=True)
def __str__(self):
return str(self.date)
# serializers.py
class DailyLoveSerializer(serializers.HyperlinkedModelSerializer):
def to_representation(self, instance):
representation = super(DailyLoveSerializer, self).to_representation(instance)
representation['pic_url'] = self.context['request'].build_absolute_uri('/' + instance.pic.url)
return representation
class Meta:
model = DailyLove
fields = '__all__'
# views.py
class DailyLoveViewSet(viewsets.ModelViewSet):
queryset = DailyLove.objects.all().order_by('-date')
serializer_class = DailyLoveSerializer
# result
HTTP 200 OK
Allow: GET, POST, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept
[
{
"url": "http://localhost:8088/daily/3/",
"date": "2019-05-04T12:33:00+08:00",
"content": "123",
"pic": "http://localhost:8088/daily/upload/api/media/DailyLove/nitish-meena-37745-unsplash.jpg",
"pic_url": "http://localhost:8088/upload/api/media/DailyLove/nitish-meena-37745-unsplash.jpg"
}
]