Как размещать и получать модель с внешним ключом

Я работаю над проектом NextJS + Django REST Framework, где у меня есть три модели: Document, MySource и QuestionBlock.

  1. Документ создается вместе с несколькими "блоками_вопросов", связанными с созданным документом. Они создаются вместе, и я уже реализовал это с помощью вложенных сериализаторов
  2. .
  3. После создания документа я хочу иметь возможность POST модели MySource, связанной с документом. Затем, когда я делаю GET запрос документа, все объекты mysource также должны быть отображены.
  4. .

POST запрос: обратите внимание, как я просто поместил id документа, с которым я хочу установить связь.

{
  "url": "urlasdf",
  "title": "tuitle",
  "publisher": "afdfas ",
  "desc": "qwefqwef",
  "summary": "asdfasdf",
  "document": "J9DY2pE"
}

GET запрос: Я хочу, чтобы запрос GET документа показывал что-то вроде следующего.

"id": "LwpQr6Y",
    "question_blocks": [
        {
            "id": 16,
            "document": "LwpQr6Y",
            "title": "question 4",
            "content": "qweqgadssdffasdf asdf"
        },
        ]
    "mysource": [
                {
            "id": 16,
            "url": "google.com",
            etc. . .
        },
        ],
    "title": "renamed title",
    "template": "commonapp",
    "updated": "2022-05-19T02:16:00+0000",
    "created": "2022-04-21T06:59:05+0000"

Странно то, что я не вижу никаких ошибок с кодом ниже, и сама функциональность работает правильно. Но когда я пытаюсь получить документ, в котором есть хотя бы один объект mysource, загрузка занимает пару минут, что заставляет меня думать, что в моем коде что-то не так, что, возможно, заставляет DRF повторяться.

models.py

class Document(models.Model):
    id = HashidAutoField(primary_key=True)
    title = models.CharField(max_length=100, default="Untitled")
    template = models.CharField(max_length=100, default="")
    updated = models.DateTimeField(auto_now=True)
    created = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.title

class QuestionBlock(models.Model):
    id = models.AutoField(primary_key=True)
    document = models.ForeignKey(
        Document,
        related_name="question_blocks",
        on_delete=models.CASCADE,
        null=True,
        blank=True,
    )
    title = models.CharField(max_length=500, default="")
    content = models.CharField(max_length=100000, default="", blank=True)

class MySource(models.Model):
    id = models.AutoField(primary_key=True)
    document = models.ForeignKey(
        Document,
        related_name="mysource",
        on_delete=models.CASCADE,
        null=True,
        blank=True,
    )
    url = models.CharField(max_length=500, default="")
    title = models.CharField(max_length=500, default="", blank=True)
    publisher = models.CharField(max_length=500, default="", blank=True)
    desc = models.CharField(max_length=500, default="", blank=True)
    summary = models.CharField(max_length=500, default="", blank=True)

serializers.py

class MySourceSerializer(serializers.ModelSerializer):
    class Meta:
        model = MySource
        fields = ("id", "url", "title", "publisher", "desc", "summary")

    def to_representation(self, instance):
        self.fields["document"] = DocumentSerializer(read_only=True)
        return super(MySourceSerializer, self).to_representation(instance)


class DocumentSerializer(serializers.ModelSerializer):
    id = HashidSerializerCharField(source_field="documents.Document.id", read_only=True)
    question_blocks = QuestionBlockSerializer(many=True)
    mysource = MySourceSerializer(many=True)

    class Meta:
        model = Document
        fields = "__all__"

    def create(self, validated_data):
        question_blocks = validated_data.pop("question_blocks")
        document = Document.objects.create(**validated_data)
        for qBlock in question_blocks:
            QuestionBlock.objects.create(document=document, **qBlock)
        document.save()
        return document

Я думаю, что подходящим способом может быть следующий:

###imports
from django.forms.models import model_to_dict


class DocumentListingField(serializers.RelatedField):
    def to_representation(self, instance):
        return model_to_dict(instance.document)

а затем в MySourceSerializer удалите функцию to_representation и обновите на что-то вроде этого:

class MySourceSerializer(serializers.ModelSerializer):
    document = DocumentListingField(many=False, read_only=True)

    class Meta:
        model = MySource
        fields = (
            "id", "url", "title", "publisher", "desc", "summary", "document")

*Редактирование: я добавил параметр read_only в True, потому что эти модели используют Hashfields, которые нелегко селиализуемы.

**edit:Причина медленного отклика в том, что у вас есть круговой вызов сериализаторов, поэтому система никогда не знает, когда остановиться. вот здесь:

class MySourceSerializer(serializers.ModelSerializer):
    def to_representation(self, instance):
        ...
        self.fields["document"] = DocumentSerializer(read_only=True) 
        #Mysource its calling Documentserializer
            ...
    #And here:
class DocumentSerializer(serializers.ModelSerializer):
    ...
    mysource = MySourceSerializer(many=True) #this one its calling the MysorceSerialize, so there are a endless loop recursion

источник : Django Rest Framework-Custom relational fields

Вернуться на верх