您的位置:首页 > 其它

Day8

2019-05-22 23:35 106 查看

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对象常用接口:

  1. description
    :如果
    cursor
    执行了查询的
    sql
    代码。那么读取
    cursor.description
    属性的时候,将返回一个列表,这个列表中装的是元组,元组中装的分别是
    (name,type_code,display_size,internal_size,precision,scale,null_ok)
    ,其中
    name
    代表的是查找出来的数据的字段名称,其他参数暂时用处不大。

  2. rowcount
    :代表的是在执行了
    sql
    语句后受影响的行数。

  3. close
    :关闭游标。关闭游标以后就再也不能使用了,否则会抛出异常。

  4. execute(sql[,parameters])
    :执行某个
    sql
    语句。如果在执行
    sql
    语句的时候还需要传递参数,那么可以传给
    parameters
    参数。示例代码如下:

    cursor.execute("select * from article where id=%s",(1,))
  5. fetchone
    :在执行了查询操作以后,获取第一条数据。

  6. fetchmany(size)
    :在执行查询操作以后,获取多条数据。具体是多少条要看传的
    size
    参数。如果不传
    size
    参数,那么默认是获取第一条数据。

  7. 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语句,那么问题就出现了:

  1. SQL语句重复利用率不高,越复杂的SQL语句条件越多,代码越长。会出现很多相近的SQL语句。
  2. 很多SQL语句是在业务逻辑中拼出来的,如果有数据库需要更改,就要去修改这些逻辑,这会很容易漏掉对某些SQL语句的修改。
  3. 写SQL时容易忽略web安全问题,给未来造成隐患。SQL注入。

ORM
,全称
Object Relational Mapping
,中文叫做对象关系映射,通过
ORM
我们可以通过类的方式去操作数据库,而不用再写原生的SQL语句。通过把表映射成类,把行作实例,把字段作为属性,
ORM
在执行对象操作的时候最终还是会把对应的操作转换为数据库原生语句。使用
ORM
有许多优点:

  1. 易用性:使用
    ORM
    做数据库的开发可以有效的减少重复SQL语句的概率,写出来的模型也更加直观、清晰。
  2. 性能损耗小:
    ORM
    转换成底层数据库操作指令确实会有一些开销。但从实际的情况来看,这种性能损耗很少(不足5%),只要不是对性能有严苛的要求,综合考虑开发效率、代码的阅读性,带来的好处要远远大于性能损耗,而且项目越大作用越明显。
  3. 设计灵活:可以轻松的写出复杂的查询。
  4. 可移植性:
    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
模型映射到数据库中,总结起来就是以下几步:

  1. settings.py
    中,配置好
    DATABASES
    ,做好数据库相关的配置。
  2. app
    中的
    models.py
    中定义好模型,这个模型必须继承自
    django.db.models
  3. 将这个
    app
    添加到
    setting
    4000
    s.py
    INSTALLED_APP
    中。
  4. 在命令行终端,进入到项目所在的路径,然后执行命令
    python manage.py makemigrations
    来生成迁移脚本文件。
  5. 同样在命令行中,执行命令
    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
可以传递以下几个参数:

  1. auto_now
    :在每次这个数据保存的时候,都使用当前的时间。比如作为一个记录修改日期的字段,可以将这个属性设置为
    True
  2. 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
来指定。可以指定的类型如下:

  1. CASCADE
    :级联操作。如果外键对应的那条数据被删除了,那么这条数据也会被删除。
  2. PROTECT
    :受保护。即只要这条数据引用了外键的那条数据,那么就不能删除外键的那条数据。
  3. SET_NULL
    :设置为空。如果外键的那条数据被删除了,那么在本条数据上就将这个字段设置为空。如果设置这个选项,前提是要指定这个字段可以为空。
  4. SET_DEFAULT
    :设置默认值。如果外键的那条数据被删除了,那么本条数据上就将这个字段设置为默认值。如果设置这个选项,前提是要指定这个字段一个默认值。
  5. SET()
    :如果外键的那条数据被删除了。那么将会获取
    SET
    函数中的值来作为这个外键的值。
    SET
    函数可以接收一个可以调用的对象(比如函数或者方法),如果是可以调用的对象,那么会将这个对象调用后的结果作为值返回回去。
  6. DO_NOTHING
    :不采取任何行为。一切全看数据库级别的约束。

以上这些选项只是Django级别的,数据级别依旧是RESTRICT!

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: