在djangorestframework中使用django-filter 基于APIView视图

在日常开发中,我比较喜欢用restframework中的APIView来做开发,现有接口过滤的功能,周转google和百度,终于找到适合自己的用法,以此记录一下


model.py

class Article(Base):
    """文章模型"""
    COMMENT_STATUS = (
        (0, "禁止评论"),
        (1, "允许评论"),
    )

    PUBLIC_STATUS = (
        (0, "私人访问"),
        (1, "粉丝访问"),
        (2, "开放访问"),
    )

    CHECK_STATUS = (
        (-1, "审核不通过"),
        (0, "审核中"),
        (1, "审核通过"),
    )

    id = models.AutoField(primary_key=True, verbose_name="唯一主键")
    uid = models.ForeignKey(Account, on_delete=models.DO_NOTHING, verbose_name="用户", db_column='uid',
                            related_name='for_article_uid')
    title = models.CharField(max_length=128, default='', verbose_name='文章标题', db_column='title')
    content = models.TextField(verbose_name='文章内容', db_column='content')
    comment_status = models.IntegerField(verbose_name='评论区状态', choices=COMMENT_STATUS, default=1,
                                         db_column='comment_status')
    is_public = models.IntegerField(verbose_name="公开状态", choices=COMMENT_STATUS, default=2, db_column='is_public')
    is_check = models.IntegerField(verbose_name="审核状态", choices=CHECK_STATUS, default=0, db_column='is_check')

    class Meta:
        db_table = 'article_db'
        verbose_name = verbose_name_plural = '文章'

    def __str__(self):
        return self.title

views.py

class ArticleView(APIView):
    """文章视图"""
    filter_class = ArticleFilter  # 指定你的过滤器
    filter_backends = [DjangoFilterBackend, OrderingFilter, ]
    ordering = ('-add_date', '-title', )  # 排序 优先级 左->右依次减小
    
    def filter_queryset(self, queryset):
        """过滤"""
        for backend in list(self.filter_backends):
        	# 这里的backend().filter_queryset会自动调用内部方法
        	# 一步步追踪下去,会发现它反射了filter_class方法 注意,其中取值的办法为.qs
            queryset = backend().filter_queryset(self.request, queryset, self)
        return queryset
    
    @cache_page_middleware()  # 自定义的缓存页面的组件 可去掉
    def get(self, request, pk=None):
        """展示所有文章"""
        if pk:
            queryset = get_instance_or_not_found(Article, pk, '没有对应的文章') # 自定义的根据id值获取对象的函数,它会返回一个查询对象或者raise一个错误的response
            serializer = ArticleSerializer(queryset)
            return SuccessResponse({"data": serializer.data})  # 自定义的成功响应体
        else:
            queryset = Article.objects.select_related('uid').all() # 查询所有文章 并且关联查询外键
            queryset = self.filter_queryset(queryset=queryset)  # 调用过滤类
            page_info = build_cursor_pagination_response(self, queryset, ArticleSimpleSerializer, request)  # 自定义的分页函数 (基于游标分类) 返回一个字典
            return SuccessResponse(page_info)

    @login_and_auth_middleware
    def post(self, request):
        """新增文章"""
        reshape_data = copy(request.data)  # 在执行函数期间 request是不允许修改的,想要修改 请先copy
        reshape_data.update({"mini_uid": request.META['mini_uid'].id})  # 新增一个参数
        serializer = ArticleSerializer(data=reshape_data)
        serializer.is_valid(raise_exception=True)
        serializer.save()
        return SuccessResponse({"msg": "创建成功"})

urls.py

from django.contrib import admin
from django.urls import path, re_path

from api.article import views


urlpatterns = [
    # 后面的http_method_names限定接口的请求方式 默认是反射你重写的所有方法
    path('articles/', views.ArticleView.as_view(http_method_names=['get', 'post'])),
    re_path(r'articles/(?P<pk>\d+)/', views.ArticleView.as_view(http_method_names=['get', ])),
]


settings.py

REST_FRAMEWORK = {
	# 过滤
	'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',),
}

filters.py

from api.article.models import Article
from django_filters import rest_framework as filters


class ArticleFilter(filters.FilterSet):
	# method后跟的函数表示自定义筛选
	title = filters.CharFilter(method='title_filter', label="title")
	content = filters.CharFilter(method='content_filter', label="content")
	
	def title_filter(self, queryset, name, value):
		return queryset.filter(title__icontains=value)
	
	def content_filter(self, queryset, name, value):
		return queryset.filter(text__icontains=value)
	
	class Meta:
		model = Article
		fields = ("title", "content", )  # 可选字段

更多filter内部的用法

class ArticleFilter(filters.FilterSet):
	"""
		参数说明
		field_name: 过滤字段名,一般应该对应模型中字段名
		lookup_expr: 查询时所要进行的操作,和ORM中运算符一致
	"""
    title = filters.CharFilter(field_name='title',lookup_expr='icontains')  # 含有关系
    pub_time_year = filters.CharFilter(field_name='pub_time',lookup_expr='year')  # 年份等于
    pub_time_year__gt = filters.CharFilter(field_name='pub_time',lookup_expr='year__gt')  # 年份大于
    view__gt = filters.NumberFilter(field_name='view_no',lookup_expr="gt")  # 查看数量大于
    view__lt = filters.NumberFilter(field_name='view_no',lookup_expr="lt")  # 查看数量小于

    class Meta:
        model = Article
        fields = ['title','content','pub_time']  # 这些都限制于数据库的字段
# 持续更新...

版权声明:本文为weixin_45111060原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。