2015-03-13 7 views
7

Więc mam następującą strukturę:Django Framework zagnieżdżonych zasobów REST klucz "id" unaccessible

ClientFile należy do właściciela (class name = kontaktowego). Próbuję utworzyć plik klienta przy użyciu interfejsu API. Żądanie zawiera następujące dane:

{ 
    name: "Hello!" 
    owner: { 
    id: 1, 
    first_name: "Charlie", 
    last_name: "Watson" 
    } 
} 

Stworzyłem serializer zgodnie z moją strukturą. Mając nadzieję, że to wywołanie API utworzyłoby plik klienta o nazwie "Hello!" i Contact id 1 jako właściciel:

class ContactSerializer(serializers.ModelSerializer): 
    class Meta: 
    model = Contact 
    fields = (
     'id', 
     'first_name', 
     'last_name', 
    ) 

class ClientfileSerializer(serializers.ModelSerializer): 

    owner = ContactSerializer(read_only=False) 

    class Meta(): 
    model = Clientfile 
    fields = (
     'id', 
     'name', 
     'owner', 
    ) 

    def create(self, validated_data): 

    owner = Contact.objects.get(pk=validated_data['owner']['id']) 

Dostaję się do metody create. Jednak jedyne pole, które potrzebuję, to (['owner']['id']). Jeśli wykonam print ['owner']['first_name'], to zwróci "Charlie". Ale identyfikator z pewnych powodów nie jest dostępny ...

Jakiekolwiek powody, dla których może to mieć miejsce? Czy coś mi brakuje? (Jestem nowy w Django)


ROZWIĄZANIE: Po prostu okazało się, że powód nie wykazał ID w pierwszej kolejności dlatego musiałem zadeklarować ją w dziedzinach tak: Mam nadzieję, że to pomaga.

class ContactSerializer(serializers.ModelSerializer): 

    id = serializers.IntegerField() # ← Here 

    class Meta: 
    model = Contact 
    fields = (
     'id', 
     'first_name', 
     'last_name', 
    ) 

Odpowiedz

1

Dobrze więc znalazłem inne podejście, które działa. Dodałem szeregowiec IntegerField dla relacji właściciela. Musiałem również ustawić relację właściciela na read_only = True.

To json przesyłam poprzez POST:

{ 
    name: "Hello!" 
    owner_id: 1 
} 

To mój serializer:

class ClientfileSerializer(serializers.ModelSerializer): 

    owner_id = serializers.IntegerField() 
    owner = ContactSerializer(read_only=True) 

    class Meta(): 
    model = Clientfile 
    fields = (
     'id', 
     'owner_id', 
     'owner', 
    ) 

Wydaje mniej fajne niż pierwszy sposób, ale spełnia swoje zadanie. Plus Nie chcę tworzyć nowego właściciela, ale wystarczy wybrać taki, który jest już w bazie danych. Więc może bardziej semantyczne jest posiadanie tylko identyfikatora, a nie pełnego zestawu informacji publikowanych przez Json.

7

W Django Framework AutoField REST pola (te, które są generowane automatycznie) są domyślnie tylko do odczytu. Od the docs:

read_only

ustawić to True aby upewnić się, że pole jest używany, gdy szeregowania reprezentacji, ale nie jest używany podczas tworzenia lub aktualizowania wystąpienie podczas deserializacji.

Domyślnie False

Można to zobaczyć przez inspecting your serializer drukując reprezentację w swojej powłoce:

serializer = ClientfileSerializer() 
print repr(serializer) 

Można to zmienić poprzez ustawienie read_only=False przeciwko polu id w extra_kwargs:

class ContactSerializer(serializers.ModelSerializer): 
    class Meta: 
    model = Contact 
    fields = (
     'id', 
     'first_name', 
     'last_name', 
    ) 
    extra_kwargs = {'id': {'read_only': False}} 

class ClientfileSerializer(serializers.ModelSerializer): 

    owner = ContactSerializer(read_only=False) 

    class Meta(): 
    model = Clientfile 
    fields = (
     'id', 
     'name', 
     'owner', 
    ) 
    extra_kwargs = {'id': {'read_only': False}} 
+0

Próbowałem. Naprawia problem, ale tworzy kolejny: Teraz nie mogę utworzyć kontaktu. Zgłasza błąd informujący, że pole identyfikacyjne jest wymagane ... – MonsieurNinja

+0

Czy próbowałeś zastosować pole tylko do odczytu w polu identyfikatora również dla narzędzia clientfileserializer? – br3w5

+0

Mam ten sam problem co @MonsieurNinja, to powoduje, że id musi być ustawiony ręcznie. – Sem

2

Można spróbować czegoś takiego:

class YourModelSerializer(serializers.ModelSerializer): 

    class Meta: 
     model = YourModel 
     fields = ('id', 'field1', 'field2') 

    def to_internal_value(self, data): 
     """ 
     Dict of native values <- Dict of primitive datatypes. 
     Add instance key to values if `id` present in primitive dict 
     :param data: 
     """ 
     obj = super(YourModelSerializer, self).to_internal_value(data) 
     instance_id = data.get('id', None) 
     if instance_id: 
      obj['instance'] = YourModel.objects.get(id=instance_id) 
     return obj 

Następnie w serializer potwierdzonych danych, które powinny mieć klucz „instancji”, jeśli request.data ma klucz „id”.

Ponadto można dodać tylko "id" zamiast pełnej instancji/obiektu.