首页 > 解决方案 > RelatedField 序列化器 Django Rest 框架

问题描述

我有这个表存储在 Postgres 数据库中

用户

| id |     email       | password | gender |
| 01 | user1@email.com | pass1    |  male  |
| 02 | user2@email.com | pass3    | female |
| 03 | user3@email.com | pass2    |  male  |

分数

| id | school_mark | subject | user_id | status |
| 01 |      9      | history |    01   | True   |
| 02 |      8      | english |    02   | True   |
| 03 |      7      | math    |    01   | True   |
| 02 |      7      | english |    01   | False  |
| 03 |      6      | math    |    03   | False  |
...

# api/models.py

from django.db import models


class User(models.Model):
    email = models.EmailField()
    password = models.CharField(max_length=100)
    gender = models.CharField(max_length=100)

class Mark(models.Model):
    school_mark = models.IntegerField()
    subject = models.CharField(max_length=100)
    user_id = models.ForeignKey(User, on_delete=models.CASCADE)
    status = models.BooleanField(default=False)

我希望我的最终结果是这样的/api/marks/male

[
    {"id" : 01,
        "marks": [
            {"id": 01,
             "subject": "history",
             "school_mark": 9},
            {"id": 03,
             "subject": "history",
             "school_mark": 7}]}
    {"id" : 03,
    "marks": []}
]

首先仅选择“男性”表单用户,然后搜索选定用户的标记,但在响应中仅返回具有 status=TRUE 的标记

我开始认为 serializers.py 是这样的:

# api/serializers.py

from rest_framework import serializers
from .models import User, Mark

class MarkSerializer(serializers.ModelSerializer):
    class Meta:
        model = Mark
        exclude = ('status', 'user_id')


class UserSerializer(serializers.ModelSerializer):
    marks = MarkSerializer(many=True, read_only=True)

    class Meta:
        model = User
        fields = ('id', 'marks')

但后来我被困在views.py上

# api/views.py

from rest_framework import generics

from .models import User, Mark
from .serializers import UserSerializer

class MarkList(generics.ListAPIView):
    serializer_class = UserSerializer

    def get_queryset(self):
        # "/api/marks/<str:gender>/"
        gender = kwargs['gender']
        ???

知道如何继续吗?

标签: pythondjangodjango-rest-framework

解决方案


您是否设置了 url/response 结构?我意识到这不是您所要求的,但为了给出我能给出的最佳答案,我可能会更改您的设置的一些结构性内容:

  • 通常对于 RESTful API,/api/marks/会返回一个序列化Mark对象的列表,而不是您所显示的,这是一个列表Users,每个对象都有一个序列化的列表Marks。由于您只需要用户 ID,因此 DRF 提供了一种简单的非嵌套机制,用于以另一种方式(使用PrimaryKeyRelatedField)进行序列化。

  • 接下来,我可能会使用查询参数(/api/marks?gender=male )而不是/api/marks/male。这有点个人偏好,但在 REST 最佳实践中有一些基础(请参阅这个 SO 答案以获得很好的描述

  • 最后,ForeignKey字段 onMark应该命名为user,而不是user_id。存储外键字段时, Django 会自动附加_id到数据库列名,因此您编写的模型将生成一个名为user_id_id.

通过这些修改,以下代码将为您提供您请求的过滤(尽管序列化响应与上述初始请求略有不同):

# api/serializers.py

from rest_framework import serializers
from .models import Mark

class MarkSerializer(serializers.ModelSerializer):
    user = serializers.PrimaryKeyRelatedField(read_only=True)
    class Meta:
        model = Mark
        exclude = ('status')


# api/views.py

from rest_framework import generics

from .models import Mark
from .serializers import MarkSerializer

class MarkList(generics.ListAPIView):
    serializer_class = MarkSerializer

    def get_queryset(self):
        queryset = Mark.objects.filter(status=True)
        gender = self.request.query_params.get('gender')
        if gender is not None:
            queryset = queryset.filter(user__gender=gender)
        return queryset

我没有对此进行测试,但除非有任何拼写错误,否则从上面的示例中请求/api/marks?gender=male应该返回如下内容:

[
    {
        "id" : 01,
        "subject": "history",
        "school_mark": 9,
        "user": 01
    },
    {
        "id" : 03,
        "subject": "math",
        "school_mark": 7,
        "user": 01
    }
]

推荐阅读