Django-8:django模型层ORM-4

ORM-4

图书管理系统-小项目

准备工作如下:

一、创建并注册应用

创建应用

创建应用分为两种方式:cmd命令行创建pycharm控制台创建

1、cmd:

进入终端
WIN+R
切换mysite项目目录下
python manage.py startapp 应用名字
'''
示例:
'''
cd /d D:/djangoProject  #切换到项目目录下
python manage.py startapp  app_01   #在djangoProject项目中创建名为app_01的应用。

2、pycharm控制台:

右下角
选中Terminal
输入命令
pycharm
Run TODO Problems Terminal
进入控制台
python manage.py startapp app01

app01为创建的应用名

注册应用

新建的应用需要在django项目中注册,如下列创建名的mysite的django项目。

进入
配置文件添加应用
mysite
mysite文件夹
settings.py的INSTALLED_APPS列表
image-20210915235304649

格式:

  • INSTALLED_APPS = [
    	'''略'''
        'app_01'    # 直接应用名即可,上图为全称
    ]
    

二、配置数据库

默认的小型数据库不好用,而且还有bug,所以我们需要再配置文件中配置指定数据库以及在应用的init文件中声明更换了数据库

一、配置settings文件

  • DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.mysql', 
            'NAME': '库名',
            'USER':'该库有权限访问的用户名',
            'PASSWORD':'密码',
            'HOST':'数据库IP地址',
            'POST':3306,
            'CHARSET':'utf8',
        }
    }
    

二、配置应用的__init__.py文件。

  • '''
    __init__.py
    '''
    import pymysql
    pymysql.install_as_MySQLdb()
    

三、解决项目启动报错

新建的Django项目需要将改行进行修改,不然会报错。

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates')]

四、静态文件配置

首先要理解代码中不同static的含义,详情见文章:

STATIC_URL = '/static/'

STATICFILES_DIRS = [
    os.path.join(BASE_DIR,'static')
]

STATIC_URL内部的值,会影响到HTML文件引入的路径。

<link rel="stylesheet" href="/static/css/bootstrap.min.css">
<link rel="stylesheet" href="/static/js/bootstrap.js">
<link rel="stylesheet" href="/static/js/jquery-3.6.0.min.js">

正片

一、前端布局

通过BootStrap框架,可以快速搭建出前端HTMl页面

