Структура відпочинку Django, яка серіалізує багато для багатьох


84

Як мені серіалізувати поле багато-до-багатьох у список чогось і повернути їх через систему відпочинку? У наведеному нижче прикладі я намагаюся повернути публікацію разом зі списком тегів, пов’язаних із нею.

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

За допомогою довідки @Brian мені вдається перерахувати елементи у такій формі: "теги": [{"name": "tag1"}]. Я хотів би спростити його для переліку, чи можливо: "теги": ["тег1", "тег2", ...]
kengcc

2
використовуйте `теги = serializers.SlugRelatedField (багато = True, read_only = True, slug_field = 'назва', // fireld ви тега хочете , щоб показати allow_null = True)` в PostSerializers
М. Dhaouadi

Відповіді:


105

Вам знадобиться TagSerializer, чий class Metaмає model = Tag. Після того, як TagSerializerстворений, модифікувати PostSerializerз many=Trueдля ManyToManyFieldзв'язку:

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

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

Відповідь на DRF 3


це працює!!! : D Будь-яка ідея, як перетворити цей серіалізатор у список, відокремлений комами? клас TagSerializer (serializers.ModelSerializer): клас Meta: model = Tag fields = ('name')
kengcc

1
Зараз я отримую: "tags": [{"name": "tag1"}] Я хотів би спростити його до: "tags": ["tag1", "tag2", ...]
kengcc

теги = серіалізатори.ListField (джерело = 'тег'). Це дасть вам список представлення str кожного об’єкта тегу
Sachin Gupta

2
Що робити, якщо ви хочете мати можливість оновити тег через повідомлення? (наприклад, не read_only) Я отримую дивну поведінку, коли я забираю read_only і намагаюся ВСТАНОВИТИ оновлення в поле тегу (я отримую повідомлення про тег, який уже існує)
getup8

1
read_only=TrueЧастина пояснюється тут: django-rest-framework.org/api-guide/relations / ...
Павло Загін Вергеев

25

Це те, що я зробив, припустимо, книга може мати більше одного автора, а автор може мати більше однієї книги: На моделі:

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)

На серіалізаторах:

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')

Будь-яка ідея, як ми можемо створювати авторів для створення сутності Книги ??
Кішан Мехта

2
Так, це потрібно зробити в класі Views, будь ласка, опублікуйте ще одне запитання, якщо ви хочете отримати більш детальну відповідь
Jesus Almaral - Hackaprende

8

Додавання до відповіді @ Брайана "тегів": [{"name": "tag1"}] можна спростити до "tags": ["tag1", "tag2", ...] таким чином:

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

Більше інформації тут: https://www.django-rest-framework.org/api-guide/relations/#custom-relational-fields


4

Це працює для мене.

tag = TagSerializer(source="tag", read_only=True, many=True)

4

Django 2.0

Для багатьох до багатьох, якщо ви хочете отримати конкретне:

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',)

Для get_topics_listвас можна спроститиreturn list(instance.topics.values_list('desc', flat=True))
bdoubleu

2

У методі серіалізатора on init ви можете передати набір запитів в поле і rest_framework перевірити ідентифікатори цього набору запитів

1) спочатку розширте свій серіалізатор із серіалізаторів.ModelSerializer

class YourSerializer(serializers.ModelSerializer):

2) включити поле в мета-класі

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

3) у методі init:

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

Ви можете обмежити набір запитів для цього поля під будь-яким аргументом, використовуючи фільтр, або виключити, як зазвичай. Якщо ви хочете включити всі, просто використовуйте .objects.all ()


1

За замовчуванням ModelSerializerдля взаємозв’язків використовуються первинні ключі. Однак ви можете легко генерувати вкладені уявлення, використовуючи Meta depthатрибут:

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

Як зазначено в документації :

Для depthпараметра слід встановити ціле значення, яке вказує на глибину взаємозв’язків, які слід пройти перед поверненням до плоского подання.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.