Django实现前后端分离开发

以之前车辆违章项目来做

修改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>&nbsp;&nbsp;
            <button data="/search/?page={{ prev_page }}&size={{ page_size }}">上一页</button>&nbsp;&nbsp;
            <button disabled>上一页</button>&nbsp;&nbsp;
            第{{ current_page }}页/共{{ total_page }}页&nbsp;&nbsp;
            <button data="/search/?page={{ next_page }}&size={{ page_size }}">下一页</button>&nbsp;&nbsp;
            <button disabled>下一页</button>&nbsp;&nbsp;
            <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请求



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

像风一样的男人@

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值