代码如下: (本章仅做布局,后续章节会对其进行修改

<!--bootstrap布局容器-->
<div class="container">

    <!--导航条-->
    <nav class="navbar navbar-default">
        <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="#">
              <img alt="Brand" src="https://ts1.cn.mm.bing.net/th/id/R-C.8b0be00c9babedefb2d4fe224aed645f?rik=ptgxzTtDF%2blz%2bA&riu=http%3a%2f%2fwww.kuaipng.com%2fUploads%2fpic%2fw%2f2019%2f04-30%2f65435%2fwater_65435_698_625.16_.png&ehk=lPA0nU%2b5gL4NqbxNrZu6aFMcQ7jUQ2qKmQu7MENISPE%3d&risl=&pid=ImgRaw&r=0" style="width: 34px;height: 30px;  position: absolute;top:12px">
             </a>
          <a class="navbar-brand" href="#" style="margin-left: 10px">图书管理系统</a>

        </div>

        <!-- Collect the nav links, forms, and other content for toggling -->
        <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
          <ul class="nav navbar-nav">
            <li class="active"><a href="#">首页<span class="sr-only">(current)</span></a></li>
            <li><a href="#">读友圈-分享好书</a></li>
            <li><a href="#">购物车</a></li>
            <li><a href="#">订单</a></li>
          </ul>

          <ul class="nav navbar-nav navbar-right">
            <li><a href="#"> <span>用户:</span> 刘煜</a></li>
            <li class="dropdown">
              <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">个人中心<span class="caret"></span></a>
              <ul class="dropdown-menu">
                <li><a href="#">我的学习</a></li>
                <li><a href="#">我的钱包</a></li>
                <li><a href="#">我的收藏</a></li>
                <li role="separator" class="divider"></li>
                <li><a href="#">我的读友圈</a></li>
              </ul>
            </li>
          </ul>
        </div><!-- /.navbar-collapse -->
      </div><!-- /.container-fluid -->
    </nav>
    <!--导航条-->


    <!--banner区域-->
    <div class="row">
        <!--左侧面板-->
        <div class="col-md-2">

            <div class="panel panel-primary">
                <div class="panel-body">
                    首页
                </div>
            </div>

            <div class="panel panel-success">
                <div class="panel-body">
                    书籍列表
                </div>
            </div>

            <div class="panel panel-info">
                <div class="panel-body">
                    出版社列表
                </div>
            </div>

            <div class="panel panel-warning">
                <div class="panel-body">
                    作者列表
                </div>
            </div>

        </div>
        <!--左侧面板-->

        <!--右侧面板-->
        <div class="col-md-10">
            <div class="panel panel-info">
              <div class="panel-heading">开启新世界</div>
              <div class="panel-body" >

                  <!--轮播图-->
                  <div id="carousel-example-generic" class="carousel slide" data-ride="carousel">
                      <!-- Indicators -->
                      <ol class="carousel-indicators">
                        <li data-target="#carousel-example-generic" data-slide-to="0" class="active"></li>
                        <li data-target="#carousel-example-generic" data-slide-to="1"></li>
                        <li data-target="#carousel-example-generic" data-slide-to="2"></li>
                        <li data-target="#carousel-example-generic" data-slide-to="3"></li>
                      </ol>

                      <!-- Wrapper for slides -->
                      <div class="carousel-inner" role="listbox">
                        <div class="item active">

                          <img src="https://img.alicdn.com/imgextra/i2/1946931453/O1CN01NduXUI1MbW1C5OBPI_!!0-item_pic.jpg_430x430q90.jpg" alt="..." style="width: 913px;height: 456.5px">
                          <div class="carousel-caption">
                            <!--图片居中底部的内容-->
                          </div>
                        </div>

                        <div class="item">
                          <img src="https://img-u-3.51miz.com/Templet/00/24/66/82/246682_2a1e5821f36ab2096e654bf2471fd38e.jpg" alt="...">
                          <div class="carousel-caption">
                            <!--图片居中底部的内容-->
                          </div>
                        </div>

                         <div class="item">
                              <img src="https://img.alicdn.com/imgextra/i2/1946931453/O1CN01x1hOYE1MbW2DJ3D4G_!!0-item_pic.jpg_430x430q90.jpg" alt="..." style="width: 913px;height: 456.5px">
                              <div class="carousel-caption">
                                <!--图片居中底部的内容-->
                              </div>
                         </div>


                        <div class="item">
                              <img src="https://img.alicdn.com/imgextra/i1/1946931453/O1CN01ixW2Dz1MbW1EaGNG8_!!0-item_pic.jpg_430x430q90.jpg" alt="..." style="width: 913px;height: 456.5px">
                              <div class="carousel-caption">
                                <!--图片居中底部的内容-->
                              </div>
                         </div>

                      </div>

                      <!-- Controls -->
                      <a class="left carousel-control" href="#carousel-example-generic" role="button" data-slide="prev">
                        <span class="glyphicon glyphicon-chevron-left iconfont icon-a-huaban1fuben44" aria-hidden="true"></span>
                        <span class="sr-only">Previous</span>
                      </a>
                      <a class="right carousel-control" href="#carousel-example-generic" role="button" data-slide="next">
                        <span class="glyphicon glyphicon-chevron-right iconfont icon-a-huaban1fuben45" aria-hidden="true"></span>
                        <span class="sr-only">Next</span>
                      </a>
                    </div>
                  <!--轮播图-->

              </div>
            </div>
        </div>
        <!--右侧面板-->

        <!--下方缩略图-->
        <div class="row">
           <div class="col-sm-6 col-md-4">
            <div class="thumbnail">
              <img src="https://tse1-mm.cn.bing.net/th/id/OIP-C.RXMO1h5jBwqGXr9oXCufZwHaHa?w=209&h=210&c=7&r=0&o=5&dpr=1.25&pid=1.7" alt="..." style="height: 360px">
              <div class="caption">
                <h3>《西游记》</h3>
                <p>全书主要描写了孙悟空出世及大闹天宫后,遇见了唐僧、猪八戒、沙僧和白龙马,西行取经,一路上历经艰险、降妖伏魔,经历了九九八十一难,终于到达西天见到如来佛祖,最终五圣成真的故事。该小说以“唐僧取经”这一历史事件为蓝本,通过作者的艺术加工,深刻地描绘了明代社会现实。</p>
                <p><a href="#" class="btn btn-primary" role="button">购买</a> <a href="#" class="btn btn-default" role="button">预览</a></p>
              </div>
            </div>
          </div>
              <div class="col-sm-6 col-md-4">
                <div class="thumbnail">
                  <img src="https://ts1.cn.mm.bing.net/th/id/R-C.201d44e44dc6479dd1f13053f72c3a19?rik=aoAlGzxJxgRbBg&riu=http%3a%2f%2fimage12.bookschina.com%2f2018%2f20180406%2f7392022.jpg&ehk=cHswL2kA0FiRoSOfgpMtNeiRa8lO%2bHL03pWNZrobiLw%3d&risl=&pid=ImgRaw&r=0" alt="...">
                  <div class="caption">
                    <h3>《水浒传》</h3>
                    <p>.全书通过描写梁山好汉反抗欺压、水泊梁山壮大和受宋朝招安,以及受招安后为宋朝征战,最终消亡的宏大故事,艺术地反映了中国历史上宋江起义从发生、发展直至失败的全过程,深刻揭示了起义的社会根源,满腔热情地歌颂了起义英雄的反抗斗争和他们的社会理想,也具体揭示了起义失败的内在历史原因。</p>
                    <p><a href="#" class="btn btn-primary" role="button">购买</a> <a href="#" class="btn btn-default" role="button">预览</a></p>
                  </div>
                </div>
              </div>
           <div class="col-sm-6 col-md-4">
            <div class="thumbnail">
              <img src="https://ts1.cn.mm.bing.net/th/id/R-C.9167560e27e377ddb04cd4ccd61e7973?rik=6Yq6QPSVwwhy8A&riu=http%3a%2f%2fimage12.bookschina.com%2f2018%2f20180731%2f2%2f6987838.jpg&ehk=wupKNKYpBYFA54qTwyYnWbBMlXxVA9fxTbQ1TzR4i3M%3d&risl=&pid=ImgRaw&r=0" alt="..." style="height: 360px">
              <div class="caption">
                <h3>《红楼梦》</h3>
                <p>小说以贾、史、王、薛四大家族的兴衰为背景,以富贵公子贾宝玉为视角,以贾宝玉与林黛玉、薛宝钗的爱情婚姻悲剧为主线,描绘了一批举止见识出于须眉之上的闺阁佳人的人生百态,展现了真正的人性美和悲剧美,可以说是一部从各个角度展现女性美以及中国古代社会世态百相的史诗性著作。</p>
                <p><a href="#" class="btn btn-primary" role="button">购买</a> <a href="#" class="btn btn-default" role="button">预览</a></p>
              </div>
            </div>
          </div>
       </div>
        <!--下方缩略图-->

    </div>
    <!--banner区域-->

</div>
<!--bootstrap布局容器-->

Django添加路由及视图

路由层

  • urlpatterns = [
    	。。。。。
        url(r'^index/',views.index),
    ]
    

视图层

  • def index(request):
        return render(request, 'index.html')
    

访问查看效果

image-20221002215018183

二、数据库构表并添加初始数据

models.py文件

class Book(models.Model):
    title = models.CharField(max_length=20,verbose_name='书籍名称')
    price = models.DecimalField(max_digits=8,decimal_places=3,verbose_name='价格')
    publication_time = models.DateField(auto_now_add=True,verbose_name='出版日期')

    bind_publish = models.ForeignKey(to='Publish')
    bind_authors = models.ManyToManyField(to='Author')


class Publish(models.Model):
    pub_name = models.CharField(max_length=32,verbose_name='出版社名称')
    pub_addr = models.CharField(max_length=32,verbose_name='出版社地址')



class Author(models.Model):
    author_name = models.CharField(max_length=16)
    bind_author_info = models.OneToOneField('Author_info')


class Author_info(models.Model):
    info = models.TextField()

test.py文件,用于添加数据,绑定外键关系

import os

if __name__ == "__main__":
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "django_demo.settings")
    import django
    django.setup()

    from app_01 import models

    models.Publish.objects.create(pub_name='《人民文学出版社》',pub_addr='北京市朝阳门内大街166号')
    models.Publish.objects.create(pub_name='《作家出版社》',pub_addr='北京市朝阳区农展馆南里10号')
    models.Publish.objects.create(pub_name='《北京图书馆出版社出版》',pub_addr='北京市西城区文津街7号')

    models.Author_info.objects.create(info='施耐庵(1296年—1370年),名耳,明代文学家。')
    models.Author_info.objects.create(info='罗贯中(约1330年-约1400年),太原人,号湖海散人,元末明初小说家。')
    models.Author_info.objects.create(info='曹雪芹(约1715年5月28日—约1763年2月12日),名霑,字梦阮,号雪芹,又号芹溪、芹圃,中国古典名著《红楼梦》的作者,')
    models.Author_info.objects.create(info='高鹗(1758年—约1815年),字云士,号秋甫,别号兰墅、行一、红楼外史。')
    models.Author_info.objects.create(info='吴承恩(约1500年—1582年),字汝忠,号射阳居士,又称射阳山人,南直隶淮安府山阳县河下(今江苏淮安)人,祖籍安东。明代文学家。')

    models.Author.objects.create(author_name='施耐庵',bind_author_info_id=1)
    models.Author.objects.create(author_name='罗贯中',bind_author_info_id=2)
    models.Author.objects.create(author_name='曹雪芹',bind_author_info_id=3)
    models.Author.objects.create(author_name='高鹗',bind_author_info_id=4)
    models.Author.objects.create(author_name='吴承恩',bind_author_info_id=5)


    models.Book.objects.create(title='《水浒传》', price=74.5, bind_publish_id=1)
    models.Book.objects.create(title='《红楼梦》', price=68.8, bind_publish_id=2)
    models.Book.objects.create(title='《西游记》', price=71.45, bind_publish_id=3)

    models.Book.objects.filter(pk=1).first().bind_authors.add(1, 2)
    models.Book.objects.filter(pk=2).first().bind_authors.add(3, 4)
    models.Book.objects.filter(pk=3).first().bind_authors.add(5)

