django restframework PrimaryKeyRelatedField筛选的困惑

一.在开发某运动app时,遇见以下情况

  1.部分表内容如下:

class Sports(models.Model):
    ‘‘‘
    运动表
    ‘‘‘
    school = models.ForeignKey(Schools, verbose_name=‘学校‘, on_delete=models.CASCADE)
    sport_name = models.CharField(max_length=30, verbose_name=‘运动项目‘)
    image = models.ImageField(upload_to=‘sports/%Y/%m‘, verbose_name=‘运动封面图‘)
    add_time = models.DateTimeField(default=datetime.now, verbose_name=‘添加时间‘)

    class Meta:
        verbose_name = ‘运动项目‘
        verbose_name_plural = verbose_name
        unique_together = (‘school‘, ‘sport_name‘)

    def __str__(self):
        return self.sport_name
class Schedule(models.Model):
    ‘‘‘
    发起约运动
    ‘‘‘
    Status = ((1, ‘已完成‘), (2, ‘待人加入‘), (3, ‘已取消‘))
    user = models.ForeignKey(UserProfile, on_delete=models.CASCADE, verbose_name=‘发起人‘)
    join_type = models.BooleanField(verbose_name=‘是否发起人‘)
    now_people = models.IntegerField(verbose_name=‘已有人数‘, null=True, blank=True)
    school = models.ForeignKey(Schools, on_delete=models.CASCADE, verbose_name=‘学校‘, default=‘‘)
    sport = models.ForeignKey(Sports, on_delete=models.CASCADE, verbose_name=‘运动项目‘)
    address = models.CharField(verbose_name=‘约定地点‘, max_length=100)
    sport_time = models.DateTimeField(verbose_name=‘约定运动开始时间‘)
    sport_end_time = models.DateTimeField(verbose_name=‘约定运动结束时间‘, default=‘‘)
    people_nums = models.IntegerField(verbose_name=‘人数‘)
    add_time = models.DateTimeField(default=datetime.now, verbose_name=‘添加时间‘)
    status = models.IntegerField(choices=Status, verbose_name=‘状态‘)

    class Meta:
        verbose_name = ‘发起约运动‘
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.sport.sport_name + ‘-‘ + str(self.sport_time)
class UserProfile(AbstractUser):
    ‘‘‘
    用户表
    ‘‘‘
    name = models.CharField(max_length=30, null=True, blank=True, verbose_name=‘姓名‘)
    image = models.ImageField(upload_to=‘users/‘, default=‘‘, null=True, blank=True, verbose_name=‘头像‘)
    birthday = models.DateField(null=True, blank=True, verbose_name=‘出生年月‘)
    mobile = models.CharField(max_length=11, verbose_name=‘电话‘, null=True, blank=True)
    student_id = models.CharField(max_length=32, verbose_name=‘学号‘, default=‘‘, null=True, blank=True)
    gender = models.CharField(max_length=6, choices=((‘male‘, ‘男‘), (‘fmale‘, ‘女‘)), default=‘男‘, verbose_name=‘性别‘)
    email = models.EmailField(verbose_name=‘邮箱‘)
    school = models.ForeignKey(Schools, verbose_name=‘学校‘, on_delete=models.CASCADE)
    institude = models.ForeignKey(Schools, verbose_name=‘学院‘, on_delete=models.CASCADE, related_name=‘institude‘)
    profession = models.ForeignKey(Schools, verbose_name=‘专业‘, on_delete=models.CASCADE, related_name=‘profession‘)
    add_time = models.DateTimeField(default=datetime.now, verbose_name=‘添加时间‘)

    class Meta():
        verbose_name = ‘用户‘
        verbose_name_plural = verbose_name

    def __str__(self):
        if self.name:
            return self.name
        else:
            return self.username

