Framework Django REST serializujący wiele pól

84

Jak serializować pole wiele-do-wielu na listę czegoś i zwrócić je przez resztę? W poniższym przykładzie próbuję zwrócić post wraz z listą powiązanych z nim tagów.

models.py

class post(models.Model):
    tag = models.ManyToManyField(Tag)
    text = models.CharField(max_length=100)

serializers.py

class PostSerializer(serializers.ModelSerializer):
    class Meta:
        model = Post
        fields = ("text", "tag"??)

views.py

class PostViewSet(viewsets.ReadOnlyModelViewSet):
    queryset = Post.objects.all()
    serializer_class = PostSerializer
kengcc
źródło
Korzystając z pomocy @Brian udaje mi się wylistować pozycje w takiej postaci: "tagi": [{"nazwa": "tag1"}]. Chciałbym uprościć to do listy, czy to możliwe: "tagi": ["tag1", "tag2", ...]
kengcc
2
użyj `tags = serializers.SlugRelatedField (many = True, read_only = True, slug_field = 'title', // tag's fireld, który chcesz pokazać allow_null = True)` w PostSerializers
M. Dhaouadi

Odpowiedzi:

105

Będziesz potrzebował pliku TagSerializer, którego class Metama model = Tag. Po TagSerializerutworzeniu zmodyfikuj PostSerializerwith many=Truedla ManyToManyFieldrelacji:

class PostSerializer(serializers.ModelSerializer):
    tag = TagSerializer(read_only=True, many=True)

    class Meta:
        model = Post
        fields = ('tag', 'text',)

Odpowiedź dotyczy DRF 3

Brian
źródło
to działa!!! : D Masz pomysł, jak zamienić ten serializator w listę oddzieloną przecinkami? class TagSerializer (serializers.ModelSerializer): class Meta: model = Tag fields = ('name')
kengcc
1
W tej chwili otrzymuję: "tagi": [{"name": "tag1"}] Chciałbym to uprościć do: "tags": ["tag1", "tag2", ...]
kengcc
tags = serializers.ListField (source = 'tag'). W ten sposób otrzymasz listę reprezentacji str każdego obiektu tagu
Sachin Gupta
2
A co jeśli chcesz mieć możliwość aktualizacji tagu przez post? (np. not read_only) Otrzymuję dziwne zachowanie, gdy zabieram read_only i próbuję PATCH zaktualizować pole tagu (
pojawia
1
read_only=TrueCzęść jest wyjaśnione tutaj: django-rest-framework.org/api-guide/relations/...
Pavel Vergeev
25

Oto, co zrobiłem, załóżmy, że książka może mieć więcej niż jednego autora, a autor może mieć więcej niż jedną książkę: Na modelu:

class Author(models.Model):
    name = models.CharField(max_length=100, default="")
    last_name = models.IntegerField(default=0)

class Book(models.Model):
    authors = models.ManyToManyField(Author, related_name="book_list", blank=True)
    name = models.CharField(max_length=100, default="")
    published = models.BooleanField(default=True)

Na serializatorach:

class BookSerializer(serializers.ModelSerializer):
    authors = serializers.PrimaryKeyRelatedField(queryset=Author.objects.all(), many=True)

    class Meta:
        model = Book
        fields = ('id', 'name', 'published', 'authors')


class AuthorSerializer(serializers.ModelSerializer):
    book_list = BookSerializer(many=True, read_only=True)

    class Meta:
        model = Author
        fields = ('id', 'name', 'last_name', 'book_list')
Jesus Almaral - Hackaprende
źródło
Masz jakiś pomysł, jak możemy tworzyć autorów po utworzeniu jednostki książki?
Kishan Mehta
2
Tak, trzeba to zrobić na zajęciach Views,
zadaj
8

Dodanie do „tagów” ​​odpowiedzi @ Briana: [{"name": "tag1"}] można uprościć do "tagów": ["tag1", "tag2", ...] w ten sposób:

class PostSerializer(serializers.ModelSerializer):
    tag = TagSerializer(read_only=True, many=True)

    class Meta:
        ...

class TagSerializer(serializers.RelatedField):

     def to_representation(self, value):
         return value.name

     class Meta:
        model = Tag

Więcej informacji tutaj: https://www.django-rest-framework.org/api-guide/relations/#custom-relational-fields

candyfoxxx
źródło
4

To działa dla mnie.

tag = TagSerializer(source="tag", read_only=True, many=True)
Windsooon
źródło
4

Django 2.0

Dla wielu do wielu dziedzin, jeśli chcesz mieć konkretne:

class QuestionSerializer(serializers.ModelSerializer):

    topics_list = serializers.SerializerMethodField()

    def get_topics_list(self, instance):
        names = []
        a = instance.topics.get_queryset()
        for i in a:
            names.append(i.desc)
        return names
    class Meta:
        model = Question
        fields = ('topics_list',)
user5299374
źródło
Bo get_topics_listmożesz uprościć się doreturn list(instance.topics.values_list('desc', flat=True))
bdoubleu
2

W serializatorze w metodzie init możesz przekazać zestaw zapytań do pola i rest_framework walidować identyfikatory w tym zestawie zapytań

1) najpierw rozszerz serializator z serializers.ModelSerializer

class YourSerializer(serializers.ModelSerializer):

2) dołącz pole do klasy meta

class YourSerializer(serializers.ModelSerializer):
  class Meta:
        fields = (..., 'your_field',)

3) w metodzie init:

def __init__(self, *args, **kwargs):
    super(YourSerializer, self).__init__(*args, **kwargs)
    self.fields['your_field].queryset = <the queryset of your field>

Możesz ograniczyć zestaw zapytań dla tego pola w dowolnym argumencie za pomocą filtru lub wykluczania, tak jak zwykle. W przypadku, gdy chcesz dołączyć wszystko, po prostu użyj .objects.all ()

yiyo
źródło
1

Domyślnie ModelSerializerdo relacji są używane klucze podstawowe. Możesz jednak łatwo wygenerować zagnieżdżone reprezentacje za pomocą Meta depthatrybutu:

class PostSerializer(serializers.ModelSerializer):
    class Meta:
        model = Post
        fields = ("text", "tag")
        depth = 1 

Jak wspomniano w dokumentacji :

depthOpcji powinna być ustawiona na wartość liczby całkowitej, która wskazuje głębokość związków, które powinny być wykonywany przed powrotu do płaskiej reprezentacji.

mohamed ali Mimouni
źródło