三、书籍列表展示

需求:

  • 点击左侧书籍列表之后,右侧面板局部刷新。

涉及到的知识点

  • 前端的a标签可以利用到反向解析,这样更改路由不需要再对a表的href属性进行更改。
  • 因为需要局部刷新所以需要用到模板的继承
  • 书籍列表的数据展示,自然也少不了ORM的操作。

反向解析:

一、路由层配置别名

  • url(r'^booklist/',views.booklist,name='booklist_path'),
    

二、修改前端HTML代码,将写死的内容,替换成a标签,并在前端利用反向解析

  • 在HTML代码中,找到左侧面板区域的内容区域,随后将其替换成a标签

    image-20221002230800330
    <div class="panel panel-success">
        <div class="panel-body">
            <a href="{% url 'booklist_path' %}" style="text-decoration: none;color: black">书籍列表</a>
        </div>
    </div>
    

三、配置视图层,随后查看效果

def booklist(request):
    return HttpResponse('书籍列表')

'''
点击左侧书籍列表按钮,会访问该URL: http://localhost:8000/booklist/
	而这个URL会对应触发views.py中的代码,所以反向解析配置完成,接下来就是完善下模板的继承,以及视图层的代码。
'''

模板的继承

一、主页面划定区域

  • 既然要实现的效果是,点击左侧面板时,右侧面板局部刷新,那么就找到对应HTML文件中的部分,随后通过{% block 名称 %}的方式,对区域内代码进行“分区”并重命名。
