内容回顾:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
补充反向解析
Html:{% url ‘别名’ 参数 %}
Views:reverse(‘别名’,args=(参数,))
模板渲染
变量 {{ 变量名 }}
逻辑相关 {% %}
过滤器:
{{ 变量|过滤器方法:’参数’ }}
标签:
{% for i in list%} for k,v in dict.items
{{ i }}
{% endfor %}
{% if 条件 %}
{%elif%}
{%else%}
{% endif %}
据点符 . 可以做深度查询
{% with 变量名=变量.属性.属性.. %}
{% with 变量.属性.属性.. as 变量名%}
{% endwith %}
母板继承
先写一个母板,大家共用的地方
母板预留钩子:
{% block ‘名字’ %}
母板里面的可以被替换的内容
{%Endblock 名字%}
再写子页面
子页面里面第一行 {% extends ‘母板名称’ %}
{% block ‘名字’ %}
{{ block.super }}
子页面的内容
{%Endblock 名字%}
Csrf_token :
{% csrf_token %}
1.模板渲染组件
可以将常用的页面内容如导航条,页尾信息等组件保存在单独的文件中,然后在需要使用的地方,文件的任意位置按如下语法导入即可。
{% include 'navbar.html' %}
例如:有个如下的导航栏,nav.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> .c1{ background-color: red; height: 40px; } </style> </head> <body> <div class="c1"> <div> <a href="">xx</a> <a href="">dd</a> </div> </div> </body> </html>
嵌入导航栏的页面,test.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> {% include 'nav.html' %} <h1>xxxxxxxxxx</h1> </body> </html>
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ # url(r'^admin/', admin.site.urls), url(r'^index/', views.index), url(r'^user/', views.user), url(r'^order/', views.order), url(r'^zujian/', views.zujian), ]
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
from django.shortcuts import render # Create your views here. def index(request): return render(request,'index.html') def user(request): return render(request,'usercenter.html') def order(request): return render(request,'order.html') def zujian(request): return render(request,'xiaomi.html')
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta http-equiv="content-Type" charset="UTF-8"> <meta http-equiv="x-ua-compatible" content="IE=edge"> <meta name="viewport" content="width=device-width" ,initial-scale="1"> <!--上边这个表示手机版的调整尺寸--> <!--上述2个meta标签"必须"放在最前面,任何其他内容都必须跟随其后--> <title>Title</title> </head> <body> {% include 'zujian.html' %} <ul> <li>1</li> <li>2</li> <li>3</li> <li>4</li> </ul> </body> </html>
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> .c1{ background-color: red; height: 40px; } </style> </head> <body> <div class="c1"> <div> <a href="">xx</a> <a href="">dd</a> </div> </div> </body> </html>
根据位置进行引入.
2.CBV和FBV=>dispatch方法
开发的两种模式:
FBV:(function base views)就是在视图里使用函数处理请求
CBV:(class base views) 就是在视图里使用类处理请求
Python是一个面向对象的编程语言,如果只用函数来开发,有很多面向对象的优点就错失了(继承、封装、多态)。所以Django在后来加入了Class-Based-View。可以让我们用类写View。这样做的优点主要下面两种:
- 提高了代码的复用性,可以使用面向对象的技术,比如Mixin(多继承)
- 可以用不同的函数针对不同的HTTP方法处理,而不是通过很多if判断,提高代码可读性
平时我们写的是FBV,下面我们说一下基于类的视图
首先导入模块,才能让django找到对应的方法:
CBV模式的url写法:
运行,得到结果:
刷新,拿到表单
输入用户名,提交
应该在form表单输入:
{% csrf_token %}
再次提交得到如上结果,这就是cbv,可拓展性强,fbv写起来更简单一些,
get和post接收的参数,要进行对应.
注意:urls.py里边有name
view.py必须有name属性
FBV版的装饰器
def wrapper(func): def inner(*args, **kwargs): start_time = time.time() ret = func(*args, **kwargs) end_time = time.time() print("used:", end_time-start_time) return ret return inner # FBV版添加班级 @wrapper def add_class(request): if request.method == "POST": class_name = request.POST.get("class_name") models.Classes.objects.create(name=class_name) return redirect("/class_list/") return render(request, "add_class.html")
装饰器表达
装饰器的本质:一个闭包函数
装饰器的功能:在不修改原函数及其调用方式的情况下对原函数功能进行扩展
CBV版的装饰器
from django.views import View from django.utils.decorators import method_decorator class AddClass(View): @method_decorator(wrapper) def get(self, request): return render(request, "add_class.html") def post(self, request): class_name = request.POST.get("class_name") models.Classes.objects.create(name=class_name) return redirect("/class_list/")
扩展:
# 使用CBV时要注意,请求过来后会先执行dispatch()这个方法,如果需要批量对具体的请求处理方法,
如get,post等做一些操作的时候,
这里我们可以手动改写dispatch方法,这个dispatch方法就和在FBV上加装饰器的效果一样。 class Login(View): def dispatch(self, request, *args, **kwargs): print('before') obj = super(Login,self).dispatch(request, *args, **kwargs) print('after') return obj def get(self,request): return render(request,'login.html') def post(self,request): print(request.POST.get('user')) return HttpResponse('Login.post')
3.input标签值补充
从数据库调用各种参数,进行页面的处理,怎样通过django处理数据库
最终得到的结果是,用户输入的名字
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta http-equiv="content-Type" charset="UTF-8"> <meta http-equiv="x-ua-compatible" content="IE=edge"> <meta name="viewport" content="width=device-width" ,initial-scale="1"> <!--上边这个表示手机版的调整尺寸--> <!--上述2个meta标签"必须"放在最前面,任何其他内容都必须跟随其后--> <title>Title</title> </head> <body> <form action="/zujian/" method="post"> {% csrf_token %} 用户名: <input type="text" name="username" value="xxx"> <input type="submit"> </form> <ul> <li>1</li> <li>2</li> <li>3</li> <li>4</li> </ul> {% include 'zujian.html' %} </body> </html>
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
"""day53_moban URL Configuration The `urlpatterns` list routes URLs to views. For more information please see: https://docs.djangoproject.com/en/1.11/topics/http/urls/ Examples: Function views 1. Add an import: from my_app import views 2. Add a URL to urlpatterns: url(r'^$', views.home, name='home') Class-based views 1. Add an import: from other_app.views import Home 2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home') Including another URLconf 1. Import the include() function: from django.conf.urls import url, include 2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls')) """ from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ # url(r'^admin/', admin.site.urls), url(r'^index/', views.index), url(r'^user/', views.user), url(r'^order/', views.order), url(r'^zujian/', views.zujian), #CBV模式的url写法 url(r'^cbv/', views.MyView.as_view(name='sss')), ]
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
from django.shortcuts import render,HttpResponse from django.views import View # Create your views here. def index(request): return render(request,'index.html') def user(request): return render(request,'usercenter.html') def order(request): return render(request,'order.html') def zujian(request): if request.method=='POST': uname=request.POST.get('username') print(uname) return HttpResponse('OK') return render(request,'xiaomi.html') class MyView(View): name='xxx' def get(self,request): return render(request,'xiaomi.html') def post(self,request): return HttpResponse('hello')
4.ORM创建表
ORM 对象关系映射
怎样通过数据库调用各种参数?
之前操作数据库的三种方式:pymysql,cmd,Navicat
学完orm,原生sql几乎就不写了
类对应数据库中的表, (类====>表)
类实例化一个对象,我们就得到一条记录 (类对象===>记录)
类中的属性,对应mysql中的字段, (类属性====>字段)
数据库的变更,只需要简单修改一些配置引擎就可以进行迁移了.
类.属性名,我们就拿到了属性对应的值.
orm就像一个引擎一样,
sqlachemy开源(功能稍弱),orm没有开源(功能更强大一些),
新创建一个项目,开始测试功能!!!
原来app中的models.py需要连接pymysql进行写语句进行测试.
磁盘是存储数据的,pymysql写完数据,存到磁盘,
orm把类对象转化成sql语句,存储到磁盘,再拿到orm上.
django不要深抠,关注实现功能就可以了,会用,用熟练就行
继承,类是创建表,属性表示字段
第一张表
from django.db import models # Create your models here. class Book(models.Model): id=models.AutoField(primary_key=True) #主键自增字段 title=models.CharField(max_length=32) #书名,字符串,后边必须写长度 price=models.DecimalField(max_digits=16,decimal_places=2) #mysql中有float,double,decimal(单双精度,精准) #float(12,6) ,总长度是12,其中6位是小数长度 #面试会用到mysql,还是需要复习的!!!!! pub_time=models.DateField() #出版日期 publish=models.CharField(max_length=20) #出版社 # id=models.PrimaryFied() #主键字段,但是没有自增,现在去掉了
在下面的,输入命令,(python manage.py makemigrations)
结果:
项目中多了红框中的内容.
这就是一个记录,记录了修改了什么!!!
执行命令:(python manage.py migrate)
db.sqlite3,是嵌套在django里边的数据库,操作简单,默认是这个,
观察pycharm右侧是否有下图:
,如果没有,我们点击View里边的Tool Buttons按钮,就可以显示了.
右侧的Database,,出现下图
将左侧框里边的 db.sqlite3,左键拉到上图的框中,得到如下图
这是因为第一次,需要下载,其他的数据库也是一样
先点击下载,(下载的位置变成下图的样子)
然后apply(应用),最后选择OK
下边里面是django自带的内容
输入完两条指令,python会在settings.py里边,找到下图:installed_apps里边的东西
上图里边的最后一条,注册了app01,因为添加了app01
执行两条指令的时候,python会扫描这些被安装的应用,上边几个都是自带的应用,而最后一个是自己安装的应用,每个自己安装的应用,都需要自己进行配置一下.这是自己创建了,通过扫描app01里边的models.py
其实在apps.py里边就有这个配置
也可以写成下面这种,也就是说,写上下两种都可以
需求:现在我们再创建一个app,进行相关的操作练习一下.
创建app的命令是=>(django-admin startapp app02)
写下面的程序,现在数据库已经发生了更改.
无论在数据库中的那张表中数据库做了修改,都需要重新执行这两条指令:
python manage.py makemigrations
python manage.py migrate
记住这样就可以了
我们看到了,这个结果没有发生变化.
这时候,我们进行下面的操作:(将app02放在下面的settings.py文件里边)
这时候,我们再执行刚才的两条命令
在app02下多了migrations文件,也就是执行的记录
点击刷新前:
点击刷新后:(多了一张食物表)
双击表,我们可以看到对应的结构:
注意,这是pycharm帮助提供的,不是django帮助提供的东西
每张表,必须有一个自增字段,也就是如上图显示的一样,如果我们创建的时候不写,内部会给我们提供一个
注意,通过类创建表,类名和数据库生成的表名的区别
Book类名对应app01_book表名
Food类名对应app02_food表名
以上全是sqllite3里边的一些配置和操作.
下面我们进行mysql的一些操作.
在settings.py里边默认写的是sqlite3:
现在不用了,先断开,点击红色按钮,再移除这个db数据库即可
这时候,数据的记录是不需要了,删除就可以了,留着可能会有一些其他的问题,将红框内的删除.
配置mysql文件
首先,修改配置文件settings.py的配置
创建orm1的库.
我们发现多了一个库
这时候,我们再修改配置文件
将刚刚创建好的orm1配置上.
这时候,我们发现没有,mysqldb模块
5.pycharm连接mysql
默认用的是mysqldb这个模块,进行了连接的,用到这个地方,安装也没有用,这个模块只支持到python3.4,我们该如何处理?
我们通过pymysql连接数据库即可,也是这样操作的,如何配置呢?
在项目文件中找到__init__py.
,这时候,再运行,那两条命令.
第一条命令表示创建记录,第二条命令表示创建表
运行完成也就,创建成功了.
这时候,我们再在CMD窗口里边,展示所有的表.如上图,可以看到已经创建成功了.
这时候查表,我们可以看到查出的结果是空的,注意这里的表名是app01_book
这是django做的优化机制.并且全部是小写,必须记住这些东西.
只要一加载这个项目,就会执行这个文件.,所以放到了这个项目的__init__.py的文件下.
此时,我们也就将表创建成功了.
这时候,我们可以用pycharm给我们提供的Navicat功能界面,操作和连接sqlite3数据库一样
依次找到,这些步骤操作.,点击进入,看下有没有下载,没有下载下来,要先下载下来.
ok之后,弹出下图:
右侧,得到结果.
注意,这时候,是两个客户端,一个是django提供的,一个是pycharm提供的.
6.图书管理系统增加和查询
(1)更多字段和参数
每个字段有一些特有的参数,例如,CharField需要max_length参数来指定VARCHAR
数据库字段的大小。还有一些适用于所有字段的通用参数。 这些参数在文档中有详细定义,这里我们只简单介绍一些最常用的:
更多字段:
<1> CharField 字符串字段, 用于较短的字符串. CharField 要求必须有一个参数 maxlength, 用于从数据库层和Django校验层限制该字段所允许的最大字符数. <2> IntegerField #用于保存一个整数. <3> FloatField 一个浮点数. 必须 提供两个参数: 参数 描述 max_digits 总位数(不包括小数点和符号) decimal_places 小数位数 举例来说, 要保存最大值为 999 (小数点后保存2位),你要这样定义字段: models.FloatField(..., max_digits=5, decimal_places=2) 要保存最大值一百万(小数点后保存10位)的话,你要这样定义: models.FloatField(..., max_digits=17, decimal_places=10) #max_digits大于等于17就能存储百万以上的数了 admin 用一个文本框(<input type="text">)表示该字段保存的数据. <4> AutoField 一个 IntegerField, 添加记录时它会自动增长. 你通常不需要直接使用这个字段; 自定义一个主键:my_id=models.AutoField(primary_key=True) 如果你不指定主键的话,系统会自动添加一个主键字段到你的 model. <5> BooleanField A true/false field. admin 用 checkbox 来表示此类字段. <6> TextField 一个容量很大的文本字段. admin 用一个 <textarea> (文本区域)表示该字段数据.(一个多行编辑框). <7> EmailField 一个带有检查Email合法性的 CharField,不接受 maxlength 参数. <8> DateField 一个日期字段. 共有下列额外的可选参数: Argument 描述 auto_now 当对象被保存时,自动将该字段的值设置为当前时间.通常用于表示 "last-modified" 时间戳. auto_now_add 当对象首次被创建时,自动将该字段的值设置为当前时间.通常用于表示对象创建时间. (仅仅在admin中有意义...) <9> DateTimeField 一个日期时间字段. 类似 DateField 支持同样的附加选项. <10> ImageField 类似 FileField, 不过要校验上传对象是否是一个合法图片.#它有两个可选参数:height_field和width_field, 如果提供这两个参数,则图片将按提供的高度和宽度规格保存. <11> FileField 一个文件上传字段. 要求一个必须有的参数: upload_to, 一个用于保存上载文件的本地文件系统路径. 这个路径必须包含 strftime #formatting, 该格式将被上载文件的 date/time 替换(so that uploaded files don't fill up the given directory). admin 用一个<input type="file">部件表示该字段保存的数据(一个文件上传部件) . 注意:在一个 model 中使用 FileField 或 ImageField 需要以下步骤: (1)在你的 settings 文件中, 定义一个完整路径给 MEDIA_ROOT 以便让 Django在此处保存上传文件. (出于性能考虑,这些文件并不保存到数据库.) 定义MEDIA_URL 作为该目录的公共 URL. 要确保该目录对 WEB服务器用户帐号是可写的. (2) 在你的 model 中添加 FileField 或 ImageField, 并确保定义了 upload_to 选项,以告诉 Django 使用 MEDIA_ROOT 的哪个子目录保存上传文件.你的数据库中要保存的只是文件的路径(相对于 MEDIA_ROOT). 出于习惯你一定很想使用 Django 提供的 get_<#fieldname>_url 函数.举例来说,如果你的 ImageField 叫作 mug_shot, 你就可以在模板中以 {{ object.#get_mug_shot_url }} 这样的方式得到图像的绝对路径. <12> URLField 用于保存 URL. 若 verify_exists 参数为 True (默认), 给定的 URL 会预先检查是否存在( 即URL是否被有效装入且 没有返回404响应). admin 用一个 <input type="text"> 文本框表示该字段保存的数据(一个单行编辑框) <13> NullBooleanField 类似 BooleanField, 不过允许 NULL 作为其中一个选项. 推荐使用这个字段而不要用 BooleanField 加 null=True 选项 admin 用一个选择框 <select> (三个可选择的值: "Unknown", "Yes" 和 "No" ) 来表示这种字段数据. <14> SlugField "Slug" 是一个报纸术语. slug 是某个东西的小小标记(短签), 只包含字母,数字,下划线和连字符.#它们通常用于URLs 若你使用 Django 开发版本,你可以指定 maxlength. 若 maxlength 未指定, Django 会使用默认长度: 50. #在 以前的 Django 版本,没有任何办法改变50 这个长度. 这暗示了 db_index=True. 它接受一个额外的参数: prepopulate_from, which is a list of fields from which to auto-#populate the slug, via JavaScript,in the object's admin form: models.SlugField (prepopulate_from=("pre_name", "name"))prepopulate_from 不接受 DateTimeFields. <13> XMLField 一个校验值是否为合法XML的 TextField,必须提供参数: schema_path, 它是一个用来校验文本的 RelaxNG schema #的文件系统路径. <14> FilePathField 可选项目为某个特定目录下的文件名. 支持三个特殊的参数, 其中第一个是必须提供的. 参数 描述 path 必需参数. 一个目录的绝对文件系统路径. FilePathField 据此得到可选项目. Example: "/home/images". match 可选参数. 一个正则表达式, 作为一个字符串, FilePathField 将使用它过滤文件名. 注意这个正则表达式只会应用到 base filename 而不是 路径全名. Example: "foo.*.txt^", 将匹配文件 foo23.txt 却不匹配 bar.txt 或 foo23.gif. recursive可选参数.要么 True 要么 False. 默认值是 False. 是否包括 path 下面的全部子目录. 这三个参数可以同时使用. match 仅应用于 base filename, 而不是路径全名. 那么,这个例子: FilePathField(path="/home/images", match="foo.*", recursive=True) ...会匹配 /home/images/foo.gif 而不匹配 /home/images/foo/bar.gif <15> IPAddressField 一个字符串形式的 IP 地址, (i.e. "24.124.1.30"). <16> CommaSeparatedIntegerField 用于存放逗号分隔的整数值. 类似 CharField, 必须要有maxlength参数.
具体用到再细说,
更多参数:
(1)null 如果为True,Django 将用NULL 来在数据库中存储空值。 默认值是 False. (1)blank 如果为True,该字段允许不填。默认为False。 要注意,这与 null 不同。null纯粹是数据库范畴的,而 blank 是数据验证范畴的。 如果一个字段的blank=True,表单的验证将允许该字段是空值。如果字段的blank=False,该字段就是必填的。 (2)default 字段的默认值。可以是一个值或者可调用对象。如果可调用 ,每有新对象被创建它都会被调用,如果你的字段没有设置可以为空,那么将来如果我们后添加一个字段,这个字段就要给一个default值 (3)primary_key 如果为True,那么这个字段就是模型的主键。如果你没有指定任何一个字段的primary_key=True, Django 就会自动添加一个IntegerField字段做为主键,所以除非你想覆盖默认的主键行为, 否则没必要设置任何一个字段的primary_key=True。 (4)unique 如果该值设置为 True, 这个数据字段的值在整张表中必须是唯一的 (5)choices 由二元组组成的一个可迭代对象(例如,列表或元组),用来给字段提供选择项。 如果设置了choices ,默认的表单将是一个选择框而不是标准的文本框,<br>而且这个选择框的选项就是choices 中的选项。 (6)db_index 如果db_index=True 则代表着为此字段设置数据库索引。 DatetimeField、DateField、TimeField这个三个时间字段,都可以设置如下属性。 (7)auto_now_add 配置auto_now_add=True,创建数据记录的时候会把当前时间添加到数据库。 (8)auto_now 配置上auto_now=True,每次更新数据记录的时候会更新该字段,标识这条记录最后一次的修改时间。
怎样添加记录?
写一个页面,写一个函数,将后端mysql数据库所有数据读取出来,放到前端页面展示
写一条数据到app01_book表中
注意,左边这个才是保存按钮.
首先是查:
urls.py写法
先写一个展示数据的页面,book_list.html,目前什么都没有写
运行,我们看一下all_books打印的是什么!!!
all_books=models.Book.objects.all() #拿到所有对象
QuerySet类型是一种新的数据类型,ORM提供的一种新的数据类型.里边放的是一个个类的对象,每个对象对应一条记录
QuerySet类型操作和列表的操作是一样的,
all_books=models.Book.objects.all()[0] #拿到第一个对象
all_books=models.Book.objects.all()[0].title #拿到第一个对象的名字
修改如上如,我们在运行,查看
在浏览器中输入(http://127.0.0.1:8000/book_list/)
服务端可以得到结果如下:
修改成第二条记录:
运行:
浏览器中输入地址(http://127.0.0.1:8000/book_list/)
服务端得到如下
修改:
这时候,我们再写,book_list是怎样展示的,也就是写book_list.html文件
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta http-equiv="content-Type" charset="UTF-8"> <meta http-equiv="x-ua-compatible" content="IE=edge"> <meta name="viewport" content="width=device-width" ,initial-scale="1"> <!--上边这个表示手机版的调整尺寸--> <!--上述2个meta标签"必须"放在最前面,任何其他内容都必须跟随其后--> <title>Title</title> </head> <body> <table> <thead> <tr> <th>id</th> <th>书名</th> <th>价钱</th> <th>出版时间</th> <th>出版社</th> </tr> </thead> <tbody> {% for one_book in all_books %} <tr> <td>{{ one_book.id }}</td> <td>{{ one_book.title }}</td> <td>{{ one_book.price }}</td> <td>{{ one_book.pub_time }}</td> <td>{{ one_book.publish }}</td> </tr> {% endfor %} </tbody> </table> </body> </html>
运行,输入地址,我们拿到如下界面
为了让界面好看一些,我们配置动态文件,cdn,也就是网络版的bootstrap,如下图内,红框内的地址.
添加的cdn文件
运行:
我们再在table里边添加属性:class="table"
运行:得到如下结果:
运用栅格系统,居中,自己占6份,移动3份
具体代码:
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta http-equiv="content-Type" charset="UTF-8"> <meta http-equiv="x-ua-compatible" content="IE=edge"> <meta name="viewport" content="width=device-width" ,initial-scale="1"> <!--上边这个表示手机版的调整尺寸--> <!--上述2个meta标签"必须"放在最前面,任何其他内容都必须跟随其后--> <title>Title</title> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"> </head> <body> <div class="container"> <div class="row"> <div class="col-md-6 col-md-offset-3"> {#表开始#} <table class="table"> <thead> <tr> <th>id</th> <th>书名</th> <th>价钱</th> <th>出版时间</th> <th>出版社</th> </tr> </thead> <tbody> {% for one_book in all_books %} <tr> <td>{{ one_book.id }}</td> <td>{{ one_book.title }}</td> <td>{{ one_book.price }}</td> <td>{{ one_book.pub_time }}</td> <td>{{ one_book.publish }}</td> </tr> {% endfor %} </tbody> </table> {#表结束#} </div> </div> </div> </body> </html>
运行:结果
向下移动100px
加上外边框:
得到结果:
再写一个添加书的功能
运行,输入地址,提交
双击右边的书籍表,得到这样的图表,有时候需要刷新一下
运行:
反应慢,需要刷新一下.
添加完成之后,应该做什么?应该显示添加之后的结果
这样写,就将路径写死了,
应该先起好别名
通过别名进行反向解析,
其实不用 reverse也是可以的,
在views.py导入模块
from django.urls import reverse
访问地址:得到结果如下.
如何通过按钮实现"添加",删除功能?还有,上边显示的出版日期不认识,怎么办?
通过过滤器实现:(在book_list.html中修改)
得到如下结果:
"点击"添加数据,我们可以跳转到新的页面进行添加操作?
新建一个"add_book.html"页面.
在通过解析,将点击之后,地址反向到"添加书籍"上
运行,点击添加书籍
跳转到,
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta http-equiv="content-Type" charset="UTF-8"> <meta http-equiv="x-ua-compatible" content="IE=edge"> <meta name="viewport" content="width=device-width" ,initial-scale="1"> <!--上边这个表示手机版的调整尺寸--> <!--上述2个meta标签"必须"放在最前面,任何其他内容都必须跟随其后--> <title>Title</title> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"> </head> <body> <div class="container"> <div class="row"> <div class="col-md-6 col-md-offset-3"> {#表单开始#} <form class="form-horizontal" action="{% url 'add_book' %}" method="post"> {#action 属性规定当提交表单时,向何处发送表单数据。#} {% csrf_token %} {#安全认证#} <div class="form-group"> <label for="book_name" class="col-sm-2 control-label">书名</label> <div class="col-sm-10"> <input type="text" class="form-control" id="book_name" placeholder="书名" name="book_name"> </div> </div> <div class="form-group"> <label for="book_price" class="col-sm-2 control-label">价格</label> <div class="col-sm-10"> <input type="text" class="form-control" id="book_price" placeholder="价格" name="book_price"> </div> </div> <div class="form-group"> <label for="book_time" class="col-sm-2 control-label">出版时间</label> <div class="col-sm-10"> <input type="text" class="form-control" id="book_time" placeholder="出版时间" name="book_time"> </div> </div> <div class="form-group"> <label for="book_publish" class="col-sm-2 control-label">出版社</label> <div class="col-sm-10"> <input type="text" class="form-control" id="book_publish" placeholder="出版社" name="book_publish"> </div> </div> <div class="form-group"> <div class="col-sm-offset-2 col-sm-10"> <input type="submit" value="保存" class="btn btn-default"> </div> </div> </form> {#表单结束#} </div> </div> </div> </body> </html>
刷新页面:
添加下面的代码:(向下移动了100px)
将保存放在右侧,颜色改成绿色
出版时间,里边的input标签的type属性改成从text改成date
现在的需求是,点击'保存',将数据发送到book_list.html页面和数据库中.
点击"保存"之后,返回页面
结果:成功添加进去了.
服务端得到的结果:
另一种创建方式,得到另一条记录
浏览器得到的结果:
保存
服务端得到的结果:
记录返回的结果应该是,添加完成之后的列表,所以,我们需要进行,修改返回返回的页面
展示页面:
点击保存:
重点::添加数据的语句,查找数据的语句
还有删改
刷新页面:
两个button中间加个空格
设置垂直居中,
实现了居中的效果:
!important 的使用。
!important:设置权重为无限大
!important 不影响继承来的权重,只影响选中的元素。不要随便使用!important,因为使用它会影响页面的布局
7.图书管理系统删除和更改操作的ORM演示
打印日志的配置文件,在settings里边放进去:
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'console':{
'level':'DEBUG',
'class':'logging.StreamHandler',
},
},
'loggers': {
'django.db.backends': {
'handlers': ['console'],
'propagate': True,
'level':'DEBUG',
},
}
}
重启项目,就可以看到一些语句了
运行:
服务端什么结果都没有.
修改
运行:
这个服务器端应该显示一条记录,但是结果是空的.
运行:
显示出4条结果
思考如何让上边类的对象显示出来?
获得对象的地址
如何显示字符串的内容?
在models里自定义一个str,不需要重启数据库,只需要重新运行项目即可
再运行项目,得到结果
filter里边的条件暂且用不了or
全部删除,出版社是"18期出版社"的,数据,展示的应该是空
运行,
展示的是4本,这样的书,
书籍列表里边也没有书了,也就是没有"18期出版社"的书籍了
运行:
点击'刷新',得到下面的结果:
再看book_list,多了下面的数据.
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
今日内容 1.模板渲染中的组件:{% include ‘xx.html’ %} 2.CBV通过类的方式来写视图 from django.views import View class My(View): def get(self,request): #获取get请求的 self.xxx() pass def post(): pass def xxx(): pass #其他请求方法 #如何找到这个类? Url(r‘^index/’,views.My.as_view()) FBV这是通过函数的形式来写视图 函数装饰器: def wrapper(fn): def inner(*args,**kwargs): print(‘Before’) ret=fn(*args,**kwargs) print(‘after’) return ret return inner Cbv装饰器 from django.views import View from django.utils.decorators import method_decorator @method_decorator(wrapper,name=’get’) class My(View): @method_decorator(wrapper) def get(self,request): self.xxx() pass def post() pass def xxx() pass url(r‘^index/’,views.My.as_view()) ORM 对象关系映射 类 ----- 表 类对象--- 记录 类属性--- 字段 应用里面的models文件里面写类 class Book(models.Model): id = models.AutoField(primary_key=True) title = models.CharField(max_length=32,unique=True) price = models.DecimalField(max_digits=16,decimal_places=2) pub_time = models.DateField() publish = models.CharField(max_length=20) def __str__(self): return self.title 连接mysql 1 mysql里面创建一个库 2 配置mysql的链接(引擎) Settings :database DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME':'bms', # 要连接的数据库,连接前需要创建好 'USER':'root', # 连接数据库的用户名 'PASSWORD':'', # 连接数据库的密码 'HOST':'127.0.0.1', # 连接主机,默认本级 'PORT':3306 # 端口 默认3306 } } 项目那个包里面的init文件里面写上: import pymysql pymysql.install_as_MySQLdb() 如果先添加了app应用的话,别忘了在settings配置文件里面的installapp那个列表里面注册上你的app 引入app INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'app01.apps.App01Config', 方式1 'app02', 方式2 ] 生成到MySQL数据库里面 Python manage.py makemigrations Python manage.py migrate 增: 方式1 :book_obj = models.Book(title=’xx’,pub=’xx’) book_obj.save() 方式2:models.Book.objects.create(title=’xx’,pub=’xx’) 删: models.Book.objects.filter(title=’冬瓜’,id=2).delete() 改: models.Book.objects.filter(title=’冬瓜’,id=2).update(title=’冬瓜’) 查: 查询所有的:models.Book.objects.all() 查询筛选的:models.Book.objects.filter(title=’冬瓜’,id=2) and多添加查询 上边两个都是querset类型
对上边的问题,进一步调试:
最终得到结果:
对上边出错的原因可能是,没有刷新数据库等原因吧