功能演示

信息展示

添加功能

编辑功能

删除功能

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. pip 安装超时解决方案

    已经使用梯子,安装某依赖时仍然超时. 首先检查pip的版本是否需要更新,如果不是最新版本运行命令更新: python -m pip install --upgrade pip 如果仍然超时错误,则运行 ...

  2. 从零开始学MySQL(三)

    经过上两节的洗礼,我们能够连接上服务器,并成功地进入与mysql交互的会话中了.那么现在就可以发起SQL语句,让服务器来执行它了!这听起来很酷吧?接下来,我们开始学习MySQL的相关知识. 本文概览: ...

  3. linux命令详解——ln

    ln是linux中又一个非常重要命令,它的功能是为某一个文件在另外一个位置建立一个同不的链接,这个命令最常用的参数是-s,具体用法是:ln -s 源文件 目标文件. 当我们需要在不同的目录,用到相同的 ...

  4. Delphi 数据类型

  5. SpringBoot页面展示Thymeleaf

    https://www.jianshu.com/p/a842e5b5012e 开发传统Java WEB工程时,我们可以使用JSP页面模板语言,但是在SpringBoot中已经不推荐使用了.Spring ...

  6. Java并发编程实战 第10章 避免活跃性危险

    死锁 经典的死锁:哲学家进餐问题.5个哲学家 5个筷子 如果没有哲学家都占了一个筷子 互相等待筷子 陷入死锁 数据库设计系统中一般有死锁检测,通过在表示等待关系的有向图中搜索循环来实现. JVM没有死 ...

  7. 约会 Rendezvous:基环树

    提炼:tarjan判环,dfs建树,倍增lca,预处理环两点间距离 我犯的错误: 1.基环树不只有一棵,可以有很多 2.自环不能将其忽略,(对于我的算法)应该将其特殊考虑在算法内 3.代码一定要简洁有 ...

  8. ArrayList为什么是线程不安全的

    首先需要了解什么是线程安全:线程安全就是说多线程访问同一代码(对象.变量等),不会产生不确定的结果. 既然说ArrayList是线程不安全的,那么在多线程中操作一个ArrayList对象,则会出现不确 ...

  9. POJ-3020-Antena Placement(最小路径覆盖)

    链接: https://vjudge.net/problem/POJ-3020 题意: The Global Aerial Research Centre has been allotted the ...

  10. 解决jmeter 请求参数中文乱码

    今天在用jmeter 写脚本时发现查看结果树request post请求中文参数值是乱码,故记录下解决过程. 解决过程如下: 1.修改本地配置文件 因为此处的数据,还没有发送出去,所以,肯定是这个变量 ...