Ich habe 2 Modelle Task
und TaskImage
, bei denen es sich um eine Sammlung von Bildern handelt, die zum Objekt Task
gehören.
Ich möchte, dass ich meinem Objekt Task
mehrere Bilder hinzufügen kann, aber ich kann dies nur mit 2 Modellen tun. Derzeit kann ich beim Hinzufügen von Bildern keine Bilder hochladen und keine neuen Objekte speichern.
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)
Wenn ich jedoch eine Post-Anfrage mache:
Ich bekomme folgenden Traceback:
Datei "/Applications/Anaconda/anaconda/envs/godo/lib/python3.6/site-packages/Django/core/handlers/exception.py" in Inner 41. response = get_response (request)
Datei "/Applications/Anaconda/anaconda/envs/godo/lib/python3.6/site-packages/Django/core/handlers/base.py" in _get_response 187. response = self.process_exception_by_middleware (e, request)
Datei "/Applications/Anaconda/anaconda/envs/godo/lib/python3.6/site-packages/Django/core/handlers/base.py" in _get_response 185. response = wrapped_callback (request, * callback_args, ** callback_kwargs)
Datei "/Applications/Anaconda/anaconda/envs/godo/lib/python3.6/site-packages/Django/views/decorators/csrf.py" in wrapped_view 58. return view_func (* args, ** kwargs)
Datei "/Applications/Anaconda/anaconda/envs/godo/lib/python3.6/site-packages/rest_framework/viewsets.py" in Ansicht 95. self.dispatch zurückgeben (request, * args, ** kwargs)
Datei "/Applications/Anaconda/anaconda/envs/godo/lib/python3.6/site-packages/rest_framework/views.py" im Versand 494. response = self.handle_exception (exc)
Datei "/Applications/Anaconda/anaconda/envs/godo/lib/python3.6/site-packages/rest_framework/views.py" in handle_exception 454. self.raise_uncaught_exception (exc)
Datei "/Applications/Anaconda/anaconda/envs/godo/lib/python3.6/site-packages/rest_framework/views.py" im Versand 491. response = handler (request, * args, ** kwargs)
Datei "/Applications/Anaconda/anaconda/envs/godo/lib/python3.6/site-packages/rest_framework/mixins.py" in create 21. self.perform_create (serializer)
Datei "/Users/gr/Desktop/PycharmProjects/godo/api/views.py" in perform_create 152. serializer.save (user = self.request.user)
Datei "/Applications/Anaconda/anaconda/envs/godo/lib/python3.6/site-packages/rest_framework/serializers.py" in save 214. self.instance = self.create (validated_data)
Datei "/Users/gr/Desktop/PycharmProjects/godo/api/serializers.py" in create 67. images_data = validated_data.pop ('images')
Ausnahmetyp: KeyError at/api/tasks/Ausnahmewert: 'images'
Beschreibung für das Problem
Der Ursprung der Ausnahme war eine KeyError
, aufgrund dieser Aussage images_data = validated_data.pop('images')
. Dies liegt daran, dass die validierten Daten keinen Schlüssel images
haben. Dies bedeutet, dass die Bildeingabe die Bildeingaben vom Postboten nicht validiert.
Django-Post-Request-Speicher InMemmoryUpload
in request.FILES
, daher verwenden wir ihn zum Abrufen von Dateien. Außerdem möchten Sie mehrere Bilder gleichzeitig hochladen. Also, Sie müssen beim Hochladen Ihres Bildes (im Postboten) unterschiedliche Bildnamen verwenden .
Ändere deine serializer
so, dass sie dir gefällt,
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
Ich kenne Ihre Ansicht nicht, möchte aber ModelViewSet
verwenden
bevorzugte Ansichtsklasse
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"
}
]
}
UPDATE
Dies ist die Antwort auf Ihren Kommentar. In Django wird reverse foreignKey
mit _set
erfasst. siehe dieses offizielle Dokument . Hier stehen Task
und TaskImage
in einer OneToMany
-Beziehung. Wenn Sie also eine Task
-Instanz haben, können Sie alle zugehörigen TaskImage
-Instanzen mit dieser reverse look-up
-Funktion abrufen
hier ist das Beispiel
task_instance = Task.objects.get(id=1)
task_img_set_all = task_instance.taskimage_set.all()
Hier ist dieser task_img_set_all
gleich TaskImage.objects.filter(task_id=1)
Sie haben read_only
im verschachtelten Feld TaskImageSerializer
auf true gesetzt. Es werden dort also keine validierten_Daten vorhanden sein.