以之前车辆违章项目来做
修改urls.py
path('api/',api) #返回json收据的url
在views.py中添加函数
def api(request:HttpRequest) -> HttpResponse:
queryset = Record.objects.filter(is_deleted=False)\
.dafer('is_deleted','deleted_time','updated_time')\
.select_related('car').order_by('-makedate')
carinfo = request.POST.get('carinfo')
if carinfo:
carinfo = re.sub(r'\s','',carinfo)
queryset = queryset.filter(
Q(car__carno__istartswith=carinfo) | Q(car__owner__icontains=carinfo)
)
records = []
for record in queryset:
data = {
'no':record.no,
'carno':record.car.carno,
'owne':record.car.owner,
'reason':record.reason,
'makedate':record.makedate,
'punish':record.punish,
'dealt':record.dealt
}
records.append(data)
return JsonResponse(records,safe=False)
#请求api可以返回一串数组
#上面的代码中,我们通过循环遍历查询违章得到的 QuerySet 对象,将每个违章的数据处理成一个字
典,在将字典保存在名为 subjects 的列表容器中,最后利用 JsonResponse 完成对列表的序列化,向浏
览器返回JSON格式的数据。由于 JsonResponse 序列化的是一个列表而不是字典,所以需要指定 safe
参数的值为 False 才能完成对 subjects 的序列化,否则会产生 TypeError 异常。
利用Django第三方库djangorestframework来实现序列化
安装依赖
pip install djangorestframework
在settings.py中修改代码
INSTALLED_APPS = [
...,
'restframework',
]
在应用下新建一个py文件(本项目在search下)
新建py文件名称为 serializers.py
进入serializers.py中
"""
自定义序列化器(把模型对象处理成字典)
"""
from rest_framework import serializers
from search.models import Record
class RecordSerializer(serializers.ModelSerializer):
class Meta:
model = Record #要序列化的对象
fields = '__all__' #__all__ 序列化所有
修改views.py函数
def records_api(request):
queryset = Record.objects.filter(is_deleted=False) \
.defer('is_deleted', 'updated_time', 'deleted_time') \
.select_related('car').order_by('-no')
carinfo = request.POST.get('carinfo','')
if carinfo:
info = re.sub(r'\s','',carinfo)
queryset = queryset.filter(
Q(car__carno__istartswith=carinfo) | Q(car__owner__icontains=carinfo)
)
resi = RecordSerializer(queryset,many=True) #这里返回一个列表
return JsonResponse({'records':resi.data}) #这种形式直接返回字典 不用加safe=False
#(resi.data,safe=False) 如果返回列表 必须加上safe=False
#最好给字典格式的
用Resonpon返回数据接口
from rest_framework.decorators import api_view
from rest_framework.response import Response
@api_view(('GET',)) #如果用Resonpon返回必须用这个装饰器,('GET'表示只接受get请求,是一个元祖)
def records_api(request):
queryset = Record.objects.filter(is_deleted=False) \
.defer('is_deleted', 'updated_time', 'deleted_time') \
.select_related('car').order_by('-no')
carinfo = request.POST.get('carinfo','')
if carinfo:
info = re.sub(r'\s','',carinfo)
queryset = queryset.filter(
Q(car__carno__istartswith=carinfo) | Q(car__owner__icontains=carinfo)
)
resi = RecordSerializer(queryset,many=True)
return Response({'record':resi.data}) #返回的是一个字典,也可以返回一个列表(resi.data)
#请求这个函数则返回drm自带的渲染页面,
#这里存在1+N查询问题,下面代码优化了这个问题
优化查询时间,在serializers.py中修改要序列化的字段
class RecordSerializer(serializers.ModelSerializer):
class Meta:
model = Record
#fields = '__all__' #序列化全部模型
fields = ('no','reason','punish','makedate','dealt','car') #需要哪些字段
#exclude = ('is_deleted','updated_time','deleted_time') #排除这几个字段
#这两者必须有一个,否则会报错
数据中外键字段显示的外键主键,我们想要的是外键字段中的数据,而不是关联对象
from rest_framework import serializers
from serach.models import Record, Car
class CarSerializer(serializers.ModelSerializer):
'''车序列化器'''
class Meta:
model = Car
fields = ('carno','owner')
class RecordSerializer(serializers.ModelSerializer):
'''违章记录序列化器'''
car = serializers.SerializerMethodField()
def get_car(self,record):
return CarSerializer(record.car).data
#return {'carno':record.car.carno,'owner':record.car.owner}
#直接返回字典的话,不需要上面的那个类,但是比较繁琐不推荐
class Meta:
model = Record
#fields = '__all__' #序列化全部模型
#fields = ('no','reason','punish','makedate','dealt','car') #需要哪些字段
exclude = ('is_deleted','updated_time','deleted_time') #排除这几个字段
#这两者必须有一个,否则会报错
#现在为止这个api接口已经实现,接下来实现前端渲染这些数据
用前端渲染页面
#修改index.html,用前端来渲染
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>违章查询</title>
<style>
#result>table {
border-collapse: collapse;
}
#result th {
border-bottom: 1px solid black;
}
#result td {
text-align: center;
height: 30px;
border-bottom: 1px dashed darkgray;
}
#result tr:last-child > td {
border: none;
}
</style>
</head>
<body>
<div id="result">
<input type="text" @keydown.enter="search()" v-model.trim="carinfo" size="30" placeholder="请输入车牌号或车主姓名">
<button @click="search()">查询</button>
<hr>
<table v-if="records.length > 0">
<tr>
<th width="100">车牌号</th>
<th width="100">车主姓名</th>
<th width="150">违章原因</th>
<th width="180">违章时间</th>
<th width="180">处罚方式</th>
<th width="100">是否受理</th>
<th width="120">操作</th>
</tr>
<tr v-for="record in records">
<td>{{ record.car.carno }}</td>
<td>{{ record.car.owner }}</td>
<td>{{ record.reason }}</td>
<td>{{ record.makedate }}</td>
<td>{{ record.punish }}</td>
<td>{{ record.dealt | handledOrNot }}</td>
<td>
<a href="" @click.prevent="handle(record)">受理</a>
<a href="" @click.prevent="remove(record)">删除</a>
</td>
</tr>
</table>
<!--
<div class="buttons">
<button data="/search/?page=1&size={{ page_size }}">首页</button>
<button data="/search/?page={{ prev_page }}&size={{ page_size }}">上一页</button>
<button disabled>上一页</button>
第{{ current_page }}页/共{{ total_page }}页
<button data="/search/?page={{ next_page }}&size={{ page_size }}">下一页</button>
<button disabled>下一页</button>
<button data="/search/?page={{ total_page }}&size={{ page_size }}">末页</button>
</div>
-->
</div>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.11/vue.min.js"></script>
<script>
let app = new Vue({
el: '#result',
data: {
carinfo: '',
records: []
},
created() { <!-- created()声明周期方法 打开首页直接执行search()函数 -->
this.search()
},
methods: {
search() {
fetch('/api/?carinfo=' + this.carinfo)
.then(resp => resp.json())
.then(json => {
this.records = json.records
})
},
handle(record) {
if (!record.dealt) {
fetch('/handle/?rno=' + record.no).then(resp => resp.json()).then(json => {
if (json.code === 30000) {
record.dealt = true
}
})
}
},
remove(record) {
if(confirm('确定要删除这条记录吗?')) {
if (record.dealt) {
fetch('/delete/?rno=' + record.no).then(resp => resp.json()).then(json => {
let index = this.records.indexOf(record)
this.records.splice(index, 1)
})
} else {
alert('只能删除已受理的违章记录')
}
}
}
},
filters: { <!-- 自定义过滤器-->
handledOrNot(dealt) {
return dealt? '已受理' : '未受理'
}
}
})
</script>
</body>
</html>
#删除之前的templates文件夹
新建static文件夹,用来存放html页面(项目根路径下创建)
#修改settings.py配置文件
删掉TEMPLATES中DIR:[os.path.join(...)]删掉中括号的内容
添加static静态资源路径
文件末行添加 STATICFILES_DIRS = [os.path.join(BASE_DIR,'static'),]
#项目上线后不会这样做
#修改views.py中index函数 请求首页重定向到index.html(实际项目中不需要写这个)
def index(request: HttpRequest) -> HttpResponse:
return redirect('../static/html/index.html')
#修改api()函数
POST改GET请求