Почему выпадающее поле исчезает в Django Rest Framework при использовании пользовательского сериализатора для поля?

Я пытаюсь использовать Django, DRF, ViewSet и Serializers для создания простого веб-блога. У меня есть главное приложение и внутри него:

main\models.py:

from django.db import models
from django.contrib.auth.models import User

class TimeStampMixin(models.Model):
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        abstract = True

class Category(TimeStampMixin):
    name=models.CharField(max_length=255)
    parent = models.ForeignKey("self", on_delete=models.CASCADE, null=True, blank=True)

    def __str__(self):
        return self.name

class PostStatus(models.Model):
    status = models.CharField(max_length=50)

    def __str__(self):
        return self.status
    
def get_draft_status():
    return PostStatus.objects.get_or_create(status='draft')[0].id

class Post(models.Model):
    author = models.ForeignKey(User, on_delete=models.CASCADE, null=True)
    title = models.CharField(max_length=200)
    description = models.TextField()
    category = models.ForeignKey(Category, on_delete=models.CASCADE, null=True)
    status = models.ForeignKey(PostStatus, on_delete=models.CASCADE, default=get_draft_status)

    def __str__(self):
        return self.title

class RelatedPost(models.Model):
    post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='related_posts')
    related_post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='related_to')

    def __str__(self):
        return f"{self.post.title} related to {self.related_post.title}"

<
from rest_framework import serializers, status
from rest_framework.response import Response
from .models import Post, RelatedPost, PostStatus, Category

class PostStatusSerializer(serializers.ModelSerializer):
    class Meta:
        model = PostStatus
        fields = '__all__'

class RelatedPostSerializer(serializers.ModelSerializer):
    class Meta:
        model = RelatedPost
        fields = '__all__'

class CategorySerializer(serializers.ModelSerializer):
    class Meta:
        model = Category
        fields = '__all__'

class PostSerializer(serializers.ModelSerializer):
    related_posts = serializers.SerializerMethodField()
    category = serializers.SerializerMethodField()

    class Meta:
        model = Post
        fields = '__all__'
    
    def get_related_posts(self, obj):
        related_posts = obj.related_posts.all()
        return [{'id': rp.related_post.id, 'title': rp.related_post.title} for rp in related_posts]
    
    def get_category(self, obj):
        if obj.category:
            return {'id': obj.category.id, 'name': obj.category.name}
        else:
            return {}

<
from .models import PostStatus, Post, RelatedPost, Category
from .serializers import PostSerializer, RelatedPostSerializer, PostStatusSerializer, CategorySerializer

class CategoryViewSet(viewsets.ModelViewSet):
    queryset = Category.objects.all()
    serializer_class = CategorySerializer

class PostStatusViewSet(viewsets.ModelViewSet):
    queryset = PostStatus.objects.all()
    serializer_class = PostStatusSerializer

class PostViewSet(viewsets.ModelViewSet):
    queryset = Post.objects.all()
    serializer_class = PostSerializer

class RelatedPostViewSet(viewsets.ModelViewSet):
    queryset = RelatedPost.objects.all()
    serializer_class = RelatedPostSerializer

<
from django.contrib import admin
from django.urls import include, path
from rest_framework.routers import DefaultRouter
from .views import PostStatusViewSet, PostViewSet, RelatedPostViewSet, CategoryViewSet

router = DefaultRouter()
router.register(r'category', CategoryViewSet, basename='category')
router.register(r'post-status', PostStatusViewSet, basename='post-status')
router.register(r'posts', PostViewSet, basename='post')
router.register(r'related-posts', RelatedPostViewSet, basename='related-post')

urlpatterns = [
    #path('admin/', admin.site.urls),
    path('', include(router.urls)),
]

<

category = serializers.SerializerMethodField()

<
def get_category(self, obj):
    if obj.category:
        return {'id': obj.category.id, 'name': obj.category.name}
    else:
        return {}

PostSerializer enter image description here

<

main\views.py:<<<1>> enter image description here

>

Проблема в том, что когда я использую category = serializers.SerializerMethodField(), выпадающий список категорий в HTML-форме исчезает (секция №2 на первом изображении). Как я могу включить в секцию номер 1 и номер 4 одновременно, чтобы иметь настраиваемый ответ категории и выпадающий список категорий в HTML-форме?

Вы можете просто переопределить метод сериализатора сериализации и заменить значение категории на "правильный" формат.

class PostSerializer(serializers.ModelSerializer):
    related_posts = serializers.SerializerMethodField()

    class Meta:
        ...

    def get_related_posts(self, obj):
        ...

    def to_representation(self, instance):
        new_cat_repr = {
            'id': instance.category.id, 
            'name': instance.category.name
        }
        representation = super().to_representation(instance)
        representation.pop("category")
        representation['category'] = new_cat_repr
        return representation

P.S. Поле SerializerMethodField предназначено только для чтения.

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