基於DRF的圖書增刪改查

功能演示

信息展現

添加功能

編輯功能

刪除功能

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自帶的頁面)css

DRF自帶的頁面是這樣的:html

固然,咱們不能讓用戶看這樣的頁面,這就須要前端請求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'),

視圖函數以下

視圖函數很是簡單,再加上是進行數據測試,因此這裏的視圖函數只負責返回頁面。jquery

數據的操做所有是用ajax與js作的。git

# 展現 書籍列表
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請求。ajax

刪除書籍發送的是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請求。django

{% 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 %}

編輯書籍頁面

編輯書籍這裏須要說一下過程:json

(1)首先我在書籍展現那裏點擊「編輯」的時候,先把當前點擊的書籍的信息取出來,而後序列化,最後將序列化的數據存在session中。bootstrap

(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 %}
相關文章
相關標籤/搜索