2017-02-06 6 views
0

ich auf einem einfachen Projekt arbeite für Produkte von einer Website zu verkaufen, für die das Modell Definition lautet wie folgt:django-rest-framework: Wie man Join von Datenbankmodellen serialisiert?

class Product(models.Model): 
    """ 
     Model for Products 
    """ 
    price = models.FloatField() 
    description = models.TextField() 
    url = models.CharField(max_length=200) 

    def __str__(self): 
     return self.description 

class Order(models.Model): 
    """ 
    Model for Orders 
    """ 
    UNPAID = 0 
    PAID = 1 
    FAILED = 2 

    STATUS = (
     (UNPAID, 'UNPAID'), 
     (PAID, 'PAID'), 
     (FAILED, 'FAILED'), 
    ) 

    user = models.ForeignKey(User) 
    product = models.ForeignKey(Product) 
    orderdate = models.DateTimeField() 
    token = models.CharField(max_length=30) 
    paymentstatus = models.IntegerField(choices=STATUS) 

Entsprechend den Serializer definiert sind, wie folgend:

class ProductSerializer(serializers.ModelSerializer): 
    """ 
    Serialize Product list 
    """ 
    class Meta: 
     """ 
     Metadata for Product Serializationt to expose API 
     """ 
     model = Product 
     fields = ('id', 'price', 'description', 'url') 

class OrderSerializer(serializers.ModelSerializer): 
    """ 
    Serialize Order of Product 
    """ 
    class Meta: 
     """ 
     Order metadata 
     """ 
     model = Order 
     fields = ('id', 'user', 'orderdate', 'token', 'paymentstatus', 
        'product') 


class OrderDetailSerializer(serializers.ModelSerializer): 
    """ 
    Serialize Order Details 
    """ 
    product = ProductSerializer(read_only=True) 
    class Meta: 
     """ 
     Order metadata 
     """ 
     model = Order 
     fields = ('id', 'user', 'orderdate', 'paymentstatus', 'product') 

Im obigen Beispiel , ist es möglich, OrderSerializer und OrderDetailsSerializer zu einem einzigen Serialisierer zu kombinieren?

Ich verwende die OrderSerializer, wenn der Benutzer eine neue Order legt, d. H. Schreibt in die Datenbank und OrderDetailSerializer, um die Details einer Bestellung aus der Datenbank abzurufen.

+0

hilft ich glaube, Sie 'OrderDetailSerializer' für beide Fälle können, warum erstellen Sie eine andere Serializer' OrderSerializer '? – Enix

+0

Ist ein "Sub-Dictionary" in Ordnung? Wenn dies der Fall ist, können Sie Ihrem OrderSerializer 'detail = OrderDetailSerializer' hinzufügen und nur' detail' zu Ihren Feldern hinzufügen. –

+0

@Enix, weil in 'OrderDetailSerializer' die' read_only = True' oder 'querieset' benötigt wird, bin ich etwas verwirrt über ihre Verwendung und daher diesen Beitrag. Ich möchte auch nicht das 'token' zum Benutzer auf get Anfrage zeigen, daher verschiedene serialzier – bawejakunal

Antwort

0

Sie können mithilfe eines benutzerdefinierten Feldes mit einem einzelnen Serializer dies tun, und durch das Token WRITE_ONLY machen

class ProductSerializer(serializers.ModelSerializer): 
    """ 
    Serialize Product list 
    """ 
    class Meta: 
     """ 
     Metadata for Product Serializationt to expose API 
     """ 
     model = Product 
     fields = ('id', 'price', 'description', 'url') 

class ProductField(serializers.PrimaryKeyRelatedField): 

    def to_representation(self, value): 
     id = super(ProductField, self).to_representation(value) 
     try: 
      product = Product.objects.get(pk=id) 
      serializer = ProductSerializer(product) 
      return serializer.data 
     except Product.DoesNotExist: 
      return None 

    def get_choices(self, cutoff=None): 
     queryset = self.get_queryset() 
     if queryset is None: 
      return {} 

     return OrderedDict([(item.id, self.display_value(item)) for item in queryset]) 

class OrderSerializer(serializers.ModelSerializer): 
    """ 
    Serialize Order of Product 
    """ 
    product = ProductField(queryset=Product.objects.all()) 

    class Meta: 
     """ 
     Order metadata 
     """ 
     model = Order 
     fields = ('id', 'user', 'orderdate', 'token', 
        'paymentstatus', 'product') 
     extra_kwargs = {'token': {'write_only': True}} 

das benutzerdefinierte Feld können Sie die Modell-ID verwenden bei der Buchung, während die verschachtelte Serializer bekommen, wenn Du bekommst den Gegenstand. z.B.

POST:

{ 
    "product": 10, 
    ... 
} 

GET:

{ 
    "product": { 
     "url": "http://localhost:8000/..." 
     "price": "$2.50", 
     ... 
    } 
    ... 
} 

Hoffnung, die

+0

Beim Senden der GET-Anfrage bekomme ich AttributeError: Got AttributError beim Versuch, einen Wert für Feld' Preis' auf Serializer 'ProductSerializer' zu erhalten. Das Serialisierungsfeld wurde möglicherweise falsch benannt und entspricht keinem Attribut oder Schlüssel in der Instanz "PKOnlyObject". Ich denke, das liegt daran, 'to_representation' ist für die schreibgeschützte Darstellung gedacht? – bawejakunal

+0

Das ist komisch. Ich habe diesen Trick oft benutzt. Ich habe keine Zeit, um Ihren tatsächlichen Code zu testen, also hoffentlich führt Sie das auf den richtigen Weg – dkarchmer

+0

Gerade diese Lösung für mein eigenes Projekt kam. Hoffe, du kannst es immer noch benutzen – dkarchmer

Verwandte Themen