【问题标题】:DRF one-to-one relation serializer with a pre-populated model具有预填充模型的 DRF 一对一关系序列化器
【发布时间】:2021-02-23 18:56:41
【问题描述】:

我有几个模型,其中一个模型已经填充了数据(书名/章节号/段落号数据),我正在为每个用户实现该功能,以便能够为每个唯一的书名添加一个注释/章节编号/段落编号,我可以,但我已经堆叠了几天试图用当前用户的related_namenote检索书籍(如果有的话)。这是我的模型:

Book 已填充数据的模型。

from django.db import models


class Book(models.Model):
    day = models.CharField(max_length=128)
    book = models.CharField(max_length=128)
    chapter = models.CharField(max_length=256)
    paragraph = models.CharField(max_length=256)
    text = models.TextField()
    link = models.CharField(max_length=256)

    def __str__(self):
        return f'{self.book}_{self.chapter}.{self.paragraph} '

    class Meta:
        ordering = ['-id']
        verbose_name = "Paragraph"
        verbose_name_plural = "Paragraph"

这是Note 模型,它应该存储当前用户关于特定唯一书名/章节号/段落号的注释:

from django.db import models
from django.conf import settings
from rest_framework.reverse import reverse
from paragraphs.models import Book

class Note(models.Model):
    owner = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='author', on_delete=models.CASCADE)
    paragraph = models.ForeignKey(Book, related_name='note', on_delete=models.CASCADE)
    created = models.DateTimeField(auto_now_add=True)
    text = models.TextField(default=None)

    def __str__(self):
        return f'Note on {self.paragraph}' 

    class Meta:
        ordering = ['created']

    def save(self, *args, **kwargs):
        """
        """
        options = {'text': self.text} if self.text else {}
        super(Note, self).save(*args, **kwargs)

    def get_absolute_url(self): 
        return reverse('note-detail', args=[self.id])

这是我的序列化程序:

Book序列化器

from rest_framework import serializers
from .models import Book


class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model = Book
        fields = '__all__'

Note序列化器

from rest_framework import serializers
from .models import Note
from users.serializers import UserSerializer
from paragraphs.serializers import BookSerializer


class NoteSerializer(serializers.ModelSerializer):
    owner = UserSerializer(many=False, read_only=True)

    class Meta:
        model = Note
        fields = ['id', 'owner', 'paragraph', 'text', 'created']

    def to_representation(self, instance):
        self.fields['paragraph'] = BookSerializer(read_only=True)
        return super(NoteSerializer, self).to_representation(instance)

    def user(self):
        request = self.context.get('request', None)
        if request:
            return request.user
        return None

    def create(self, validated_data):
        note, _ = Note.objects.update_or_create(
            owner=self.user(),
            paragraph=validated_data.get('paragraph', None),
            defaults={'text': validated_data.get('text', None)})
        return note

我得到的数据:

{
    "id": 25,
    "day": "2",
    "book": "Some book",
    "chapter": "1",
    "paragraph": "3",
    "text": "This is an example text that the user would like to attach a note to",
    "link": "https://somelink.com",
}

我想要获取的数据:

{
    "id": 25,
    "day": "2",
    "book": "Some book",
    "chapter": "1",
    "paragraph": "3",
    "text": "This is an example text that the user would like to attach a note to",
    "link": "https://somelink.com",
    "note": "note of current user or none"
}

感谢任何帮助

