Day8
Day8
- 模板结构优化
- 加载静态文件
- 数据库操作
- 图书管理系统
- ORM
复习
1.渲染模板 context = { } render(request,'模板名称',) {% if in %} {% elif %} {% else %} {% endif%} {% for in reversed%} {% endfor %} {% for key,value in vip.items %} forloop.counter 默认1 counter0 recounter recounter0 first last parentloop for in {% empty %} with list=vip.0 with vip.0 as list a href="{% url 'front:users' name='xubao id='1' %}?page=1" spaceless 移除空白 空格 换行 tab autoescape off verbatim {{}} {{ 变量名 |过滤器名:参数 }} templatetags my_filter.py from django import template 创建模板库对象 register = template.Library() #过滤器函数 @register.filter def mycut(value,mystr): return value.replace(mystr) register.filter("mycut",mycut) {% load my_filter %}
模版结构优化
引入模版
有时候一些代码是在许多模版中都用到的。如果我们每次都重复的去拷贝代码那肯定不符合项目的规范。一般我们可以把这些重复性的代码抽取出来,就类似于Python中的函数一样,以后想要使用这些代码的时候,就通过
include包含进来。这个标签就是
include。示例代码如下:
# header.html <p>我是header</p> # footer.html <p>我是footer</p> # main.html {% include 'header.html' %} <p>我是main内容</p> {% include 'footer.html' %}
include标签寻找路径的方式。也是跟
render渲染模板的函数是一样的。
默认
include标签包含模版,会自动的使用主模版中的上下文,也即可以自动的使用主模版中的变量。如果想传入一些其他的参数,那么可以使用
with语句。示例代码如下:
# header.html <p>用户名:{{ username }}</p> # main.html {% include "header.html" with username='qf' %}
模板继承:
在前端页面开发中。有些代码是需要重复使用的。这种情况可以使用
include标签来实现。也可以使用另外一个比较强大的方式来实现,那就是模版继承。模版继承类似于
Python中的类,在父类中可以先定义好一些变量和方法,然后在子类中实现。模版继承也可以在父模版中先定义好一些子模版需要用到的代码,然后子模版直接继承就可以了。并且因为子模版肯定有自己的不同代码,因此可以在父模版中定义一个block接口,然后子模版再去实现。以下是父模版的代码:
{% load static %} <!DOCTYPE html> <html lang="en"> <head> <link rel="stylesheet" href="{% static 'style.css' %}" /> <title>{% block title %}我的站点{% endblock %}</title> </head> <body> <div id="sidebar"> {% block sidebar %} <ul> <li><a href="/">首页</a></li> <li><a href="/blog/">博客</a></li> </ul> {% endblock %} </div> <div id="content"> {% block content %}{% endblock %} </div> </body> </html>
这个模版,我们取名叫做
base.html,定义好一个简单的
html骨架,然后定义好两个
block接口,让子模版来根据具体需求来实现。子模板然后通过
extends标签来实现,示例代码如下:
{% extends "base.html" %} {% block title %}博客列表{% endblock %} {% block content %} {% for entry in blog_entries %} <h2>{{ entry.title }}</h2> <p>{{ entry.body }}</p> {% endfor %} {% endblock %}
需要注意的是:extends标签必须放在模版的第一行。
子模板中的代码必须放在block中,否则将不会被渲染。
如果在某个
block中需要使用父模版的内容,那么可以使用
{{block.super}}来继承。比如上例,
{%block title%},如果想要使用父模版的
title,那么可以在子模版的
title block中使用
{{ block.super }}来实现。
在定义
block的时候,除了在
block开始的地方定义这个
block的名字,还可以在
block结束的时候定义名字。比如
{% block title %}{% endblock title %}。这在大型模版中显得尤其有用,能让你快速的看到
block包含在哪里。
操作数据库
Django配置连接数据库:
在操作数据库之前,首先先要连接数据库。这里我们以配置
MySQL为例来讲解。
Django连接数据库,不需要单独的创建一个连接对象。只需要在
settings.py文件中做好数据库相关的配置就可以了。示例代码如下:
DATABASES = { 'default': { # 数据库引擎(是mysql还是oracle等) 'ENGINE': 'django.db.backends.mysql', # 数据库的名字 'NAME': 'dfz', # 连接mysql数据库的用户名 'USER': 'root', # 连接mysql数据库的密码 'PASSWORD': 'root', # mysql数据库的主机地址 'HOST': '127.0.0.1', # mysql数据库的端口号 'PORT': '3306', } }
在Django中操作数据库:
在
Django中操作数据库有两种方式。第一种方式就是使用原生
sql语句操作,第二种就是使用
ORM模型来操作。这节课首先来讲下第一种。
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', #数据库的名字 'NAME': 'django_db1', #数据库用户名 'USER':'root', #数据库密码: 'PASSWORD':'123456', #数据库主机地址 'HOST':'127.0.0.1', #端口号 'PORT':'3306' } }
在
Django中使用原生
sql语句操作其实就是使用
python db api的接口来操作。如果你的
mysql驱动使用的是
pymysql,那么你就是使用
pymysql来操作的,只不过
Django将数据库连接的这一部分封装好了,我们只要在
settings.py中配置好了数据库连接信息后直接使用
Django封装好的接口就可以操作了。示例代码如下:
# 使用django封装好的connection对象,会自动读取settings.py中数据库的配置信息 from django.db import connection # 获取游标对象 cursor = connection.cursor() # 拿到游标对象后执行sql语句 cursor.execute("select * from book") # 获取所有的数据 rows = cursor.fetchall() # 遍历查询到的数据 for row in rows: print(row)
以上的
execute以及
fetchall方法都是
Python DB API规范中定义好的。任何使用
Python来操作
MySQL的驱动程序都应该遵循这个规范。所以不管是使用
pymysql或者是
mysqlclient或者是
mysqldb,他们的接口都是一样的。更多规范请参考:https://www.python.org/dev/peps/pep-0249/。
Python DB API下规范下cursor对象常用接口:
-
description
:如果cursor
执行了查询的sql
代码。那么读取cursor.description
属性的时候,将返回一个列表,这个列表中装的是元组,元组中装的分别是(name,type_code,display_size,internal_size,precision,scale,null_ok)
,其中name
代表的是查找出来的数据的字段名称,其他参数暂时用处不大。 -
rowcount
:代表的是在执行了sql
语句后受影响的行数。 -
close
:关闭游标。关闭游标以后就再也不能使用了,否则会抛出异常。 -
execute(sql[,parameters])
:执行某个sql
语句。如果在执行sql
语句的时候还需要传递参数,那么可以传给parameters
参数。示例代码如下:cursor.execute("select * from article where id=%s",(1,))
-
fetchone
:在执行了查询操作以后,获取第一条数据。 -
fetchmany(size)
:在执行查询操作以后,获取多条数据。具体是多少条要看传的size
参数。如果不传size
参数,那么默认是获取第一条数据。 -
fetchall
:获取所有满足sql
语句的数据。
ORM模型介绍
内连接: select 表1.字段 [as 别名],表n.字段n from 表 [别名],表n where 条件; select 表1.字段 [as 别名],表n.字段n from 表n inner join 表n on条件; 外连接: 左连接 select 表1.字段 [as 别名],表n.字段n from 表n left join 表n on条件; 右连接 select 表1.字段 [as 别名],表n.字段n from 表n right join 表n on条件; 子查询 select 字段 from 表 where 字段 in( select 字段 from 表 )
随着项目越来越大,采用写原生SQL的方式在代码中会出现大量的SQL语句,那么问题就出现了:
- SQL语句重复利用率不高,越复杂的SQL语句条件越多,代码越长。会出现很多相近的SQL语句。
- 很多SQL语句是在业务逻辑中拼出来的,如果有数据库需要更改,就要去修改这些逻辑,这会很容易漏掉对某些SQL语句的修改。
- 写SQL时容易忽略web安全问题,给未来造成隐患。SQL注入。
ORM,全称
Object Relational Mapping,中文叫做对象关系映射,通过
ORM我们可以通过类的方式去操作数据库,而不用再写原生的SQL语句。通过把表映射成类,把行作实例,把字段作为属性,
ORM在执行对象操作的时候最终还是会把对应的操作转换为数据库原生语句。使用
ORM有许多优点:
- 易用性:使用
ORM
做数据库的开发可以有效的减少重复SQL语句的概率,写出来的模型也更加直观、清晰。 - 性能损耗小:
ORM
转换成底层数据库操作指令确实会有一些开销。但从实际的情况来看,这种性能损耗很少(不足5%),只要不是对性能有严苛的要求,综合考虑开发效率、代码的阅读性,带来的好处要远远大于性能损耗,而且项目越大作用越明显。 - 设计灵活:可以轻松的写出复杂的查询。
- 可移植性:
Django
封装了底层的数据库实现,支持多个关系数据库引擎,包括流行的MySQL
、PostgreSQL
和SQLite
。可以非常轻松的切换数据库。
创建ORM模型:
ORM模型一般都是放在
app的
models.py文件中。每个
app都可以拥有自己的模型。并且如果这个模型想要映射到数据库中,那么这个
app必须要放在
settings.py的
INSTALLED_APP中进行安装。以下是写一个简单的书籍
ORM模型。示例代码如下:
from django.db import models class Book(models.Model): name = models.CharField(max_length=20,null=False) author = models.CharField(max_length=20,null=False) pub_time = models.DateTimeField(default=datetime.now) price = models.FloatField(default=0)
以上便定义了一个模型。这个模型继承自
django.db.models.Model,如果这个模型想要映射到数据库中,就必须继承自这个类。这个模型以后映射到数据库中,表名是模型名称的小写形式,为
book。在这个表中,有四个字段,一个为
name,这个字段是保存的是书的名称,是
varchar类型,最长不能超过20个字符,并且不能为空。第二个字段是作者名字类型,同样也是
varchar类型,长度不能超过20个。第三个是出版时间,数据类型是
datetime类型,默认是保存这本书籍的时间。第五个是这本书的价格,是浮点类型。
还有一个字段我们没有写,就是主键
id,在
django中,如果一个模型没有定义主键,那么将会自动生成一个自动增长的
int类型的主键,并且这个主键的名字就叫做
id。
映射模型到数据库中:
将
ORM模型映射到数据库中,总结起来就是以下几步:
- 在
settings.py
中,配置好DATABASES
,做好数据库相关的配置。 - 在
app
中的models.py
中定义好模型,这个模型必须继承自django.db.models
。 - 将这个
app
添加到setting 4000 s.py
的INSTALLED_APP
中。 - 在命令行终端,进入到项目所在的路径,然后执行命令
python manage.py makemigrations
来生成迁移脚本文件。 - 同样在命令行中,执行命令
python manage.py migrate
来将迁移脚本文件映射到数据库中。
模型常用属性
常用字段:
在
Django中,定义了一些
Field来与数据库表中的字段类型来进行映射。以下将介绍那些常用的字段类型。
AutoField:
映射到数据库中是
int类型,可以有自动增长的特性。一般不需要使用这个类型,如果不指定主键,那么模型会自动的生成一个叫做
id的自动增长的主键。如果你想指定一个其他名字的并且具有自动增长的主键,使用
AutoField也是可以的。
BigAutoField:
64位的整形,类似于
AutoField,只不过是产生的数据的范围是从
1-9223372036854775807。
BooleanField:
在模型层面接收的是
True/False。在数据库层面是
tinyint类型。如果没有指定默认值,默认值是
None。
CharField:
在数据库层面是
varchar类型。在
Python层面就是普通的字符串。这个类型在使用的时候必须要指定最大的长度,也即必须要传递
max_length这个关键字参数进去。
DateField:
日期类型。在
Python中是
datetime.date类型,可以记录年月日。在映射到数据库中也是
date类型。使用这个
Field可以传递以下几个参数:
auto_now
:在每次这个数据保存的时候,都使用当前的时间。比如作为一个记录修改日期的字段,可以将这个属性设置为True
。auto_now_add
:在每次数据第一次被添加进去的时候,都使用当前的时间。比如作为一个记录第一次入库的字段,可以将这个属性设置为True
。
DateTimeField:
日期时间类型,类似于
DateField。不仅仅可以存储日期,还可以存储时间。映射到数据库中是
datetime类型。这个
Field也可以使用
auto_now和
auto_now_add两个属性。
TimeField:
时间类型。在数据库中是
time类型。在
Python中是
datetime.time类型。
EmailField:
类似于
CharField。在数据库底层也是一个
varchar类型。最大长度是254个字符。
FileField:
用来存储文件的。这个请参考后面的文件上传章节部分。
ImageField:
用来存储图片文件的。这个请参考后面的图片上传章节部分。
FloatField:
浮点类型。映射到数据库中是
float类型。
IntegerField:
整形。值的区间是
-2147483648——2147483647。
BigIntegerField:
大整形。值的区间是
-9223372036854775808——9223372036854775807。
PositiveIntegerField:
正整形。值的区间是
0——2147483647。
SmallIntegerField:
小整形。值的区间是
-32768——32767。
PositiveSmallIntegerField:
正小整形。值的区间是
0——32767。
TextField:
大量的文本类型。映射到数据库中是longtext类型。
UUIDField:
只能存储
uuid格式的字符串。
uuid是一个32位的全球唯一的字符串,一般用来作为主键。
URLField:
类似于
CharField,只不过只能用来存储
url格式的字符串。并且默认的
max_length是200。
Field的常用参数:
null:
如果设置为
True,
Django将会在映射表的时候指定是否为空。默认是为
False。在使用字符串相关的
Field(CharField/TextField)的时候,官方推荐尽量不要使用这个参数,也就是保持默认值
False。因为
Django在处理字符串相关的
Field的时候,即使这个
Field的
null=False,如果你没有给这个
Field传递任何值,那么
Django也会使用一个空的字符串
""来作为默认值存储进去。因此如果再使用
null=True,
Django会产生两种空值的情形(NULL或者空字符串)。如果想要在表单验证的时候允许这个字符串为空,那么建议使用
blank=True。如果你的
Field是
BooleanField,那么对应的可空的字段则为
NullBooleanField。
blank:
标识这个字段在表单验证的时候是否可以为空。默认是
False。
这个和
null是有区别的,
null是一个纯数据库级别的。而
blank是表单验证级别的。
db_column:
这个字段在数据库中的名字。如果没有设置这个参数,那么将会使用模型中属性的名字。
default:
默认值。可以为一个值,或者是一个函数,但是不支持
lambda表达式。并且不支持列表/字典/集合等可变的数据结构。
primary_key:
是否为主键。默认是
False。
unique:
在表中这个字段的值是否唯一。一般是设置手机号码/邮箱等。
更多
Field参数请参考官方文档:https://docs.djangoproject.com/zh-hans/2.0/ref/models/fields/
模型中Meta
配置:
对于一些模型级别的配置。我们可以在模型中定义一个类,叫做
Meta。然后在这个类中添加一些类属性来控制模型的作用。比如我们想要在数据库映射的时候使用自己指定的表名,而不是使用模型的名称。那么我们可以在
Meta类中添加一个
db_table的属性。示例代码如下:
class Book(models.Model): name = models.CharField(max_length=20,null=False) desc = models.CharField(max_length=100,name='description',db_column="description1") class Meta: db_table = 'book_model'
以下将对
Meta类中的一些常用配置进行解释。
db_table:
这个模型映射到数据库中的表名。如果没有指定这个参数,那么在映射的时候将会使用模型名来作为默认的表名。
ordering:
设置在提取数据的排序方式。后面章节会讲到如何查找数据。比如我想在查找数据的时候根据添加的时间排序,那么示例代码如下:
class Book(models.Model): name = models.CharField(max_length=20,null=False) desc = models.CharField(max_length=100,name='description',db_column="description1") pub_date = models.DateTimeField(auto_now_add=True) class Meta: db_table = 'book_model' ordering = ['pub_date']
更多的配置后面会慢慢介绍到。 官方文档:https://docs.djangoproject.com/en/2.0/ref/models/options/
外键和表关系
外键:
在
MySQL中,表有两种引擎,一种是
InnoDB,另外一种是
myisam。如果使用的是
InnoDB引擎,是支持外键约束的。外键的存在使得
ORM框架在处理表关系的时候异常的强大。因此这里我们首先来介绍下外键在
Django中的使用。
类定义为
class ForeignKey(to,on_delete,**options)。第一个参数是引用的是哪个模型,第二个参数是在使用外键引用的模型数据被删除了,这个字段该如何处理,比如有
CASCADE、
SET_NULL等。这里以一个实际案例来说明。比如有一个
User和一个
Article两个模型。一个
User可以发表多篇文章,一个
Article只能有一个
Author,并且通过外键进行引用。那么相关的示例代码如下:
class User(models.Model): username = models.CharField(max_length=20) password = models.CharField(max_length=100) class Article(models.Model): title = models.CharField(max_length=100) content = models.TextField() author = models.ForeignKey("User",on_delete=models.CASCADE)
以上使用
ForeignKey来定义模型之间的关系。即在
article的实例中可以通过
author属性来操作对应的
User模型。这样使用起来非常的方便。示例代码如下:
article = Article(title='abc',content='123') author = User(username='张三',password='111111') article.author = author article.save() # 修改article.author上的值 article.author.username = '李四' article.save()
为什么使用了
ForeignKey后,就能通过
author访问到对应的
user对象呢。因此在底层,
Django为
Article表添加了一个
属性名_id的字段 4000 (比如author的字段名称是author_id),这个字段是一个外键,记录着对应的作者的主键。以后通过
article.author访问的时候,实际上是先通过
author_id找到对应的数据,然后再提取
User表中的这条数据,形成一个模型。
如果想要引用另外一个
app的模型,那么应该在传递
to参数的时候,使用
app.model_name进行指定。以上例为例,如果
User和
Article不是在同一个
app中,那么在引用的时候的示例代码如下:
# User模型在user这个app中 class User(models.Model): username = models.CharField(max_length=20) password = models.CharField(max_length=100) # Article模型在article这个app中 class Article(models.Model): title = models.CharField(max_length=100) content = models.TextField() author = models.ForeignKey("user.User",on_delete=models.CASCADE)
如果模型的外键引用的是本身自己这个模型,那么
to参数可以为
'self',或者是这个模型的名字。在论坛开发中,一般评论都可以进行二级评论,即可以针对另外一个评论进行评论,那么在定义模型的时候就需要使用外键来引用自身。示例代码如下:
class Comment(models.Model): content = models.TextField() origin_comment = models.ForeignKey('self',on_delete=models.CASCADE,null=True) # 或者 # origin_comment = models.ForeignKey('Comment',on_delete=models.CASCADE,null=True)
外键删除操作:
如果一个模型使用了外键。那么在对方那个模型被删掉后,该进行什么样的操作。可以通过
on_delete来指定。可以指定的类型如下:
CASCADE
:级联操作。如果外键对应的那条数据被删除了,那么这条数据也会被删除。PROTECT
:受保护。即只要这条数据引用了外键的那条数据,那么就不能删除外键的那条数据。SET_NULL
:设置为空。如果外键的那条数据被删除了,那么在本条数据上就将这个字段设置为空。如果设置这个选项,前提是要指定这个字段可以为空。SET_DEFAULT
:设置默认值。如果外键的那条数据被删除了,那么本条数据上就将这个字段设置为默认值。如果设置这个选项,前提是要指定这个字段一个默认值。SET()
:如果外键的那条数据被删除了。那么将会获取SET
函数中的值来作为这个外键的值。SET
函数可以接收一个可以调用的对象(比如函数或者方法),如果是可以调用的对象,那么会将这个对象调用后的结果作为值返回回去。DO_NOTHING
:不采取任何行为。一切全看数据库级别的约束。
以上这些选项只是Django级别的,数据级别依旧是RESTRICT!
- [ASP.NET 控件实作 Day8] 控件常用 Attribute 介绍(1)
- 黑马程序员---java基础之day8-9
- DAy8-自动完成输入内容
- 十天冲刺---Day8
- Day8使用IDEA 开发spark
- Spark Streaming揭秘 Day8 RDD生命周期研究
- 2016.7.15 夏令营 Day8
- 西安十五日游day8 模拟赛
- 【2016-10-17】【坚持学习】【Day8】【抽象工厂模式】
- 从零开始学Python-day8
- Linux打卡Day8-用户和组
- 暑期项目开发实训 Day8
- 2017 暑假艾教集训 day8 (补一道思维题,
- HDOJ 5821 Ball 贪心 (16多校day8 1001) )
- Alpha冲刺Day8
- Python-socket网络编程-Day8
- DAY8-python异常处理
- C++ 输入流的 四个函数 get() getline() peek() putback() 20180317 day8
- 工程实训DAY8
- JAVA Day8 总结