image-20221004022059658

二、子页面继承主页面,并修改上自己自定义的页面内容

  • 红色方框内的代码为继承index主页面,绿色方框内代码表示,修改主页面划定区域内的代码。
image-20221004022457094

3.1 获取数据并渲染

本章节开头呢,回顾了反向解析以及模板继承,本章节开始,将介绍后端如何获取数据,并渲染在HTML页面上。

一、后端获取数据并返回给前端

def booklist(request):
    from app_01 import  models
    # 因为本章节案例是书籍相关,所以获取的就是书籍表的数据。
    book_queryset = models.Book.objects.all()

    return render(request,'booklist.html',locals())

二、利用前端模板语法,对将后端传过来的数据进行处理。

<table class="table-hover table table-striped table-bordered">
<thead>
    <tr>
        <th>书籍名称</th>
        <th>书籍售价</th>
        <th>作者</th>
        <th>出版社</th>
        <th>出版日期</th>
        <th>操作</th>
    </tr>
</thead>
<tbody>
    {% for foo in book_queryset %}
        <tr class="active">
            <td>{{ foo.title }}</td>
            <td>{{ foo.price }}</td>

            <td>   
                {% for author_obj in foo.bind_authors.all %}
                    {% if forloop.last %}
                        {{ author_obj.author_name }}
                    {% else %}
                        {{ author_obj.author_name }}{% endif %}
                {% endfor %}            
            </td>

            <td>{{ foo.bind_publish.pub_name }}</td>
            <td>{{ foo.publication_time | date:'Y-m-d'}}</td>
            <td>
                <a href=""><button class="btn btn-success btn-xs">编辑</button></a>
                <a href=""><button class="btn btn-danger btn-xs">删除</button></a>
            </td>
        </tr>
    {% endfor %}

