2017-06-27 2 views
1

Ich habe dieses Grundmodell Layout:Speicher ähnliche Bilder Django REST-Framework

class Listing(models.Model): 
    name = models.TextField() 

class ListingImage(models.Model): 
    listing = models.ForeignKey(Listing, related_name='images', on_delete=models.CASCADE) 
    image = models.ImageField(upload_to=listing_image_path) 

Im Versuch, einen Serializer zu schreiben, das mich einen Rest api Endpunkt für die Erstellung von Anzeigen mit Bildern hinzufügen kann.

Meine Idee wäre dies:

class ListingImageSerializer(serializers.ModelSerializer): 
    class Meta: 
     model = ListingImage 
     fields = ('image',) 

class ListingSerializer(serializers.ModelSerializer): 
    images = ListingImageSerializer(many=True) 

class Meta: 
    model = Listing 
    fields = ('name', 'images') 

def create(self, validated_data): 
    images_data = validated_data.pop('images') 
    listing = Listing.objects.create(**validated_data) 
    for image_data in images_data: 
     ListingImage.objects.create(listing=listing, **image_data) 

    return listing 

Meine Probleme sind:

  1. Ich bin nicht sicher, wie und ob ich eine Liste von Bildern in einem verschachtelten Wörterbuch mit einem mehrteiliger senden POST-Anfrage

  2. Wenn ich nur eine Bilderliste posten und versuche, sie aus einer Liste in eine Liste von Wörterbüchern vor dem Aufruf des Serialisierer zu konvertieren, bekomme ich seltsame OS-Fehler beim Parsing des tatsächlichen Bildes.

    for key, item in request.data.items(): 
        if key.startswith('images'): 
         # images.append({'image': item}) 
         request.data[key] = {'image': item} 
    

Meine Anfrage Code sieht wie folgt aus:

import requests 
from requests_toolbelt.multipart.encoder import MultipartEncoder 

api_token = 'xxxx' 

images_data = MultipartEncoder(
    fields={ 
     'name': 'test', 
     'images[0]': (open('lilo.png', 'rb'), 'image/png'), 
     'images[1]': (open('panda.jpg', 'rb'), 'image/jpeg') 
    } 
) 


response = requests.post('http://127.0.0.1:8000/api/listings/', data=images_data, 
         headers={ 
          'Content-Type': images_data.content_type, 
          'Authorization': 'Token' + ' ' + api_token 
         }) 

ich eine sehr hacky Lösung gefunden haben, die ich in den Antworten veröffentlichen wird, aber es ist nicht wirklich robust und es muss ein besser sein Weg, dies zu tun.

Antwort

1

Also meine Lösung basiert auf diesem Beitrag und funktioniert ganz gut, aber scheint sehr unbändig und hacky.

Ich ändere das Bildfeld von einem Relationserializer, der ein Dictionary zu einem ListField benötigt. Dazu muss ich die Listenfeldmethode überschreiben, um beim Aufruf von "to_representation" tatsächlich eine Liste aus dem RelatedModelManager zu erstellen.

Dies verhält sich baiscally wie eine Liste am Eingang, aber wie ein Modellfeld beim Lesen.

class ModelListField(serializers.ListField): 
    def to_representation(self, data): 
     """ 
     List of object instances -> List of dicts of primitive datatypes. 
     """ 
     return [self.child.to_representation(item) if item is not None else None for item in data.all()] 


class ListingSerializer(serializers.ModelSerializer): 
    images = ModelListField(child=serializers.FileField(max_length=100000, allow_empty_file=False, use_url=False)) 

    class Meta: 
     model = Listing 
     fields = ('name', 'images') 

    def create(self, validated_data): 
     images_data = validated_data.pop('images') 
     listing = Listing.objects.create(**validated_data) 
     for image_data in images_data: 
      ListingImage.objects.create(listing=listing, image=image_data) 

     return listing 
+0

Ist dieser Teil Ihrer Frage oder beantworten Sie (sofort) Ihre eigene Frage? –

+0

Wie ich am Ende der Frage sagte: "Ich habe eine sehr hacky Lösung gefunden, die ich in den Antworten posten werde, aber es ist nicht wirklich robust und es muss einen besseren Weg geben, dies zu tun." Ich biete nur dies, weil es funktioniert und ich möchte pps Zeit sparen, wenn ich versuche zu helfen. – Julian

Verwandte Themen