coredumped0x
coredumped0x

Reputation: 848

DRF one-to-one relation serializer with a pre-populated model

I have a couple models, one of which is already populated with data (book name/ chapter number/ paragraph number data), and I am implementing the feature for each user to be able to add a note per each unique book name/ chapter number/ paragraph number, which I could, but I have been stack for a couple of days trying to retrieve books with the related_name note of the current user if they have any. Here are my models:

Book model that is already populated with data.

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"

Here is the Note model that should store the current user's note regarding a specific unique book name / chapter number / paragraph number:

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

Here are my serializers:

Book serializer

from rest_framework import serializers
from .models import Book


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

Note serializer

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

The data I am getting:

{
    "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",
}

The data I am trying to get:

{
    "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"
}

Any help is appreciated

Upvotes: 1

Views: 103

Answers (2)

Pradip Kachhadiya
Pradip Kachhadiya

Reputation: 2235

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

Output:

{
    "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 )"
    ]
}

It's return all field:

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

Output:

{
    "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"
        }
    ]
}

Upvotes: 1

Avi Nehama
Avi Nehama

Reputation: 143

What you're actually trying to achieve is for the NoteSerializer to include fields from the Foreign-key related book model. Overriding the to_representation method of the serializer is clunky and not the way to go. See here a better approach.

Upvotes: 0

Related Questions