class Schedule(models.Model):
    ‘‘‘
    发起约运动
    ‘‘‘
    Status = ((1, ‘已完成‘), (2, ‘待人加入‘), (3, ‘已取消‘))
    user = models.ForeignKey(UserProfile, on_delete=models.CASCADE, verbose_name=‘发起人‘)
    join_type = models.BooleanField(verbose_name=‘是否发起人‘)
    now_people = models.IntegerField(verbose_name=‘已有人数‘, null=True, blank=True)
    school = models.ForeignKey(Schools, on_delete=models.CASCADE, verbose_name=‘学校‘, default=‘‘)
    sport = models.ForeignKey(Sports, on_delete=models.CASCADE, verbose_name=‘运动项目‘)
    address = models.CharField(verbose_name=‘约定地点‘, max_length=100)
    sport_time = models.DateTimeField(verbose_name=‘约定运动开始时间‘)
    sport_end_time = models.DateTimeField(verbose_name=‘约定运动结束时间‘, default=‘‘)
    people_nums = models.IntegerField(verbose_name=‘人数‘)
    add_time = models.DateTimeField(default=datetime.now, verbose_name=‘添加时间‘)
    status = models.IntegerField(choices=Status, verbose_name=‘状态‘)

    class Meta:
        verbose_name = ‘发起约运动‘
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.sport.sport_name + ‘-‘ + str(self.sport_time)

  2.序列化想实现的功能:

    在序列化Schedule表时,sport是一个外键字段,想筛选sport的外键school是当前已登录的用户的school字段下的该学校所有运动项目(即筛选为queryset=Sports.objects.filter(school=user.school)),看似很简单,但该如何在字段中获取当前用户呐。

    首先想到,把该字段设计为SerializerMethodField字段,即如下(该方法确实能实现筛选,但这不是我要的结果,我想在序列化时有该字段,并且能选择筛选出的数据中的一个并添加新的数据):

#失败方法sport = serializers.SerializerMethodField()
def get_sport(self, obj):
        all_sport = Sports.objects.filter(school=self.context[‘request‘].user.school).values_list(‘pk‘,flat=True)
        json_all = SportsSerializer(all_sport, many=True,
                                                       context={‘request‘: self.context[‘request‘]}).data
        return all_sport

    然后就有点麻烦,想从写view中的get_queryset(),也是只能在list或retrieve中才能筛选,而序列化添加仍是一个问题;又想到从写一个类或者函数专门筛选,但是又增大了获取当前用户的难度,有点恼火,咋办,看看源码它写了哪些方法,真看不太懂,只能了解一点。

    看到了RelatedField中的get_queryset()方法,好像重写它有点作用:

 def get_queryset(self):
        queryset = self.queryset
        if isinstance(queryset, (QuerySet, Manager)):
            # Ensure queryset is re-evaluated whenever used.
            # Note that actually a `Manager` class may also be used as the
            # queryset argument. This occurs on ModelSerializer fields,
            # as it allows us to generate a more expressive ‘repr‘ output
            # for the field.
            # Eg: ‘MyRelationship(queryset=ExampleModel.objects.all())‘
            queryset = queryset.all()
        return queryset

三.目前最终方案:

    于是勉强写吧,重写该方法确实有用,只能说功能完成了,但还真得改进:

 class SportPrimaryKeyRelatedField(serializers.PrimaryKeyRelatedField):
        def get_queryset(self):
            queryset = self.queryset
            # if isinstance(queryset, (QuerySet, Manager)):
            # Ensure queryset is re-evaluated whenever used.
            # Note that actually a `Manager` class may also be used as the
            # queryset argument. This occurs on ModelSerializer fields,
            # as it allows us to generate a more expressive ‘repr‘ output
            # for the field.
            # Eg: ‘MyRelationship(queryset=ExampleModel.objects.all())‘
            queryset = queryset.filter(school=self.context[‘request‘].user.school)
            return queryset

    sport = SportPrimaryKeyRelatedField(queryset=Sports.objects.all(), label="运动")

    

原文地址:https://www.cnblogs.com/lyq-biu/p/9769421.html

时间: 2024-10-13 09:52:24

django restframework PrimaryKeyRelatedField筛选的困惑的相关文章

django restframework serializer 增加自定义字段