</tbody>
</table>
  • 利用模板语法-标签也就是for循环,来实现将数据渲染到页面上。
  • 需要注意的是,模板语法会自动识别是否可以执行,如果可以执行自动执行,如需再加括号,比如foo.bind_authors.all。

详解:

<td>   
    {% for author_obj in foo.bind_authors.all %}
        {% if forloop.last %}
            {{ author_obj.author_name }}
        {% else %}
            {{ author_obj.author_name }}{% endif %}
    {% endfor %}            
</td>

(1)首先一本书对应的作者肯定是一个或多个,子查询不管是正向查询还是反向查询,只要返回数据不止一条,都需要加上all(),又因为这是模板语法,所以后面的括号省略掉了。

(2)forloop.last可以判断这是第几次循环,如果是最后一次,那么就不后跟 顿号。

<td>{{ foo.publication_time | date:'Y-m-d'}}</td>
  • 这里使用的是date过滤器,将事件对象转换成更为直观的数据,而不是 Oct. 2, 2022

效果展示:

image-20221005005623931

获取出版社列表和作者列表:

  • 略,实现思路与书籍列表一致。

3.2 新增图书

既然是新增图书,那么肯定先开设路由、书写视图函数、书写模板,随后利用反向解析配置好a标签的href属性即可。

详细的步骤就暂时省略,后面的代码不考虑什么优化,着重于实现效果,将前面文章的知识点串起来。

代码:

{% extends 'index.html' %}


{% block right_banner %}
<div class="col-md-10">
    <div class="panel panel-info">
      <div class="panel-heading">
          <span>
              <a href="{% url 'booklist_path' %}">返回图书列表</a>
          </span>

      </div>
      <div class="panel-body" style="position: relative">
          <form action="" method="post">
              <p><label for="">书籍名称:<input type="text" class="from form-control" placeholder="骆驼祥子" name="bookname"></label></p>
              <p><label for="">书籍售价:<input type="text" class="from form-control" placeholder="49.98" name="bookprice"></label></p>
              <p><label for="">书籍作者:<input type="text" class="from form-control" placeholder="老舍" name="bookauthors"></label></p>
              <p><label for="">出版社:
                  <select name="bookpublish" id=""  class="form-control">
                      {% for pub_obj in pulish_queryset %}
                        <option value="{{ pub_obj.pk }}">{{ pub_obj.pub_name }}</option>
                      {% endfor %}
                  </select>
              </label></p>
            
              <p><label for="">出版时间:<input type="date" class="from form-control" name="bookpubtime"></label></p>
              <button class="btn btn-success">提交</button>
          </form>
          <!--表单右侧的插图-->
          <div><img src="https://img-u-3.51miz.com/Templet/00/18/79/88/187988_8d6ffdb325894cb7aaded7ec4b26260b.jpg" alt="" style="position: absolute;top:0;right: 2px;width: 281px;"></div>
      </div>
    </div>
