Skip to main content
 首页 » 编程设计

python之RelatedField Serializer Django Rest Framework

2024年09月07日35三少

我将这个表存储在 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  | 
... 
  • user_id 是将 marks 元素链接到每个用户的外键
  • id(在两个表中)都是主键

# 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": []} 
] 

首先仅选择“男性”形式的用户,然后搜索所选用户的标记,但在响应中仅返回状态为 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'] 
        ??? 

知道如何继续吗?

请您参考如下方法:

您是否设置了 url/response 结构?我知道这并不完全是您所要求的,但为了给出我能提供的请您参考如下方法:,我可能会更改您的设置的一些结构性内容:

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

  • 接下来,我可能会使用查询参数 (/api/marks?gender=male) 而不是 /api/marks/male。这有点个人偏好,但在 REST 最佳实践中有一定的基础(请参阅 this SO answer for a nice description)

  • 最后,Mark 上的ForeignKey 字段应命名为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 
    } 
]