功能演示

信息展示

添加功能

编辑功能

删除功能

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>

base.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 %}

基于DRF的图书增删改查的更多相关文章

  1. 基于DRF的图书增删改查练习

    功能演示 信息展示 添加功能 编辑功能 删除功能 DRF构建后台数据 本例的Model如下 from django.db import models class Publish(models.Mode ...

  2. 基于pymysql模块的增删改查

    上课笔记 重点:(熟练)多表查询创建存储过程原生sql索引原理 pymysql 封装好的客户端cursor 底层就是一个send操作commit 告诉mysql真的要完成修改操作(不然修改不会生效)e ...

  3. django -- ORM实现图书增删改查

    表结构设计 上篇我们实现了出版社的增删改查,出版社数据表有两个字段id和name,那图书的表结构怎么设计呢?图书也要有一个主键id,还要有一个名称title,是哪个出版社的,要有个字段press和Pr ...

  4. Python Web实战:Python+Django+MySQL实现基于Web版的增删改查

    前言 本篇使用Python Web框架Django连接和操作MySQL数据库学生信息管理系统(SMS),主要包含对学生信息增删改查功能,旨在快速入门Python Web,少走弯路.效果演示在项目实战最 ...

  5. 基于springmvc的简单增删改查实现---中间使用到了bean validation

    package com.kite.controller; import java.util.HashMap; import java.util.Map; import javax.validation ...

  6. MVC3学习:基于ObjectContext的数据增删改查操作

    数据库里面的表格,映射为对应的实体类.实体类的编写,可以自己手动编写,也可以使用工具或插件自动生成.在MVC3里面,我们可以使用VS的POCO插件自动生成实体类.如下图: 关于POCO插件的安装与使用 ...

  7. 【项目笔记】完成一个基于SSM框架的增删改查的模块后总结的问题

    最近为了准备新工作重新摸出了SSM框架,同时从0学习了JQuery,终于用一周做完了一个包括增删改查的模块(主要是属性太多了,其中一个类50+,复制粘贴耗时). 从中特意记下了几个遇到的问题,总结一下 ...

  8. axios和drf结合的增删改查

    增删改查 查: 前端实例: mounted() { //获取所有数据 // var Base_url = 'http://paas.bktst.sh.sgcc.com.cn/t/files-check ...

  9. Django drf:序列化增删改查、局部与全局钩子源码流程、认证源码分析、执行流程

    一.序列化类的增.删.改.查 用drf的序列化组件   -定义一个类继承class BookSerializer(serializers.Serializer):   -写字段,如果不指定source ...

随机推荐

  1. Git 操作 GitHub

    Git安装 https://www.cnblogs.com/taopanfeng/p/11076702.html 设置用户名(设置一次 以后就不用再设置了) git config --global u ...

  2. Redis【3】其他部分~

    Java连接VMware的Redis:ping()返回PONG 要可以ping通VMware地址 端口号要正确.默认6379 VMware中的防火墙原因.需添加6379端口号的防火墙: vim /et ...

  3. 使用switchshow/supportshow命令确认Brocade交换机型号(转载)

    switchshow命令(或supportshow日志)中的switchType是以数字来代表不同的交换机型号,完整的对应表格如下: Switchtype EMC / Brocade名称 / 端口 / ...

  4. Transposed Convolution 反卷积

    Transposed convolutions也称作fractionally strided convolutions(本人比较喜欢这个称呼,比较直观),Upconvolution,deconvolu ...

  5. laravel 中数据库查询结果自动转数组

    今天在项目中再次碰见laravel中从数据库中查询到的结果是对象,用toArray也不好用,之前改过一次,印象中是在/confing/database.php,    'fetch' => PD ...

  6. SQLSERVER调用OPENROWSET的方法

    前言:正好这两天在同步生产环境的某张表数据到测试环境,之前用过一些同步数据软件,感觉不太可靠,有时候稍有操作不当,就会出现生产环境数据被清空等情况,还要去恢复数据.如果能恢复还好,不能恢复那么.... ...

  7. spring boot 2.0(三)使用docker部署springboot

    Docker 技术发展为微服务落地提供了更加便利的环境,使用 Docker 部署 Spring Boot 其实非常简单,这篇文章我们就来简单学习下. 首先构建一个简单的 Spring Boot 项目, ...

  8. 2019 第十届 SWPUCTF writeup(Pwn)

    p1KkHeap 0.环境 1.文件信息 2.文件开启的保护 3.IDA分析 main函数 add show edit delete delete功能出现了指针悬浮的问题,配合上tcache,可以任意 ...

  9. windows补丁服务器

    一.WSUS 安装要求 1.硬件要求: 对于多达 13000 个客户端的服务器,建议使用以下硬件:* 4 Core E5-2609 2.1GHz 的处理器* 8 GB 的 RAM 2.软件要求: 要使 ...

  10. 【shell】sed处理多行合并

    有这么一个题 文件格式 table=t1 name owner address table=t2 id text col1 comment col5 table=t3 prod_name price ...