</div>
{% endblock %}
# views.py
def addbook(request):

    if request.method == 'POST':
        import re

        # 表单中输入书籍作者时,如果是多个作者,大家习惯是空格或者任意标点符号隔开
        # 这里的正则就是获取到每一段的名称,不受“隔断符”的影响。
        ipt_booklist_list = re.findall('[\w]+',request.POST.getlist('bookauthors')[0])
        print(ipt_booklist_list) # ['苏轼', '范仲淹']
        '''
        <QueryDict: {'bookname': ['test'], 'bookprice': ['19.90'], 'bookauthors': ['李时珍 孙思邈,张恒、司马光;司马迁'], 'bookpublish': ['人教出版社'], 'bookpubtime': ['2021-10-07']}>
        '''

        # 查询作者表中,是否存在表单提交的作者
        for authorname in ipt_booklist_list:
            res = models.Author.objects.filter(author_name=authorname)
            if res == False:
                # 如果没找到,可以给弹框,提示作者不存在请前往添加/取消,但是现在并未介绍ajax,所以此处直接return HttpResponse
                return HttpResponse('请检查作者名')


        # 当输入的用户名为在作者表中存在时,创建数据绑定关系,一对多 多对多
        bookname = request.POST.get('bookname')
        bookprice = request.POST.get('bookprice')
        bookpublish_id = request.POST.get('bookpublish')
        bookpubtime = request.POST.get('bookpubtime')

        newbook_obj = models.Book.objects.create(title=bookname,price=bookprice,publication_time=bookpubtime,bind_publish_id=bookpublish_id)

        #图书与作者进行绑定
        '''
        现在知道作者的姓名,但是建立绑定关系时,需要用到ID主键值
        所以需要通过姓名找主键。
        id_lis列表存放着,前端输入的作者对应在数据库中的主键值。
        '''
        id_lis = []
        for name in ipt_booklist_list:
            pk = models.Author.objects.filter(author_name=name).values('pk')
            id_lis.append(pk.first()['pk'])
        newbook_obj.bind_authors.add(*id_lis)
        return redirect('booklist_path')

    pulish_queryset = models.Publish.objects.all()
    return render(request,'addbook.html',locals())

实现思路

  • 依旧是通过反向解析来让前端的a标签,可以始终访问到页面,而不受路由路径规则的影响。

  • 前端渲染数据时,出版社表单采用select标签,可以通过滚动下拉框,选中已添加的出版社。

    作者表单考虑到作者那么多,如果还是挨个去选,不显示,所以采用了手动填写,只需要将每个名称之间隔开就好

    (正则书写有bug,当是用字母隔开时,就无法区分出多个作者,本章只为看效果,优化略)

  • 后端先对前端需要用到的数据进行查找,后续再对POST提交过来的数据进行简单的校验,随后利用ORM对数据进行新增,以及绑定关系。

3.3 删除图书

用到的知识点:

  • 删除图书首先要获取被删除图书的主键值,所以这里采用有名或无名分组,前端传入,随后路由层接收,视图层引用。

代码:

url(r'^delbook/(?P<del_id>\d+)/',views.delbook,name='delbook_path'),
<td>
	<a href=""><button class="btn btn-success btn-xs">编辑</button></a>
	<a href="{% url 'delbook_path' foo.pk %}"><button class="btn btn-danger btn-xs">删除</button></a>
</td>
  • 这里的foo为book_obj图书对象,在渲染数据的时候,就把每条数据的后面的删除按钮,与图书主键值进行“绑定”。
def delbook(request,del_id):
    models.Book.objects.filter(pk=del_id).delete()
    return redirect('booklist_path')

3.4 编辑图书

由于比较简单,所以就直接放源码了。另外:新增图书章节有明明不规范的问题,不过影响不大,能正常跑。

其实是懒得写了,捂脸.jpg

路由层

url(r'^editbook/(?P<edit_id>\d+)/',views.editbook,name='addbook_path'),

模板层

{% extends 'index.html' %}


