RelatedField序列化器Django Rest框架

时间:2018-08-07 13:57:59

标签: python django django-rest-framework

我将此表存储在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": []}
]

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

有什么想法吗?

2 个答案:

答案 0 :(得分:2)

您是否设置了url /响应结构?我意识到这并不是您所要的,但是为了给出最佳答案,我可能会对您的设置进行一些结构上的更改:

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

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

  • 最后,Marks上的ForeignKey字段应命名为Mark,而不是user。在存储外键字段时,Django会自动将user_id附加到数据库列名称中,因此您编写的模型将产生一个名为_id的数据库列。

进行了这些修改后,以下代码将为您提供所请求的过滤功能(尽管如上所述,序列化响应与初始请求有所不同)

user_id_id

我尚未对此进行测试,但是除非您有任何错别字,否则从上面的示例中请求 / api / marks?gender = male 都应返回以下内容:

# 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

答案 1 :(得分:0)

这不是 RESTful API的最佳实践。因此,我建议您执行以下操作

将您的$(".feel").click(function() { alert("s"); $(this).next(".hide").show(); });更改为有意义

view.py

class MarkList(generics.ListAPIView): serializer_class = MarkSerializer queryset = Mark.objects.all() class UserList(generics.ListAPIView): serializer_class = UserSerializer queryset = User.objects.all()

urls.py

现在,您必须 API端点,它们是urlpatterns = [ url(r'user/', UserList.as_view()), url(r'mark/', MarkList.as_view()) ]/path/user/

如果您在视图上需要过滤器,请使用一些第三方过滤器,例如django-filter(它也有很好的文档说明)或覆盖/path/mark方法 。请参见下面的示例

get_queryset()

要使用这些过滤器,您必须将API用作
class MarkList(generics.ListAPIView): serializer_class = MarkSerializer queryset = Mark.objects.all() def get_queryset(self): queryset = Mark.objects.all() if self.request.GET.get('gender'): queryset = queryset.filter(user_id__gender=self.request.GET.get('gender')) # if you need to add more filter like "subject" or "status", implement here if self.request.GET.get('subject'): # subject filter queryset = queryset.filter(subject=self.request.GET.get('subject')) if self.request.GET.get('status'): # status filter queryset = queryset.filter(subject=self.request.GET.get('status')) return queryset

/path/mark/?gender=male&status=True&subject=some_subject

/path/mark/?subject=some_subject