反向工程
# 正向工程 - 模型变表 - 项目规模较小没有专业的DBA
# python manage.py makemigration<应用名>
# 反向工程 - 表变模型 -项目规模较大公司由专业DBA
# python manage.py inspectdb > <appname>/models.py
# 由数据库迁移数据
from django.db import models
class District(models.Model):
distid = models.IntegerField(primary_key=True)
parent = models.ForeignKey(to='self',on_delete=models.PROTECT,db_column='pid',blank=True, null=True)
name = models.CharField(max_length=255)
ishot = models.BooleanField(default=False)
intro = models.CharField(max_length=255,default='')
class Meta:
managed = False
db_table = 'tb_district'
过滤数据
django-filter
库包含一个DjangoFilterBackend
类
如果需要过滤数据(对数据接口设置筛选条件、排序条件等),可以使用django-filter
三方库来实现。
pip install django-filter
INSTALLED_APPS = [
'django_filters',
]
REST_FRAMEWORK = {
# 默认的后端过滤器
'DEFAULT_FILTER_BACKENDS': (
'django_filters.rest_framework.DjangoFilterBackend',
'rest_framework.filters.OrderingFilter',
),
}
过滤器api/utils
"""自定义记录数据过滤器"""
class RecordFilterSet(django_filters.FilterSet):
#过滤器
# carno调用自定义方法
carno = django_filters.CharFilter(method='filter_by_carno')
# gte最小值 lte最大值
min_date = django_filters.DateTimeFilter(field_name='makedate',lookup_expr='gte')
max_date = django_filters.DateTimeFilter(field_name='makedate',lookup_expr='lte')
@staticmethod
def filter_by_carno(queryset,name,value):
# 置换空格
value = normalize(value)
# 设置过滤条件car的carno、owner属性(模糊)/value为?carno=川A12345&owner=王 中的值
return queryset.filter(Q(car__carno=value)|
Q(car__owner__contains=value))
class Meta:
model = Record
# 根据这些项进行过滤
fields = ('carno','min_date','max_date')
视图函数
# 设置缓存过期时间为1S,缓存调用默认缓存,在settings文件中修改,修改数据和查找的缓存
@method_decorator(decorator=cache_page(timeout=1, cache='default'),name='retrieve')
@method_decorator(decorator=cache_page(timeout=1, cache='default'),name='list')
class RecordViewSet(ModelViewSet):
"""违章记录视图集合"""
# 内连接查询
queryset = Record.objects.all().select_related('car')
# 限流类
throttle_classes = ()
# 序列化器
serializer_class = RecordSerializer
# 后端过滤器
filter_backends = (DjangoFilterBackend,OrderingFilter)
# 排序方式
ordering = ('-makedate')
# 排序类调用自定义排序类
filterset_class = RecordFilterSet
drf的第三种方法
fbv在视图里使用函数处理请求。
cbv在视图里使用类处理请求。
定义序列化器api/serializers
class DistrictSerializer(serializers.ModelSerializer):
class Meta:
model = District
exclude = ('parent','ishot')
class DistrictDetailSerializer(serializers.ModelSerializer):
# 在这个模型中,没有这个字段使用SerializerMethodField,当用户获取这个数据,调用函数返回给用户
cities = serializers.SerializerMethodField()
# 定义静态方法,回调函数
# parent=district进行筛选
# 返回data数据
@staticmethod
# 当传入district的时候回调方法get_cities
def get_cities(district):
# 取到parent=district的对象
cities = District.objects.filter(parent=district)
return DistrictSerializer(cities,many=True).data
class Meta:
model = District
fields = ('distid','name','intro','cities')
使用装饰器,编写函数方法的视图函数
@api_view(['GET'])
@cache_page(timeout=None, cache='api')
def provinces(request):
# queryset获取查询对象
queryset = District.objects.filter(parent__isnull=True)
# 进行序列化 调用Serializer
serializer = DistrictSerializer(queryset, many=True)
# 返回数据,通过data属性可以获取序列化后的数据
return Response(serializer.data)
@api_view(['GET'])
def get_districts(request,distid):
# distid = url传入的<int:distid>进行筛选
district = District.objects.filter(distid=distid).first()
serializer = DistrictDetailSerializer(district)
return Response(serializer.data)
urlpatterns = [
path('districts/', get_provinces),
path('districts/<int:distid>/', get_districts),
] # 映射url districts/130000/
使用了Django自带的视图装饰器(@cache_page)来实现对API接口返回数据的缓存。可以使用多种装饰器 但需要在api_view下使用
函数方法中的分页器使用
获取url参数,127.0.0.1:8000/?page=<value>
# 非法数值则返回1 数值为空也返回1 如 127.0.0.1:8000/?page=asdsa
page = int(request.GET.get('page','1'))
size = int(request.GET.get('size','5'))
print(size,page)
queryset = District.objects.filter(parent__isnull=True)
# 每5份内容分页一次
paginator = Paginator(queryset,size)
serializer = DistrictSerializer(paginator.page(page).object_list,many=True)
return Response(serializer.data)
使用APIView及其子类/使用ViewSet及其子类
让浏览器能够发起DELETE/PUT/PATCH
<script>
const app = new Vue({
el: '#app',
data: {
records: [],
carno: '',
minDate:'',
maxDate:'',
currentPage: 1,
totalPage: 0,
loaded: false
},
methods: {
getData() {
let carno = this.carno.trim()
fetch(`/api/records/?carno=${carno}&min_date=${this.minDate}&max_date=${this.maxDate}&page=${this.currentPage}`)
.then(resp => resp.json())
.then(json => {
this.records = json.results
this.totalPage = parseInt((json.count - 1) / 5) + 1
console.log(json.results)
})
},
change() {
this.loaded = false
},
search() {
this.currentPage = 1
this.totalPage = 0
this.getData()
this.loaded = true
},
// fetch的PATCH方法将数据上传
handleItem(record) {
// 数据接口
fetch(`/api/records/${record.id}/`, {
method: 'PATCH',
// 上传数据
body: JSON.stringify({dealt: true}),
headers: {
// 数据类型 json
'content-type': 'application/json'
}
})
// 请求json
.then(resp => resp.json())
// 页面刷新
.then(json => record.dealt = json.dealt)
},
deleteItem(record) {
if (confirm('确定要删除吗?')) {
fetch(`/api/records/${record.id}/`, {
// 删除方法
method: 'DELETE'
})
.then(resp => {
// 204提示删除成功
if (resp.status == 204) {
// 根据下标删除记录
let index = this.records.indexOf(record)
this.records.splice(index, 1)
}
})
}
}
}
})
</script>