過濾器(組件)使用
群查接口各種篩選、過濾數據准備
models.py
# 數據庫表數據
class Course(BaseModel):
"""課程"""
course_type = (
(0, '付費'),
(1, 'VIP專享'),
(2, '學位課程')
)
level_choices = (
(0, '初級'),
(1, '中級'),
(2, '高級'),
)
status_choices = (
(0, '上線'),
(1, '下線'),
(2, '預上線'),
)
name = models.CharField(max_length=128, verbose_name="課程名稱")
course_img = models.ImageField(upload_to="courses", max_length=255, verbose_name="封面圖片", blank=True, null=True)
course_type = models.SmallIntegerField(choices=course_type, default=0, verbose_name="付費類型")
# 使用這個字段的原因
brief = models.TextField(max_length=2048, verbose_name="詳情介紹", null=True, blank=True)
level = models.SmallIntegerField(choices=level_choices, default=0, verbose_name="難度等級")
pub_date = models.DateField(verbose_name="發布日期", auto_now_add=True)
period = models.IntegerField(verbose_name="建議學習周期(day)", default=7)
attachment_path = models.FileField(upload_to="attachment", max_length=128, verbose_name="課件路徑", blank=True,
null=True)
status = models.SmallIntegerField(choices=status_choices, default=0, verbose_name="課程狀態")
course_category = models.ForeignKey("CourseCategory", on_delete=models.SET_NULL, db_constraint=False, null=True, blank=True,
verbose_name="課程分類")
students = models.IntegerField(verbose_name="學習人數", default=0)
sections = models.IntegerField(verbose_name="總課時數量", default=0)
pub_sections = models.IntegerField(verbose_name="課時更新數量", default=0)
price = models.DecimalField(max_digits=6, decimal_places=2, verbose_name="課程原價", default=0)
teacher = models.ForeignKey("Teacher", on_delete=models.DO_NOTHING, null=True, blank=True, verbose_name="授課老師")
orders = models.IntegerField(default=0)
# 自定義插拔式字段
@property
def level_name(self):
return self.get_level_display()
# 連表查詢
@property
def section_list(self):
temp_section_list = []
for chapter in self.coursechapters.all():
for section in chapter.coursesections.all():
if len(temp_section_list) >= 4:
return temp_section_list
temp_section_list.append({
'chapter': chapter.chapter,
'name': section.name,
'free_trail': section.free_trail,
})
return temp_section_list
class Meta:
db_table = "luffy_course"
verbose_name = "課程"
verbose_name_plural = "課程"
def __str__(self):
return "%s" % self.name
class CourseCategory(BaseModel):
"""分類"""
name = models.CharField(max_length=64, unique=True, verbose_name="分類名稱")
orders = models.IntegerField(default=0)
class Meta:
db_table = "luffy_course_category"
verbose_name = "分類"
verbose_name_plural = verbose_name
def __str__(self):
return "%s" % self.name
class CourseChapter(BaseModel):
"""章節"""
course = models.ForeignKey("Course", related_name='coursechapters', on_delete=models.CASCADE, verbose_name="課程名稱")
chapter = models.SmallIntegerField(verbose_name="第幾章", default=1)
name = models.CharField(max_length=128, verbose_name="章節標題")
summary = models.TextField(verbose_name="章節介紹", blank=True, null=True)
pub_date = models.DateField(verbose_name="發布日期", auto_now_add=True)
orders = models.IntegerField(default=0)
class Meta:
db_table = "luffy_course_chapter"
verbose_name = "章節"
verbose_name_plural = verbose_name
def __str__(self):
return "%s:(第%s章)%s" % (self.course, self.chapter, self.name)
class CourseSection(BaseModel):
"""課時"""
section_type_choices = (
(0, '文檔'),
(1, '練習'),
(2, '視頻')
)
chapter = models.ForeignKey("CourseChapter", related_name='coursesections', on_delete=models.CASCADE,
verbose_name="課程章節")
name = models.CharField(max_length=128, verbose_name="課時標題")
orders = models.PositiveSmallIntegerField(verbose_name="課時排序")
section_type = models.SmallIntegerField(default=2, choices=section_type_choices, verbose_name="課時種類")
section_link = models.CharField(max_length=255, blank=True, null=True, verbose_name="課時鏈接",
help_text="若是video,填vid,若是文檔,填link")
duration = models.CharField(verbose_name="視頻時長", blank=True, null=True, max_length=32) # 僅在前端展示使用
pub_date = models.DateTimeField(verbose_name="發布時間", auto_now_add=True)
free_trail = models.BooleanField(verbose_name="是否可試看", default=False)
class Meta:
db_table = "luffy_course_Section"
verbose_name = "課時"
verbose_name_plural = verbose_name
def __str__(self):
return "%s-%s" % (self.chapter, self.name)
adminx.py
import xadmin
from . import models
# 注冊xadmin后台管理
xadmin.site.register(models.Course)
xadmin.site.register(models.CourseCategory)
xadmin.site.register(models.CourseChapter)
xadmin.site.register(models.CourseSection)
urls.py
from django.urls import path, re_path
from . import views
urlpatterns = [
path('free', views.FreeCourseListAPIView.as_view()),
re_path('^free/(?P<pk>\d+)$', views.FreeCourseRetrieveAPIView.as_view()),
path('category', views.CategoryListAPIView.as_view()),
path('chapters', views.ChapterListAPIView.as_view()),
]
serializers.py
from rest_framework import serializers
from .import models
# 課程序列化
class FreeCourseModelSerializer(serializers.ModelSerializer):
class Meta:
model = models.Course
fields = (
'id',
'name',
'course_img',
'brief',
'level_name',
'period',
'students',
'price',
)
# 分類序列化
class CategoryModelSerializer(serializers.ModelSerializer):
class Meta:
model = models.CourseCategory
fields = ('name', 'id')
class CourseSectionModelSerialize(serializers.ModelSerializer):
class Meta:
model = models.CourseSection
fields = '__all__' # 所有字段
# 章節
class CourseChapterModelSerializer(serializers.ModelSerializer):
coursesections = CourseSectionModelSerialize(many=True) # 子序列化
class Meta:
model = models.CourseChapter
fields = (
'id',
'name',
'chapter',
'summary',
'coursesections'
)
views.py
from rest_framework.generics import ListAPIView
from . import models, serializers
# 配置過濾器類,導包, 排序過濾器
from rest_framework.filters import OrderingFilter
# 導包, 搜索過濾器
from rest_framework.filters import SearchFilter
# 自定義過濾器,導入
from .filters import LimitFilter
# 分類過濾器
from django_filters.rest_framework import DjangoFilterBackend
# 導入自定義分頁器
from .paginations import CouerPageNumberPagination
# 自定義分類區間篩選導入
from.filters import CourseFilterSet
# 群查
class FreeCourseListAPIView(ListAPIView):
queryset = models.Course.objects.filter(is_delete=False, is_show=True).order_by('-orders').all()
serializer_class = serializers.FreeCourseModelSerializer
# 群查排序過濾器 1、導包
# 2、配置過濾器類
# # LimitFilter 自定義過濾器 訪問url格式http://127.0.0.1:8000/course/free?limit=2
filter_backends = [OrderingFilter, SearchFilter, LimitFilter, DjangoFilterBackend ]
# 3.添加過濾的字段
# 訪問接口方式為http://127.0.0.1:8000/course/free?ordering=-id,price
# ordering = 'price'
ordering_fields = ['price', 'id']
# 群查搜索過濾器
# 1、 導包
# 2、 配置過濾器類,統一配置在filter_backends中,如上
# 3、 添加搜索字段,訪問鏈接格式 http://127.0.0.1:8000/course/free?search=python
search_fields = ['name', 'brief']
# 自定義過濾器,新建filters.py文件,完成自定義
# LimitFilter 自定義過濾器 訪問url格式http://127.0.0.1:8000/course/free?limit=2
# 分類過濾器
# 分類篩選過濾器:1、安裝環境-- pip install django-filter
# 2、然后在過濾器庫:filter_backends =[]中配置DjangoFilterBackend
# 3、在filter_fields 中配置分組篩選字段
# 訪問數據格式:http://127.0.0.1:8000/course/free?course_category=2
# 參與分類篩選的字段:所有字段都可以,但是用於分組的字段更有意義
filter_fields = ['course_category']
# 自定義區間分組篩選過濾器,從自定義文件導入
filter_class = CourseFilterSet
# 分頁器
# 新建 paginations.py
# 1、導入自定義分頁器
# 2、選擇分頁器, 訪問格式:http://127.0.0.1:8000/course/free?page=2
pagination_class = CouerPageNumberPagination
# 單查
from rest_framework.generics import RetrieveAPIView
class FreeCourseRetrieveAPIView(RetrieveAPIView):
queryset = models.Course.objects.filter(is_delete=False, is_show=True).order_by('-orders')
serializer_class = serializers.FreeCourseModelSerializer
# 分類查詢 群查
class CategoryListAPIView(ListAPIView):
queryset = models.CourseCategory.objects.filter(is_delete=False, is_show=True).order_by('-orders').all()
serializer_class = serializers.CategoryModelSerializer
# 課程章節查詢, 群查
class ChapterListAPIView(ListAPIView):
queryset = models.CourseChapter.objects.filter(is_delete=False, is_show=True).order_by('-orders').all()
serializer_class = serializers.CourseChapterModelSerializer
自定義過濾器文件入口
filters.py
# 自定義過濾器
from rest_framework.filters import BaseFilterBackend
# 自定義限制過濾器,限制顯示條數
class LimitFilter(BaseFilterBackend):
def filter_queryset(self, request, queryset, view):
# request:從前台請求獲取過濾的條件 query_params
# queryset:要處理的數據
# view:從視圖中反射過濾相關的配置
limit = request.query_params.get('limit')
try:
return queryset[:int(limit)] # queryset數據庫查詢結果
except:
return queryset
# 分類篩選,自定義區間篩選
# 基於django-filter插件,自定義分類篩選器,完成指定區間篩選(一般都是對應數字字段)
from django_filters.rest_framework.filterset import FilterSet
from django_filters import filters
from . import models
class CourseFilterSet(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.Course
fields = ['course_category', 'max_price', 'min_price']
自定義分頁器導入
paginations.py
# 分頁器
from rest_framework.pagination import PageNumberPagination
from rest_framework.pagination import LimitOffsetPagination
from rest_framework.pagination import CursorPagination
class CouerPageNumberPagination(PageNumberPagination):
# 默認一頁條數
page_size = 2
# 訪問路徑的額外參數(選擇哪一頁的 key)
page_query_param = 'page'
# 用戶自定義一頁條數
page_size_query_param = 'page_size'
# 用戶自定義一頁最大控制條數
max_page_size = 10
class CourseLimitOffsetPagination(LimitOffsetPagination):
# 默認一頁條數
default_limit = 2
limit_query_param = 'limit'
offset_query_param = 'offset'
max_limit = 2
class CourseCursorPagination(CursorPagination):
cursor_query_param = 'cursor'
page_size = 2
page_size_query_param = 'page_size'
max_page_size = 2
# ordering = 'id' # 默認排序規則,不能和排序過濾器OrderingFilter共存
補充
群查接口各種篩選組件數據准備
models.py
class Car(models.Model):
name = models.CharField(max_length=16, unique=True, verbose_name='車名')
price = models.DecimalField(max_digits=10, decimal_places=2, verbose_name='價格')
brand = models.CharField(max_length=16, verbose_name='品牌')
class Meta:
db_table = 'api_car'
verbose_name = '汽車表'
verbose_name_plural = verbose_name
def __str__(self):
return self.name
admin.py
admin.site.register(models.Car)
serializers.py
class CarModelSerializer(serializers.ModelSerializer):
class Meta:
model = models.Car
fields = ['name', 'price', 'brand']
urls.py
url(r'^cars/$', views.CarListAPIView.as_view()),
drf搜索過濾組件
views.py 搜索組件使用方法:路由后綴加 /?search=1 (name和price中包含1的數據都會被查詢出來)
from rest_framework.generics import ListAPIView
# 第一步:drf的SearchFilter - 搜索過濾
from rest_framework.filters import SearchFilter
class CarListAPIView(ListAPIView):
queryset = models.Car.objects.all()
serializer_class = serializers.CarModelSerializer #自定義認證
# 第二步:局部配置 過濾類 們(全局配置用DEFAULT_FILTER_BACKENDS)
filter_backends = [SearchFilter]
# 第三步:SearchFilter過濾類依賴的過濾條件 => 接口:/cars/?search=...
search_fields = ['name', 'price'] #篩選字段
# eg:/cars/?search=1,name和price中包含1的數據都會被查詢出
drf排序過濾組件
views.py
from rest_framework.generics import ListAPIView
# 第一步:drf的OrderingFilter - 排序過濾
from rest_framework.filters import OrderingFilter
class CarListAPIView(ListAPIView):
queryset = models.Car.objects.all()
serializer_class = serializers.CarModelSerializer
# 第二步:局部配置 過濾類 們(全局配置用DEFAULT_FILTER_BACKENDS)
filter_backends = [OrderingFilter]
# 第三步:OrderingFilter過濾類依賴的過濾條件 => 接口:/cars/?ordering=...
ordering_fields = ['pk', 'price']
# eg:/cars/?ordering=-price,pk,先按price降序,如果出現price相同,再按pk升序
drf基礎分頁組件
paginations.py
from rest_framework.pagination import PageNumberPagination
class MyPageNumberPagination(PageNumberPagination):
# ?page=頁碼 定義代表頁碼的屬性,如果寫pages,就是?pages=頁碼
page_query_param = 'page'
# ?page=頁碼 設置默認下一頁顯示的條數
page_size = 3
# ?page=頁碼&page_size=條數 用戶自定義一頁顯示的條數
page_size_query_param = 'page_size'
# 用戶自定義一頁顯示的條數最大限制:數值超過5也只顯示5條
max_page_size = 5
views.py
from rest_framework.generics import ListAPIView
class CarListAPIView(ListAPIView):
# 如果queryset沒有過濾條件,就必須 .all(),不然分頁會出問題
queryset = models.Car.objects.all()
serializer_class = serializers.CarModelSerializer
# 分頁組件 - 給視圖類配置分頁類即可 - 分頁類需要自定義,繼承drf提供的分頁類即可
pagination_class = pagenations.MyPageNumberPagination
#eg:/cars/ 顯示第一頁三條
/cars/?page=2&page_size=4 每頁顯示4條,顯示第二頁的4條