在使用django restframework serializer 序列化在django中定义的model时,有时候我们需要额外在serializer中增加一些model中没有的字段.有两种方法实现这个目的. 假设现在有一个Animal模型,其中有name, type, country字段,country为外键.我们在序列化Animal时,需要额外增加外键country的area信息. 方法一: 1.首先,在django的model中定义property class Animal(models

django restframework 初识

简介 从后台开发的角度来说,不借助restframework框架一样可以用django来写接口.但是有了restframework之后,我们用restframework会更加方便,因为这个框架帮我们做了很多事,使用这个框架来开发接口会更加便捷.restframework里面大致实现了以下功能: 权限 认证 访问评率限制 序列化 路由 视图 分页 渲染器 解析器 版本 CBV和FBV 首先django不存在CBV和FBV哪种方式更好的说法,它们的本质都是一样的,写在路由里都是对应一个函数,CBV的

基于Django RESTframework设计Restful API

导语 ? 关于RESTful的问题,在最近的面试中遇到很多,之前有过一定的了解,但没有系统性的总结分析.所以现在结合Django RESTframework来加深对RESTful的理解,同时梳理这过程的一些知识点. 什么是RESTful? ?这个问题是最容易想到的,首先要分析这个问题,网上的其他文章都会讲到有关REST(Representational State Transfer),中文翻译:"表述性状态传递",再白话一点就是对资源的表述性状态传递.刚开始,看到这里头都大了,那我们来

测开大佬告诉你:如何5分钟快速创建restful风格的API接口-使用django restframework框架

一.思考?? 1.创建API接口难吗? 软件测试工程师: 只测过API接口, 从没创建过 应该需要掌握一门后端开发语言和后端开发框架吧!? 脑容量有限,想想就可怕 2.如何创建API接口呢? 使用Django restframework能快速创建符合restful风格的API接口 通过Django restframework框架提供的序列化器.视图集可轻轻松松实现 简单高效,学习成本低 二.搭建项目工程???? 1.创建项目 打开pycharm 创建项目 使用豆瓣源安装Django Django

Django rest-framework框架

rest-framework框架有哪些作用? 一共有十点. 序列化 queryset对象转化为json给客户端返回. 视图 面试题:你写的类都继承过哪些类? 认证 权限 访问频率限制 路由控制 as_view()加参数,不加参数 解析器 分页 渲染器 查看详情. 版本 查看详情. 根据Django请求声明周期,执行顺序: 路由-->视图-->版本-->认证-->权限-->频率-->解析器-->序列化-->分页-->渲染 出现这种问题: 如何解决? se

django restframework解析器和分页

解析器 由来 django请求的原始数据是放到request.body当中,django默认的解析器只负责解析同时满足下面两个条件的数据 请求头 Content-Type: application/x-www-form-urlencoded 数据格式要求name=alex&age=18 只要这两个条件有一个不满足,django默认的解析器就不会把数据解析到request.POST里. 情况一: $.ajax({ url: ... type: POST, # 请求头默认是 application/

django restframework视图、路由系统和渲染器

视图 使用混合(mixins) 有多张表,多个类,这些类的代码除了从数据库的数据和相应的序列化类不一样,其他都一样,可以做第一步封装.原先做的封装成函数,然后调用函数,但是这里是利用类的继承,这是一种可以借鉴的方式.把逻辑部分封装成父类,代码不同的地方做配置即可.为了满足做一下配置就完成功能,这里使用了generics.GenericAPIView class UserView(mixins.ListModelMixin, mixins.CreateModelMixin, generics.Ge

Django Restframework.1

官方文档: https://www.django-rest-framework.org/ 中文版文档: https://q1mi.github.io/Django-REST-framework-documentation/ DRF特性:是基于Python打造的实现了RESTApi风格重量级框架 可浏览API 提供丰富认证 支持数据序列化 可以轻量嵌入,仅使用fbv 强大的社区支持 实现:(需要在工程文件的settings.py文件中进行注册) INSTALLED_APPS = [ 'django

【Django】组合筛选

组合筛选 数据库表设计: from django.db import models class Direction(models.Model): ''' 视频方向:全栈.前端.后端.测试.运维.自动化 ''' name = models.CharField(max_length=32,verbose_name="方向名称") m = models.ManyToManyField("Classification") # 别名 class Meta: verbose_n