zoukankan      html  css  js  c++  java
  • drf

    数据准备

    model.py文件

    定义两个表Car表和Brand表,其中Car中的brand字段外键关联Brand表

    from django.db import models
    class BaseModel(models.Model):
        is_delete = models.BooleanField(default=False)
        create_time = models.DateTimeField(auto_now_add=True)
        class Meta:
            abstract = True
    
    
    class Car(BaseModel):
        name = models.CharField(max_length=32)
        price = models.DecimalField(max_digits=5, decimal_places=2)
        brand = models.ForeignKey('Brand', db_constraint=False, on_delete=models.DO_NOTHING, related_name='cars')
        @property
        def brand_name(self):
            return self.brand.name
        class Meta:
            db_table = 'old_boy_car'
            verbose_name = '汽车'
            verbose_name_plural = verbose_name
        def __str__(self):
            return self.name
        
    class Brand(BaseModel):
        name = models.CharField(max_length=32)
        class Meta:
            db_table = 'old_boy_brand'
            verbose_name = '品牌'
            verbose_name_plural = verbose_name
        def __str__(self):
            return self.name
    

    新建的serializer.py文件

    brand字段只参与反序列化,brand_name只参与序列化

    from rest_framework.serializers import ModelSerializer
    from . import models
    class CarModelSerializer(ModelSerializer):
        class Meta:
            model = models.Car
            fields = ('name','price','brand','brand_name')
            extra_kwargs = {
                "brand":{
                    'write_only':True
                },
                'brand_name':{
                    'read_only':True
                },
            }
    

    分类筛选 filter_fields

    views.py文件

    from rest_framework.viewsets import ModelViewSet
    from . import models, serializer
    from django_filters.rest_framework import DjangoFilterBackend
    
    class CarModelViewSet(ModelViewSet):
        queryset = models.Car.objects.filter(is_delete=False)
        serializer_class = serializer.CarModelSerializer
        
        filter_backends = [DjangoFilterBackend]
        # 分类: 一般都是可以分组的字段
        filter_fields = ['brand']  
    
    # 按品牌brand分类,url链接:/car/?brand=1
    

    区间筛选 filter_class

    新建的 filterset.py

    max_price与min_price是用于参与区间分类,不写也可以仅做分类同 filter_fields效果一样

    from django_filters import FilterSet,filters
    from . import models
    class CarFilterSet(FilterSet):
        max_price = filters.NumberFilter(field_name='price',lookup_expr='lte')
        min_price = filters.NumberFilter(field_name='price',lookup_expr='gte')
        class Meta:
            model = models.Car
            # brand 还是实现分类
            fields = ['brand','max_price','min_price']
    

    views.py文件

    from rest_framework.viewsets import ModelViewSet
    from . import models, serializer
    from django_filters.rest_framework import DjangoFilterBackend
    from .filterset import CarFilterSet
    
    class CarModelViewSet(ModelViewSet):
        queryset = models.Car.objects.filter(is_delete=False)
        serializer_class = serializer.CarModelSerializer
        
        filter_backends = [DjangoFilterBackend]
        filter_class = CarFilterSet
    # url链接:/car/?max_price=100  价格不超过100
    # url链接:/car/?min_price=10  价格不低于10
    # url链接:/car/?brand=1&min_price=10&max_price=100  品牌brand为1且价格在[10,100]内的汽车
    

    DjangoFilterBackend部分源码解析

    1. 在DjangoFilterBackend组件中先调用filter_queryset方法中

    def filter_queryset(self, request, queryset, view):
        filterset = self.get_filterset(request, queryset, view)  # 获取筛选条件
        # 如果filterset为None,表示没有筛选条件
        if filterset is None:
            return queryset
        
        # 无效的筛选条件处理
        if not filterset.is_valid() and self.raise_exception:
            raise utils.translate_validation(filterset.errors)
        return filterset.qs
    

    2. 调用get_filterset方法获取filterset

    def get_filterset(self, request, queryset, view):
        filterset_class = self.get_filterset_class(view, queryset)  # 获取筛选类
        if filterset_class is None:
            return None
    
        kwargs = self.get_filterset_kwargs(request, queryset, view)
        return filterset_class(**kwargs)
    

    3.调用get_filterset_class方法获取filterset_class

    def get_filterset_class(self, view, queryset=None):
        """
        Return the `FilterSet` class used to filter the queryset.
        """
        filterset_class = getattr(view, 'filterset_class', None)  
        filterset_fields = getattr(view, 'filterset_fields', None)
    	
        # 将filter_class映射给filterset_class
        if filterset_class is None and hasattr(view, 'filter_class'):
            utils.deprecate(
                "`%s.filter_class` attribute should be renamed `filterset_class`."
                % view.__class__.__name__)
            filterset_class = getattr(view, 'filter_class', None)
    
        # 将filter_fields映射给filterset_fields
        if filterset_fields is None and hasattr(view, 'filter_fields'):
            utils.deprecate(
                "`%s.filter_fields` attribute should be renamed `filterset_fields`."
                % view.__class__.__name__)
            filterset_fields = getattr(view, 'filter_fields', None)
    	
        # 有filterset_class时执行,filterset_class定义的是一个类
        if filterset_class:
            filterset_model = filterset_class._meta.model 
    
            # FilterSets do not need to specify a Meta class
            if filterset_model and queryset is not None:
                assert issubclass(queryset.model, filterset_model), 
                    'FilterSet model %s does not match queryset model %s' % 
                    (filterset_model, queryset.model)
    
            return filterset_class
        
    	# 有filterset_fields时执行
        if filterset_fields and queryset is not None:
            MetaBase = getattr(self.filterset_base, 'Meta', object)
    
            class AutoFilterSet(self.filterset_base):
                class Meta(MetaBase):
                    model = queryset.model
                    fields = filterset_fields
                    
            return AutoFilterSet
    
        return None
    
  • 相关阅读:
    Centos 7安装python3(PY3.6)
    linux仅修改文件夹权限 分别批量修改文件和文件夹权限
    【工作手札】Nginx接口代理可跨域
    微信自定义分享链接信息(标题,图片和内容)实现过程
    ios 等保 删除 uiwebview
    postman 接口批量测试
    uniapp之 页面滑动 组件
    uniapp之 点击图片跳转详情 组件
    安装 node.js
    创建一个mpvue的小程序
  • 原文地址:https://www.cnblogs.com/863652104kai/p/11522191.html
Copyright © 2011-2022 走看看