{% block right_banner %}
<div class="col-md-10">
    <div class="panel panel-info">
      <div class="panel-heading">

          <span>
              <a href="{% url 'booklist_path' %}">返回图书列表</a>
          </span>

      </div>
      <div class="panel-body" style="position: relative">
          <form action="" method="post">
              <p><label for="">书籍名称:<input type="text" class="from form-control" value="{{ editbook_obj.title }}" name="bookname"></label></p>
              <p><label for="">书籍售价:<input type="text" class="from form-control" value="{{ editbook_obj.price }}" name="bookprice"></label></p>
              <p><label for="">书籍作者:<input type="text" class="from form-control" value="{{ book_author }}" name="bookauthors"></label></p>
              <p><label for="">出版社:
                  <select name="bookpublish" id=""  class="form-control" autocomplete="off">
                      {% for pub_obj in pulish_queryset %}
                          
                          {% if editbook_obj.bind_publish.pub_name == pub_obj.pub_name %}
                            <option value="{{ pub_obj.pk }}" selected>{{ pub_obj.pub_name }}</option>
                          {% else %}
                              <option value="{{ pub_obj.pk }}">{{ pub_obj.pub_name }}</option>
                          {% endif %} 

                      {% endfor %}
                  </select>
              </label></p>
              <p><label for="">出版时间:<input type="date" class="from form-control" name="bookpubtime" value="{{ editbook_obj.publication_time | date:'Y-m-d'}}"></label></p>
              <button class="btn btn-success">提交</button>
          </form>
          <!--表单右侧的插图-->
          <div><img src="https://img-u-3.51miz.com/Templet/00/18/79/88/187988_8d6ffdb325894cb7aaded7ec4b26260b.jpg" alt="" style="position: absolute;top:0;right: 2px;width: 281px;"></div>
      </div>
    </div>
</div>
{% endblock %}

视图层

def editbook(request,edit_id):
    # 先获取前端需要用到的数据
    pulish_queryset = models.Publish.objects.all()
    editbook_obj = models.Book.objects.filter(pk=edit_id).first()

	
    '''
    这里将作者数据渲染在表单中,由于作者可能有多个,所以这里是做了个拼接。
    '''
    # 子查询
    book_author=''
    for author_obj in editbook_obj.bind_authors.all():
        book_author += author_obj.author_name + '、'
    book_author = book_author[0:-1]

    # 也可以:连表查询
    # res = models.Book.objects.filter(pk=edit_id).values('bind_authors__author_name')
    # for i in res :
    #     print(i['bind_authors__author_name'])


    # 当在编辑界面提交之后,获取数据进行操作。
    if request.method == 'POST':
        import re

        # 获取前端表单输入的作者数据,并通过正则表达式进行简单拆解,将多个作者的分隔符拆开,返回值为列表
        ipt_book2author_list = re.findall('[\w]+',request.POST.getlist('bookauthors')[0])

        # 对获取到前端的作者名称进行比对,查看数据库中存不存在该作者。
        for authorname in ipt_book2author_list:
            res = models.Author.objects.filter(author_name=authorname)
            if res == False:
                # 由于本章节用于回顾之前知识点,并未介绍ajax等,所以此处就简单的返回个HttpResponse
                return HttpResponse('请检查作者名')

        # 获取输入的数据
        bookname = request.POST.get('bookname')
        bookprice = request.POST.get('bookprice')
        bookpublish_id = request.POST.get('bookpublish')
        bookpubtime = request.POST.get('bookpubtime')

        # print(bookname,bookprice,bookpublish_id,bookpubtime,ipt_book2author_list)
        # 《老人与海》 999 4 2022-10-01 ['刘煜', '夏阳凤']


        # 更新数据
        models.Book.objects.filter(pk=edit_id).update(title=bookname,price=bookprice,publication_time=bookpubtime,bind_publish_id=bookpublish_id)
        newbook_obj = models.Book.objects.filter(pk=edit_id).first()
        #图书与作者进行更改绑定(多对多关系)

        print('-----')
        update_authorsobj_lis = []
        for name in ipt_book2author_list:
            ipt_author_obj = models.Author.objects.filter(author_name=name).first()
            update_authorsobj_lis.append(ipt_author_obj)

        newbook_obj.bind_authors.set(update_authorsobj_lis)

        return redirect('booklist_path')

    return render(request,'editbook.html',locals())
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿煜yv

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值