功能演示
信息展示

添加功能

編輯功能

刪除功能

DRF構建后台數據
本例的Model如下
from django.db import models class Publish(models.Model): name = models.CharField(max_length=32) class Author(models.Model): name = models.CharField(max_length=32,verbose_name='姓名') class Book(models.Model): title = models.CharField(verbose_name='書名',max_length=56) price = models.DecimalField(verbose_name='價格',max_digits=8,decimal_places=2) pub_date = models.DateField(verbose_name='出版日期') publish = models.ForeignKey(to=Publish,on_delete=models.CASCADE) authors = models.ManyToManyField(to=Author)
注冊DRF
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'book.apps.BookConfig', 'rest_framework', ]
路由分發如下
# 查看與新增—— GET與POST url(r'^books/$',views.BookListView.as_view(),name='book_get_post'), # 修改與刪除—— PUT與DELETE url(r'^book/(?P<pk>\d+)/$',views.BookView.as_view(),name='book_put_delete'),
視圖函數如下
from rest_framework.views import APIView from rest_framework.response import Response from book import models from book.my_serializer import BookSerializer class BookListView(APIView): def get(self, request, *args, **kwargs): """ 獲取書籍信息 """ # 用自定義的序列化器去實現~~~ all_books = models.Book.objects.all() # 第一個參數是instance~是一個對象 # 但是all()方法查出來的是一個“對象列表”——所以需要加many=True ser_obj = BookSerializer(all_books, many=True) # 返回自定義序列化器的data return Response(ser_obj.data) def post(self, request, *args, **kwargs): """新增數據 返回新建的書籍的數據 json格式 """ # 用序列化器進行校驗!!! # 注意:這里用的是request.data去取新增的值!!! print('>>>>>>',request.data) ser_book = BookSerializer(data=request.data) if ser_book.is_valid(): ser_book.save() # 校驗成功並且成功保存的話~返回新增的數據! return render(request,'book_list.html') else: print(ser_book.errors) return Response(ser_book.errors) class BookView(APIView): def get(self,request,pk,*args,**kwargs): # 找Model對象 book_obj = models.Book.objects.filter(pk=pk).first() # 序列化器對象——此時instance只有一個book_obj,不用加many=True了! ser_obj = BookSerializer(instance=book_obj) # 用Response方法返回序列化器對象的data return Response(ser_obj.data) def put(self,request,pk,*args,**kwargs): book_obj = models.Book.objects.filter(pk=pk).first() # partial=True —— 表示支持“部分提交/局部更新” ser_obj = BookSerializer(instance=book_obj,data=request.data,partial=True) if ser_obj.is_valid(): ser_obj.save() return Response(ser_obj.data) else: return Response(ser_obj.errors) # 刪除方法不需要用序列化器了 def delete(self,request,pk,*args,**kwargs): obj = models.Book.objects.filter(pk=pk).first() if obj: obj.delete() return Response({'msg':'刪除成功!'}) else: return Response({"error":'數據不存在!'})
自定義的序列化器代碼如下
# -*- coding:utf-8 -*- from rest_framework import serializers from book import models class PublishSerializer(serializers.Serializer): id = serializers.IntegerField(read_only=True) name = serializers.CharField() class AuthorSerializer(serializers.Serializer): id = serializers.IntegerField() name = serializers.CharField() class BookSerializer(serializers.Serializer): # 與Book中的屬性對應上 # id 也需要~后面編輯與刪除用得到~~設置read_only,添加的時候不必填 id = serializers.IntegerField(read_only=True) title = serializers.CharField() price = serializers.DecimalField(max_digits=8,decimal_places=2) pub_date = serializers.DateField() # 外鍵的~這個字段其實存的是id~~注意這里是publish_id——數據庫中存儲的字段~~但是這種方式只能拿到id值 # publish_id = serializers.IntegerField() # 多對一 外鍵關聯~ # 如果我們想拿publish的name的話,就需要交給上一個序列化器PublishSerializer去處理 # 提交的時候~~不用填這個,所以設置required=False # 只有get請求要他而post請求不用它~所以設置 read_only=True publish = PublishSerializer(required=False,read_only=True) # 多對多~ # 只有get請求要他而post請求不用它:read_only=True # 下面必須有一個 get_字段名 的方法對應! authors = serializers.SerializerMethodField(read_only=True) # post提交用這個字段~是int類型的 # get請求不要他~~設置 write_only=True post_publish = serializers.IntegerField(write_only=True) # post提交用這個字段~是一個ListField~列表里是數字 # get請求不要他~~設置 write_only=True post_authors = serializers.ListField(write_only=True) # 多對多關系查找authors用到的方法——與上面的SerializerMethodField對應 def get_authors(self,obj): # 注意~obj是Book對象!! # print(obj) # 基於對象的跨表查詢~注意是多個對象了~many應該設置為True ser_obj = AuthorSerializer(obj.authors.all(),many=True) return ser_obj.data # POST方式增加數據需要 def create(self, validated_data): # post提交的時候~~重寫create方法 # post提交給的數據應該是這種格式的 # 注意后面那兩個是post_publish、post_authors~專門用於提交的字段 """ { "title": "西游記", "price": 12.20, "pub_date": "2019-12-22T10:10:11Z", "post_publish": 1, "post_authors": [1,2] } """ print('validated_data>>>',validated_data) book_obj = models.Book.objects.create( title=validated_data.get('title'), price=validated_data.get('price'), pub_date=validated_data.get('pub_date'), publish_id=validated_data.get('post_publish'), ) # 多對多插入數據~~基於對象的跨表查詢 # 注意用set方法存多對多關系的數據 book_obj.authors.set(validated_data.get('post_authors')) return book_obj # PUT請求修改數據需要寫的方法 def update(self, instance, validated_data): # 如果取到了就用修改的~~如果沒有就用原來的數據 instance.title = validated_data.get('title',instance.title) instance.prince = validated_data.get('price',instance.price) instance.pub_date = validated_data.get('pub_date',instance.pub_date) # 上面設置了post_publish為write_only了~所以修改要用post_publish instance.publish_id = validated_data.get('post_publish',instance.publish_id) # 先save~然后再處理一下多對多關系的數據 instance.save() # 基於對象的跨表查詢~~注意用set方法存多對多關系的數據 # 如果沒有的話需要用all方法取出所有對象~~ # # 上面設置了post_authors為write_only了~所以修改要用post_authors instance.authors.set(validated_data.get('post_authors',instance.authors.all())) # 最后記得把instance 返回 return instance
在DRF自帶的頁面進行數據的增刪改查測試
至此DRF就寫好了,我們可以根據路由去訪問對應的頁面進行數據的增刪改查操作(需要注意,必須先在settings中注冊了rest_framework后才能訪問DRF自帶的頁面)
DRF自帶的頁面是這樣的:

