功能演示

信息展示

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

添加功能

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

编辑功能

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

删除功能

基于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自带的页面)

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

相关文章:

  • 2022-02-20
  • 2022-12-23
  • 2021-10-08
  • 2021-06-17
  • 2022-01-01
  • 2021-04-04
  • 2022-12-23
猜你喜欢
  • 2022-12-23
  • 2021-08-09
  • 2022-12-23
  • 2022-01-27
  • 2021-10-30
  • 2021-09-20
  • 2021-07-07
相关资源
相似解决方案