【问题讨论】:

    标签: python django django-models serialization django-rest-framework


    【解决方案1】:

    models.py:

    class Book(models.Model):
        day = models.CharField(max_length=128)
        book = models.CharField(max_length=128)
        chapter = models.CharField(max_length=256)
        paragraph = models.CharField(max_length=256)
        text = models.TextField()
        link = models.CharField(max_length=256)
    
        def __str__(self):
            return f'{self.book}_{self.chapter}.{self.paragraph} '
    
        class Meta:
            ordering = ['-id']
    
    class Note(models.Model):
        owner = models.ForeignKey(to = User, related_name='author', on_delete=models.CASCADE)
        book = models.ForeignKey(Book, related_name='note', on_delete=models.CASCADE)
        created = models.DateTimeField(auto_now_add=True)
        text = models.TextField(default=None)
        
        def __str__(self):
            return '%s(%s)' %(self.owner,self.book)
    

    serializers.py:

    class NoteSerializer(serializers.ModelSerializer):
        class Meta:
            model = Note
            fields = ['id', 'owner', 'book', 'text', 'created']
            
    class BookSerializer(serializers.ModelSerializer):
        note = serializers.StringRelatedField(many=True, read_only=True)
        # note = NoteSerializer(many=True, read_only=True)
        class Meta:
            model = Book
            fields = ['day','book','chapter','paragraph','text','link','note']
    

    输出:

    {
        "day": "2",
        "book": "some book",
        "chapter": "1",
        "paragraph": "example",
        "text": "some textttttttttttttttttttttttttttttttttttttttttttttttt",
        "link": "http://127.0.0.1:8000/admin/api/book/add/",
        "note": [
            "admin(some book_1.example )"
        ]
    }
    

    返回所有字段:

    class NoteSerializer(serializers.ModelSerializer):
        class Meta:
            model = Note
            fields = ['id', 'owner', 'book', 'text', 'created']
            
    class BookSerializer(serializers.ModelSerializer):
        # note = serializers.StringRelatedField(many=True, read_only=True)
        note = NoteSerializer(many=True, read_only=True)
        class Meta:
            model = Book
            fields = ['day','book','chapter','paragraph','text','link','note']
    

    输出:

    {
        "day": "2",
        "book": "some book",
        "chapter": "1",
        "paragraph": "example",
        "text": "some textttttttttttttttttttttttttttttttttttttttttttttttt",
        "link": "http://127.0.0.1:8000/admin/api/book/add/",
        "note": [
            {
                "id": 2,
                "owner": 1,
                "book": 1,
                "text": "saaaaaaaaaaaaaaaaaaa",
                "created": "2021-02-24T14:34:13.279750Z"
            }
        ]
    }
    

    【讨论】:

    • 谢谢您的回复,先生。但是我收到错误 AttributeError: 'Book' object has no attribute 'owner',有什么想法吗?再次感谢您
    • @MurphyAdam 我编辑了我的答案...我在我的机器上尝试了您的问题。它完全有效...
    • 感谢您的支持和时间。我很感激!
    【解决方案2】:

    您实际上想要实现的是让 NoteSerializer 包含来自外键相关书籍模型的字段。覆盖序列化程序的 to_representation 方法很笨拙,而且不是要走的路。请参阅here 更好的方法。

    【讨论】:

    • 感谢您的回复。我很感激。我点击链接并尝试应用我认为我从帖子中理解的内容,但我收到以下错误:django.db.utils.ProgrammingError: column notes_note.book_id does not exist LINE 1: ...ELECT "notes_note" ."id", "notes_note"."owner_id", "notes_not。请问我写模型的方式有什么问题吗?
    • 不看代码很难判断哪里出了问题。从技术上讲,您的模型似乎是合理的,但是从建模(以及因此的可读性和可维护性)的角度来看,它们非常令人困惑。特别是,在 Book 模型上使用“book”字段是没有意义的。
    • 是的,您是对的,我相信该模型的最佳名称是“Lesson”,它还可以避免混淆。感谢您的帮助。啊,当你没有说代码的时候,你能告诉我你的代码是什么意思吗?
    • @MurphyAdam 我指的是您的评论:“我点击链接并尝试应用我认为我从帖子中理解的内容”
    • 啊,是的。我设置了 note = serializers.RelatedField(read_only=True) 并添加了 depth = 1。你认为有更好的方法吗?我觉得我这样做的方式不对
    猜你喜欢
    • 2017-10-30
    • 2018-10-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-03
    • 1970-01-01
    • 2020-05-20
    • 1970-01-01
    相关资源
    最近更新 更多