當然,我們不能讓用戶看這樣的頁面,這就需要前端請求DRF構建好的數據進行標簽的構建了。
前端請求DRF構建好的數據並構建頁面效果
測試路由如下
# 書籍展示的頁面 url(r'^book_list/$',views.book_list,name='book_list'), # 添加書籍的頁面 url(r'^add_book_view/$',views.add_book,name='add_book_view'),# 編輯書籍的展示頁面~~ url(r'edit_book_view/(?P<pk>\d+)/$',views.edit_book,name='edit_book'),
視圖函數如下
視圖函數非常簡單,再加上是進行數據測試,所以這里的視圖函數只負責返回頁面。
數據的操作全部是用ajax與js做的。
# 展示 書籍列表 def book_list(request): return render(request,'book_list.html') # 展示 添加書籍頁面 def add_book(request): return render(request,'add_book.html') # 編輯書籍的展示頁面 def edit_book(request,pk): return render(request,'edit_book.html')
所有頁面的母版
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{% block title %} {% endblock title %}</title>
<link rel="stylesheet" href="{% static 'bootstrap-3.3.7/css/bootstrap.css' %}">
<style>
{# th中的文字劇中 bootstrap設置的是left #}
th {
text-align: center;
}
</style>
</head>
<body style="padding-top:52px;">
<!--導航 獨立於頁面,不包含在盒子里面。不要放在container里面 -->
<nav class="navbar navbar-default navbar-fixed-top navbar-inverse">
<div class="container-fluid">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse"
data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">火之國</a>
</div>
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse pull-right" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
<li><a href="#">Link</a></li>
<li><a href="#">Link</a></li>
</ul>
</div><!-- /.navbar-collapse -->
</div><!-- /.container-fluid -->
</nav>
<div class="container">
<div class="row">
<div class="col-md-12">
<div class="pannel panel-danger">
<!--panel-heading-->
<div class="panel-heading">
<!--panel-title-->
<h3 class="panel-title">火之國圖書管理系統</h3>
</div>
<!--panel-body-->
<div class="panel-body">
<!--把其他的組件放到panel-body里面-->
<!--block -->
{% block pannel-body %}
{% endblock pannel-body %}
</div>
</div>
</div>
</div>
</div>
<script src="{% static 'jquery-3.4.1.js' %}"></script>
<script src="{% static 'bootstrap-3.3.7/js/bootstrap.js' %}"></script>
{% block script %}
{% endblock script %}
</body>
</html>
書籍展示頁面及刪除書籍的功能
書籍展示發送的是get請求。
刪除書籍發送的是delete請求。
{% extends 'base.html' %}
{% block title %}
主頁
{% endblock title %}
{% block pannel-body %}
{% csrf_token %}
<a id="add_book" href="{% url 'add_book_view' %}" class="btn btn-success pull-right">添加書籍</a>
<br><br>
<div id="div_table" class="table-responsive" style="text-align: center">
<table id="table" class="table table-striped table-bordered table-hover table-condensed">
<thead>
<tr class="success">
<th>編號</th>
<th>書籍名稱</th>
<th>價格</th>
<th>出版日期</th>
<th>出版社</th>
<th>作者</th>
<th>操作</th>
</tr>
</thead>
{# 委托的父級標簽用tbody #}
<tbody id="tbody">
</tbody>
</table>
</div>
{% endblock pannel-body %}
{% block script %}
<script>
// 格式化時間的函數
function formatDate(time) {
var date = new Date(time);
var year = date.getFullYear(),
month = date.getMonth() + 1,//月份是從0開始的
day = date.getDate(),
hour = date.getHours(),
min = date.getMinutes(),
sec = date.getSeconds();
var newTime = year + '-' +
month + '-' +
day + ' ' +
hour + ':' +
min + ':' +
sec;
return newTime;
}
// 頁面加載自動觸發ajax請求~向DRF獲取所有數據並在前端渲染
$(document).ready(function () {
$.ajax({
url: '/books/',
type: 'get',
success: function (data) {
console.log(data, typeof (data));
// data是一個object
for (var i = 0; i < data.length; i++) {
// data[i]是一個個自定義對象
//console.log(data[i],typeof(data[i]));
var tr = document.createElement('tr');
var td_num = document.createElement('td');
// 提前把編號寫進tr中去 注意同時將id也加進去
td_num.innerHTML = (i + 1) + '<span class="book_pk" style="display: none">' + data[i].id + '</span> </td>';
//這時tr的第一個元素就是一個個的編號——並且里面的span標簽帶着每個數據的id
tr.append(td_num);
for (var j in data[i]) {
//console.log(j);
// 不用填id字段
if (j === 'id') {
continue;
}
// 新建一個td標簽,把遍歷的數據加進去
var td = document.createElement('td');
//格式化一下出版日期的格式
if (j === 'pub_date') {
data[i][j] = formatDate(data[i][j]);
}
//展示出版社的名字
if (j === 'publish') {
data[i][j] = data[i][j]['name'];
}
//展示作者的名字
if (j === 'authors') {
//console.log(data[i][j]);
var authors = '';
for (var k in data[i][j]) {
authors += data[i][j][k]['name'] + ' ';
}
data[i][j] = authors;
}
td.append(data[i][j]);
tr.append(td);
}
//循環完,最后把編輯與刪除按鈕添加進去
var tdd = document.createElement('td');
tdd.innerHTML = '<td><a class="btn btn-primary edit_book"><span class="glyphicon glyphicon-pencil" aria-hidden="true"></span><span>編輯</span>\n' +
'</a><a class="btn btn-danger del_book"><span class="glyphicon glyphicon-remove" aria-hidden="true"></span><span>刪除</span></a></td>';
tr.append(tdd);
// 最后將tr加到tbody中
$('#tbody').append(tr);
}
}
})
});
// 刪除按鈕的點擊事件
// 用委托實現
// 這里也可以加一個"模態對話框"~給用戶一個確認刪除刪除的提示
$('#tbody').on('click', '.del_book', function () {
// 找到這本書對應的id~
// console.log($(this).parent().parent().find('.book_pk').text());
var book_id = $(this).parent().parent().find('.book_pk').text();
$.ajax({
url: '/book/' + book_id + '/',
type: 'delete',
success: function (data) {
location.href = '/book_list/';
}
})
});
// 編輯按鈕的點擊事件
// 用委托實現
$('#tbody').on('click', '.edit_book', function () {
// 找到這本書對應的id~
var book_id = $(this).parent().parent().find('.book_pk').text();
$.ajax({
url:'/book/'+book_id+'/',
type:'put',
success:function (data) {
// data是待編輯書籍的數據
console.log(data,typeof(data));
// 序列化數據
data_json = JSON.stringify(data);
// 將數據存到session中
sessionStorage.edit_book_data = data_json;
// 跳轉到編輯書籍頁面
location.href = '/edit_book_view/' + book_id +'/';
}
})
})
</script>
{% endblock script %}
添加書籍頁面
添加書籍發送的是post請求。
{% extends 'base.html' %}
{% block title %}
主頁
{% endblock title %}
{% block pannel-body %}
<div class="col-md-8 col-md-offset-2">
<h2 class="text-center">添加書籍</h2>
<div>
<div class="form-group">
<label for="book_name">書籍名稱</label>
<input type="text" id="book_name" class="form-control" placeholder="書籍名稱"
autocomplete="off">
<span class="help-block"></span>
</div>
<div class="form-group">
<label for="price">價格</label>
<input type="number" id="price" class="form-control" placeholder="價格"
autocomplete="off">
<span class="help-block"></span>
</div>
<div class="form-group">
<label for="pub_date">出版日期</label>
<input type="date" id="pub_date" class="form-control" placeholder="出版日期">
<span class="help-block"></span>
</div>
<div class="form-group">
<label for="">出版社</label>
<select id="publish" class="form-control">
<option value="1">蘋果出版社</option>
<option value="2">西瓜出版社</option>
</select>
</div>
<div class="form-group">
<label for="">作者</label>
<select name="authors" id="authors" class="form-control" multiple>
<option value="1">whw</option>
<option value="2">naruto</option>
<option value="3">sasuke</option>
</select>
</div>
<div class="form-group">
<h4 id="add_error" class="pull-left" style="color:red;margin-top: 0"></h4>
<input id="confirm_add" type="button" class="btn btn-success pull-right" value="確認添加">
</div>
</div>
</div>
{% endblock pannel-body %}
{% block script %}
<script>
{# 確認按鈕 #}
$('#confirm_add').click(function () {
{#console.log(123123);#}
var title = $('#book_name').val();
var price = $('#price').val();
var pub_date = $('#pub_date').val();
// 下拉列表被選中的這樣選取
var publish = $('#publish option:selected').val();
//ajax操作
$.ajax({
url: '{% url "book_get_post" %}',
type: 'post',
data: {
title: title,
price: price,
pub_date: pub_date,
//pub_date: "2019-08-02T09:35:13.064532Z",
post_publish: publish,
//post_authors: authors,
post_authors: $('#authors').val(),
},
// 傳數組
traditional: true,
success: function (data) {
console.log(data);
//alert('添加成功!');
location.href = '{% url "book_list" %}';
}
})
});
</script>
{% endblock script %}
編輯書籍頁面
編輯書籍這里需要說一下過程:
(1)首先我在書籍展示那里點擊“編輯”的時候,先把當前點擊的書籍的信息取出來,然后序列化,最后將序列化的數據存在session中。
(2)然后在編輯頁面從session中獲取當前需要編輯的書籍的信息並把這些信息顯示在前端的input框中。
(3)最后根據用戶輸入的數據保存書籍信息。
{% extends 'base.html' %}
{% block title %}
主頁
{% endblock title %}
{% block pannel-body %}
<div class="col-md-8 col-md-offset-2">
<h2 class="text-center">編輯書籍</h2>
<div>
<div class="form-group">
<label for="book_name">書籍名稱</label>
<input type="text" id="book_name" class="form-control" placeholder="書籍名稱"
autocomplete="off">
<span class="help-block"></span>
</div>
<div class="form-group">
<label for="price">價格</label>
<input type="number" id="price" class="form-control" placeholder="價格"
autocomplete="off">
<span class="help-block"></span>
</div>
<div class="form-group">
<label for="pub_date">出版日期</label>
<input type="date" id="pub_date" class="form-control" placeholder="出版日期">
<span class="help-block"></span>
</div>
<div class="form-group">
<label for="">出版社</label>
<select id="publish" class="form-control">
<option value="1">蘋果出版社</option>
<option value="2">西瓜出版社</option>
</select>
</div>
<div class="form-group">
<label for="">作者</label>
<select name="authors" id="authors" class="form-control" multiple>
<option value="1">whw</option>
<option value="2">naruto</option>
<option value="3">sasuke</option>
</select>
</div>
<div class="form-group">
<h4 id="add_error" class="pull-left" style="color:red;margin-top: 0"></h4>
<input id="confirm_add" type="button" class="btn btn-success pull-right" value="確認編輯">
</div>
</div>
</div>
{% endblock pannel-body %}
{% block script %}
<script>
// 頁面加載后將session中的數據寫到上面的標簽中
$(document).ready(function () {
// 獲取session中的數據
var data_session = sessionStorage['edit_book_data'];
// 記得反序列化一下
var data = JSON.parse(data_session);
console.log(data, typeof (data));
// 取出edit_book_id 把它設置為全局的變量!后面ajax提交的時候會用到
edit_book_id = data['id'];
// 將數據填在上面的input框中~注意是val方法!
$('#book_name').val(data['title']);
$('#price').val(data['price']);
$('#pub_date').val(data['pub_date']);
$('#publish').val(data['publish']['id']);
// 讓之前的作者名被選中
var arr_val = [];
for(var i in data['authors']){
//console.log(data['authors'][i]['id']);
arr_val.push(data['authors'][i]['id'])
}
// console.log(arr_val); [1,2]
// 把數組傳給復選框的val~讓之前的作者被選中
$('#authors').val(arr_val);
});
// 確認編輯按鈕
$('#confirm_add').click(function () {
var title = $('#book_name').val();
var price = $('#price').val();
var pub_date = $('#pub_date').val();
// 下拉列表被選中的這樣選取
var publish = $('#publish option:selected').val();
//ajax操作
$.ajax({
url: '/book/'+edit_book_id+'/',
type: 'put',
data: {
title: title,
price: price,
pub_date: pub_date,
//pub_date: "2019-08-02T09:35:13.064532Z",
post_publish: publish,
//post_authors: authors,
post_authors: $('#authors').val(),
},
// 傳數組~
traditional: true,
success: function (data) {
console.log(data);
//alert('添加成功!');
location.href = '{% url "book_list" %}';
}
})
});
</script>
{% endblock script %}
