私は2つのモデルTask
とTaskImage
を持っています。これはTask
オブジェクトに属する画像のコレクションです。
Task
オブジェクトに複数の画像を追加できるようにしたいのですが、2つのモデルを使用しないとできません。現在、画像を追加しても、画像をアップロードして新しいオブジェクトを保存することはできません。
settings.py
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'
serializers.py
class TaskImageSerializer(serializers.ModelSerializer):
class Meta:
model = TaskImage
fields = ('image',)
class TaskSerializer(serializers.HyperlinkedModelSerializer):
user = serializers.ReadOnlyField(source='user.username')
images = TaskImageSerializer(source='image_set', many=True, read_only=True)
class Meta:
model = Task
fields = '__all__'
def create(self, validated_data):
images_data = validated_data.pop('images')
task = Task.objects.create(**validated_data)
for image_data in images_data:
TaskImage.objects.create(task=task, **image_data)
return task
models.py
class Task(models.Model):
title = models.CharField(max_length=100, blank=False)
user = models.ForeignKey(User)
def save(self, *args, **kwargs):
super(Task, self).save(*args, **kwargs)
class TaskImage(models.Model):
task = models.ForeignKey(Task, on_delete=models.CASCADE)
image = models.FileField(blank=True)
ただし、投稿リクエストを行うと、
次のトレースバックが表示されます。
内部41のファイル「/Applications/Anaconda/anaconda/envs/godo/lib/python3.6/site-packages/Django/core/handlers/exception.py」。response= get_response(request)
_get_response 187内のファイル「/Applications/Anaconda/anaconda/envs/godo/lib/python3.6/site-packages/Django/core/handlers/base.py」。response= self.process_exception_by_middleware(e、request)
_get_response 185のファイル「/Applications/Anaconda/anaconda/envs/godo/lib/python3.6/site-packages/Django/core/handlers/base.py」。response= wrapped_callback(request、* callback_args、** callback_kwargs)
ファイル "/Applications/Anaconda/anaconda/envs/godo/lib/python3.6/site-packages/Django/views/decorators/csrf.py" in wrapped_view 58. return view_func(* args、** kwargs)
ビュー95のファイル "/Applications/Anaconda/anaconda/envs/godo/lib/python3.6/site-packages/rest_framework/viewsets.py"。returnself.dispatch(request、* args、** kwargs)
ディスパッチ494のファイル「/Applications/Anaconda/anaconda/envs/godo/lib/python3.6/site-packages/rest_framework/views.py」。response= self.handle_exception(exc)
Handle_exception 454のファイル「/Applications/Anaconda/anaconda/envs/godo/lib/python3.6/site-packages/rest_framework/views.py」。self.raise_uncaught_exception(exc)
ディスパッチ491のファイル "/Applications/Anaconda/anaconda/envs/godo/lib/python3.6/site-packages/rest_framework/views.py"。response= handler(request、* args、** kwargs)
Create 21のファイル「/Applications/Anaconda/anaconda/envs/godo/lib/python3.6/site-packages/rest_framework/mixins.py」。self.perform_create(serializer)
Perform_create 152のファイル「/Users/gr/Desktop/PycharmProjects/godo/api/views.py」。serializer.save(user=self.request.user)
保存214内のファイル「/Applications/Anaconda/anaconda/envs/godo/lib/python3.6/site-packages/rest_framework/serializers.py」。self.instance= self.create(validated_data)
作成67のファイル「/Users/gr/Desktop/PycharmProjects/godo/api/serializers.py」。images_data= validated_data.pop( 'images')
例外タイプ:/ api/tasks /のKeyError例外値: 'images'
問題の説明
このステートメントimages_data = validated_data.pop('images')
が原因で、例外の原因はKeyError
でした。これは、検証されたデータにキーimages
がないためです。つまり、画像入力は郵便配達員からの画像入力を検証しません。
DjangoポストリクエストストアInMemmoryUpload
in _request.FILES
_なので、ファイルのフェッチに使用します。また、一度に複数の画像をアップロードする必要があります。したがって、(postmanで)画像をアップロードするときは、異なるimage_nameを使用する必要があります。serializer
を次のように変更します。
_class TaskSerializer(serializers.HyperlinkedModelSerializer):
user = serializers.ReadOnlyField(source='user.username')
images = TaskImageSerializer(source='taskimage_set', many=True, read_only=True)
class Meta:
model = Task
fields = ('id', 'title', 'user', 'images')
def create(self, validated_data):
images_data = self.context.get('view').request.FILES
task = Task.objects.create(title=validated_data.get('title', 'no-title'),
user_id=1)
for image_data in images_data.values():
TaskImage.objects.create(task=task, image=image_data)
return task
_
あなたの見方はわかりませんが、ModelViewSet
を使用します
好ましいビュークラス
_class Upload(ModelViewSet):
serializer_class = TaskSerializer
queryset = Task.objects.all()
_
_{
"id": 12,
"title": "This Is Task Title",
"user": "admin",
"images": [
{
"image": "http://127.0.0.1:8000/media/Screenshot_from_2017-12-20_07-18-43_tNIbUXV.png"
},
{
"image": "http://127.0.0.1:8000/media/game-of-thrones-season-valar-morghulis-wallpaper-1366x768_3bkMk78.jpg"
},
{
"image": "http://127.0.0.1:8000/media/IMG_212433_lZ2Mijj.jpg"
}
]
}
_
[〜#〜]更新[〜#〜]
これがあなたのコメントに対する答えです。 Django _reverse foreignKey
_は__set
_を使用してキャプチャしています。これを参照してください 公式ドキュメント 。ここで、Task
およびTaskImage
はOneToMany
関係にあるため、1つのTask
インスタンスがある場合、この_reverse look-up
_機能により、関連するすべてのTaskImage
インスタンスを取得できます
ここに例があります
_task_instance = Task.objects.get(id=1)
task_img_set_all = task_instance.taskimage_set.all()
_
ここでこの_task_img_set_all
_はTaskImage.objects.filter(task_id=1)
と等しくなります
あなたが持っている read_only
ネストされたフィールドTaskImageSerializer
でtrueに設定。したがって、validated_dataはありません。