Как размещать и получать модель с внешним ключом
Я работаю над проектом NextJS + Django REST Framework, где у меня есть три модели: Document, MySource и QuestionBlock.
- Документ создается вместе с несколькими "блоками_вопросов", связанными с созданным документом. Они создаются вместе, и я уже реализовал это с помощью вложенных сериализаторов .
- После создания документа я хочу иметь возможность POST модели MySource, связанной с документом. Затем, когда я делаю GET запрос документа, все объекты mysource также должны быть отображены. .
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