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
Odpowiedzi:
Będziesz potrzebował pliku
TagSerializer
, któregoclass Meta
mamodel = Tag
. PoTagSerializer
utworzeniu zmodyfikujPostSerializer
withmany=True
dlaManyToManyField
relacji:class PostSerializer(serializers.ModelSerializer): tag = TagSerializer(read_only=True, many=True) class Meta: model = Post fields = ('tag', 'text',)
Odpowiedź dotyczy DRF 3
źródło
read_only=True
Część jest wyjaśnione tutaj: django-rest-framework.org/api-guide/relations/...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')
źródło
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
źródło
To działa dla mnie.
tag = TagSerializer(source="tag", read_only=True, many=True)
źródło
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',)
źródło
get_topics_list
możesz uprościć się doreturn list(instance.topics.values_list('desc', flat=True))
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 ()
źródło
Domyślnie
ModelSerializer
do relacji są używane klucze podstawowe. Możesz jednak łatwo wygenerować zagnieżdżone reprezentacje za pomocąMeta
depth
atrybutu:class PostSerializer(serializers.ModelSerializer): class Meta: model = Post fields = ("text", "tag") depth = 1
Jak wspomniano w dokumentacji :
źródło