zoukankan      html  css  js  c++  java
  • 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="运动")

        

  • 相关阅读:
    centos7配置java环境
    puppet使用 apache passsenger 作为前端 (debian)
    puppet 和 apache passenger的配置
    puppet 安装
    JQuery Plugin 开发
    Shell脚本中的 测试开关 和 特殊参数
    CPPUTest 单元测试框架(针对 C 单元测试的使用说明)
    Makefile 使用总结
    挂载KVM Guest操作系统磁盘
    Linux资源管理-IO优先级
  • 原文地址:https://www.cnblogs.com/lyq-biu/p/9769421.html
Copyright © 2011-2022 走看看