首页 > 解决方案 > 使用具有外键的模型序列化程序在 Django Rest Framework 中的父表上执行 CRUD

问题描述

在我的 API 中,我有两个模型QuestionOption如下所示

class Question(models.Model):
    body = models.TextField()


class Options(models.Model):
    question = models.ForeignKey(Question, on_delete=models.CASCADE)
    option = models.CharField(max_length=100)
    is_correct = models.SmallIntegerField()

在创建问题时,可以同时创建选项会更好。并且不应创建已存在的问题,但如果选项与以前的选项不同,则可以更改选项。
我正在使用ModelSerializerModelViewSetQuestion我对and使用不同的 url 和视图Option

序列化程序.py

class QuestionSerializer(serializers.ModelSerializer):
    class Meta:
        model = Question
        fields = '__all__'


class OptionReadSerializer(serializers.ModelSerializer):
    question = QuestionSerializer(read_only=True)

    class Meta:
        model = Option
        fields = ('question', 'option', 'is_correct')


class OptionWriteSerializer(serializer.ModelSerializer):
    class Meta:
        model = Option
        fields = ('question', 'option', 'is_correct')

视图.py

class QuestionViewSet(ModelViewSet):
    seriaizer_class = QuestionSerializer
    queryset = Question.objects.all()


class OptionViewSet(ModelViewSet):
    queryset = Option.objects.all()

    def get_serializer_class(self):
        if self.request.method == 'POST':
            return OptionWriteSerializer
        return OptionReadSerializer

网址.py

from django.urls import include
from rest_framework.routers import DefaultRouter

router = DefaultRouter()
router.register('api/question', QuestionViewset, base_name='question')
router.register('api/option', OptionViewSet, base_name='option')

urlpatterns = [
    path('', include(router.urls))
]

这样,我总是必须先创建问题,然后我才能为该问题单独添加选项。我认为这可能不是一个实用的方法。
最好可以同时添加问题和选项,并且类似于所有 CRUD 操作。

JSON格式的预期结果和发布数据如下所示:

{
    "body": "Which country won the FIFA world cup 2018",
    "options": [
        {
            "option": "England",
            "is_correct": 0
        },
        {
            "option": "Germany",
            "is_correct": 0
        },
        {
            "option": "France",
            "is_correct": 1
        }
    ]
}

标签: djangodjango-modelsdjango-rest-frameworkdjango-viewsdjango-rest-viewsets

解决方案


我们可以使用PrimaryKeyRelatedField

tldr;

我相信一个Question可以有多个Options附加到它。而不是让Option一个Question.

像这样的东西:

class Question(models.Model):
    body = models.TextField()
    options = models.ManyToManyField(Option)

class Options(models.Model):
    text = models.CharField(max_length=100)
    is_correct = models.BooleanField()

然后我们可以像这样使用PrimaryKeyRelatedField :

class QuestionSerializer(serializers.ModelSerializer):
    options = serializers.PrimaryKeyRelatedField(queryset=Options.objects.all(), many=True, read_only=False)
    class Meta:
        model = Question
        fields = '__all__'

参考:https ://www.django-rest-framework.org/api-guide/relations/#primarykeyrelatedfield


推荐阅读