Django深入研究2(深入模板、模型和数据库及数据库操作)
一、模板深究
??Django作为Web框架,需要一种很便利的方法去动态地生成HTML网页,因此有了模板这个概念。模板包含所需HTML的部分代码以及一些特殊的语法,特殊的语法用于描述如何将数据动态插入HTML网页中。 ??Django可以配置一个或多个模板引擎(甚至是0,如果不需要使用模板),模板系统有Django模板语言(Django Template Language,DTL)和Jinja2。Django模板语言是Django内置的模板语言,Jinja2是当前Python最流行的模板语言。这里以Django内置的模板语言为讲述内容,模板配置可看前文。
1、变量与标签
??变量是模板中最基本的组成单位,模板变量是由视图函数生成的。如果变量没有被视图函数生成,那么模板引擎解析HTML时,模板变量不会显示在网页上。变量以{{variable}}表示,variable是变量名,变量的类型可以是Python支持的数据类型。 模板中常用的语法如下: 示例代码:
<ul id="cate_box" class="lf">
{%for type in type_list%}
<li>
<h3><a href="这是链接">{{type.type}}</a></h3>
<p>
{% for name in name_list %}
{% if name.type == type.type %}
<span>{{name.name}}</span>
{%endif%}
{%endfor%}
</p>
</li>
{%endfor%}
</ul>
- {{ title }}代表模板变量,从变量名title可以知道,变量的数据类型是字符串类型或整型。
- {% load staticfiles %}是模板的内置标签,load标签用于导入静态资源信息。
- {% static “css/hw_index.css” %}是模板是内置标签,static标签用于读取静态资源的文件内容。
- {% for type in type_list %}是for遍历标签,将变量进行遍历输出。
- {% if name.type=type.type %}是if判断标签,主要对变量进行判断处理。
- {{ type.type }}代表变量type_list的某个属性。
?? 从上面的例子可以看到,模板的变量需要和标签相互结合使用。模板的标签就如Python 里面的函数和方法,Django常用的内置标签说明如下: ?? 需要说明的是,for和if都是支持嵌套的,而且需要再结束时增加终止符({% endif %}和{% endfor %});在for标签中,模板还提供一些特殊的变量来获取for标签的循环信息:
2、模板继承
?? 模板继承是通过模板标签来实现的,其作用是将多个HTML模板的共同代码集中在一个新的HTML模板中,然后各个模板可以直接调用新的HTML模板,从而生成HTML网页,这样可以减少模板之间重复的代码。示例如下:
"""
这是一个完整的HTML模板,一个完整的模板有<head>和<body>两大部分,
其中<head>部分在大多数情况下都是相同的,因此可以将<head>部分写到共用模板中,
将共用模板命名为base.html
"""
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>{{title}}</title>
</head>
<body>
<a href="{% url 'index' %)"target="_blank">首页</a>
<h1>He11o Django</h1>
</body>
</html>
"""
在base.html的代码中可以看到,<body>里的内容变为{%block body %}
{% endblock %},block标签相当于一个函数(用于重写父类代码),body是对该函数的命名,开发者可自行命名。在一个模板中可以添加多个block标签,只要每个block标签的命名不相同即可。
"""
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>{{title}}</title>
</head>
<body>
{%block body %}{% endblock %}
</body>
</html>
{% extends "base.html" %}
{% block body %}
<a href="{%url 'index'%}"target="_blank">首页</a>
<h1>Hello Django</h1>
{% endblock %}
??模板index.html调用共用模板 base.html的实质是由模板继承实现的,调用步骤如下:
- 步骤1:在模板index.html中使用{%extends"base.html"%}来继承模板base.html的代码。
- 步骤2:由标签{%block body%}在继承模板的基础上实现自定义模板的内容。
- 步骤3:由{%endblock%}结束block标签。
??从上面例子看到,模板继承与Python的类继承的原理是一致的,通过继承的方式使其具有父类的功能和属性,然后以重写的方式实现各种开发需求。
3、自定义过滤器
??过滤器主要是对变量的内容进行处理,如替换、反序和转义等。通过过滤器处理变量可以将变量的数据格式和内容转化为我们想要的效果,而且相应减少视图函数的代码量。过滤器的使用方法如下:
{{variable | filter}}
??模板引擎解析带过滤器的变量时,首先过滤器filter处理变量variable,然后将处理后的变量显示在网页上。其中,variable代表模板变量,管道符号“|”代表变量使用过滤器,filter代表某个过滤器。变量可以支持多个过滤器同时使用,例如下:
{{variable | filter | lower)}
??在使用的过程中,有些过滤器还可以传入参数,但仅支持一个参数的传入。带参过滤器的使用方法如下:
{{variable | date:"D d M Y"}}
Django 的内置过滤器: ??在实际开发中,如果内置过滤器的功能不太适合实际开发需求,我们可以通过自定义过滤器来解决问题。首先在MyDjango项目中添加了user_defined文件夹,在其文件夹下又分别添加了templatetags文件夹和_init.py文件。templatetags用于存放自定义过滤器的代码文件,该文件夹也可以存放在项目的App中,但必须注意的是,文件夹的命名必须为templatetags,否则Django在运行的时候无法识别自定义过滤器。最后在templatetags文件夹下创建myfilter.py文件,该文件是编写自定义过滤器的实现代码。 ??完成过滤器的目录搭建,接着是配置过滤器的信息,在配置文件 settings.py 中的INSTALLED_APPS 里面添加user_defined。当项目启动时,Django会从INSTALLED_APPS 的配置中查找过滤器,若过滤器在index目录下,则只需要在INSTALLED_APPS 中添加index。 ??文件路径以及配置文成后,就可以编写自定义的过滤器函数了。在myfilter.py中添加如下代码,即可实现字符串替换功能:
from django import template
register = template.Library()
@register.filter
def myreplace(value, agrs):
o1dValue=agrs.split(':')[0]
newValue=agrs.split(':')[1]
return value.replace(oldValue, newValue)
代码说明:
- 首先导入模板功能template,通过template声明Library对象,将对象赋值给变量register,这一过程称为注册过滤器。
- 过滤器以函数的形式实现,在函数前使用register.filter装饰器来表示该函数是一个过滤器,函数名可自行命名。
- 函数参数可设置一个或两个,如上述的参数分别是value和agrs,参数value是HTML模板的变量,实际中不适用,和类的self很像,参数agrs是过滤器函数定义的函数参数。
- 过滤器函数最后必须将处理结果返回,否则在使用过程中会出现异常信息。
自定义过滤器使用: ??在HTML模板中使用自定义的过滤器可以分为两大步骤,说明如下:
- {%load myfilter%}用于导入templatetags文件夹的myfilter.py文件中所定义的功能,用来告诉Django在哪个地方可以找到自定义过滤器,必须写在模板的第一行。
- {{ title | myreplace:‘首页:我的首页’ }}把变量title含有“首页”的内容替换成“我的首页”。其中,myreplace是过滤器的函数名,“首页:我的首页”是函数参数agrs的值,函数参数value的值为模板变量title的值。
二、模型和数据库
??Django对各种数据库提供了很好的支持,包括:PostgreSQL、MySQL、SQLite和Oracle,而且为这些数据库提供了统一的调用API,这些API统称为ORM框架。 通过使用Django内置的ORM框架可以实现数据库连接和读写操作。
1、构建模型
构建模型步骤如下: (1)配置目标数据库信息,主要在settings.py中设置数据库信息,具体配置步骤参考前文基础配置。 (2)构建虚拟对象数据库,在App的models.py文件中以类的形式定义模型。 (3)通过模型在目标数据库中创建相应的数据表。数据可视化章节 (4)在视图函数中通过对模型操作实现目标数据库的读写操作。
??具体的步骤前面文章已演示,具体可参考前文,这里细说下创建模型时的数据类型:
2、数据表的关系
??一个模型对应目标数据库的一个数据表,但我们知道,每个数据表之间是可以存在关联的,表与表之间有三种关系:一对一、一对多和多对多。 ??在模型中可以通过OneToOneField来构建数据表的一对一关系;通过ForeignKey来构建数据表的一对多关系;通过ManyToManyField来构建数据表多的对多关系。
需要注意的是创建数据表前最好先删除0001_initial.py文件并清空数据库里的数据表,否则可能创建不成功。
具体代码如下:
class Performer(models.Model):
id = models.IntegerField(primary_key=True)
name = models.CharField(max_length=20)
nationality = models.CharField(max_length=20)
masterpiece = models. CharField(max_length=50)
class Performer_info(models.Model):
id = models. IntegerField(primary_key=True)
performer = models.OneToOneField(Performer, on_delete=models.CASCADE)
birth = models. CharField(max_length=20)
elapse = models. CharField(max_length=20)
class Program_main(models.Model):
id = models.IntegerField(primary_key=True)
performer = models.ForeignKey(Performer, on_delete=models.CASCADE)
name = models.CharField(max_length=20)
class Program(models.Model):
id = models.IntegerField(primary_key=True)
name = models.CharField(max_length=20)
performer = models.ManyToManyField(Performer)
结果展示: 一对一: 一对多: 多对多: ??Django创建多对多关系的时候只需定义两个数据库对象,在创建目标数据表的时候会自动生成第三个数据表来建立多对多关系。效果见上图。
3、数据表的读写
??数据库的读写操作主要对数据进行增、删、改、查四种操作,当然一些固定的数据可以直接通过数据库工具(Navicat)操作,但是有一些个动态的数据就必须在项目中经行,所以在这里开启项目的shell模式,开启命令为:
python manage.py shell
1.增加代码如下:
from index.models import *
p = Performer()
p.id = 1
p.name = "张三"
p.nationality = "中国"
p.masterpiece = "万万没想到"
p.save()
Performer.objects.create (id = 2, name='李四',nationality='中国', masterpiece='十万个冷笑话')
p = Performer(id = 3, name='王五',nationality='中国', masterpiece='陈翔六点半')
p.save()
2.更新代码如下:
??如果想对现有的数据进行更新,实现步骤与数据插入的方法大致相同,唯一的区别是在模型实例化之后,要更新数据,需要先进行一次数据查询,将查询结果以对象的形式赋给p,最后对p的属性重新赋值就能实现数据的更新,代码如下:
p = Performer.objects.get(id = 1)
p.name ="赵六"
p.save()
Performer.objects.filter(id=2).update(name='钱七')
3.删除代码如下:
??如果要对数据进行删除处理,有三种方式:删除表中全部数据、删除一条数据和删除多条数据。实现三种删除方式的代码如下:
Performer.objects.all().delete()
Performer.objects.get(id=1).delete()
Performer.objects.filter(id=2).delete()
4.查询代码如下:
??数据查询是数据库操作中最为复杂并且内容最多的部分,下面通过代码讲解一些经常使用的,代码如下:
p = Performer.objects.all()
p[1].name()
p = Performer.objects.all()[:2]
p = Performer.objects.values('name')
p = Performer.objects.get(id=1)
p.name
p = Performer.objects.filter(id=1)
p[0].name
from django.db.models import Q
p=Performer.objects.filter(Q(name='李四')|Q(id=1))
p=Performer.objects.filter(Q(name='李四')|Q(id=1)).distinct()
p=Performer.objects.filter(Q(name='李四')|Q(id=1)).distinct().count()
p =Performer.objects.order_by('-id')
p = Performer.objects.values('name').annotate(Sum('id'))
Out[63]: <QuerySet [{'name': '张三', 'id__sum': 1}, {'name': '李四', 'id__sum': 2},
{'name': '王五', 'id__sum': 3}]>
p = Performer.objects.aggregate(id_count=Count('id'))
Out[65]: {'id_count': 3}
以上代码包括常用的查询语句,但是可能实际中还会用到大于、小于、类似等特殊查询条件,则需要下面的匹配符实现;
4、多表查询
??在上文我们了解到数据表的读写操作,但仅仅局限在单个数据表的操作。在日常的开发中,常常需要对多个数据表同时进行数据查询。多个数据表查询需要数据表之间建立了表关系才得以实现。 ??一对多或一对一的表关系是通过外键实现关联的,而多表查询分为正向查询和反向查询。 如论正向还是反向,代码大致相同,但是反向查询时要执行两次SQL查询,为了避免这种情况发生,引入select_related方法实现,代码示例如下,两个表分别用tab1和tab2代表:
t=tab1.objects.filter(tab2_id=11)
t[0].字段
t[0].tab2_set.values('字段')
Product.objects.select_related('type').values('name','type_type_name')
??select related的使用说明如下:
- 以模型Product作为查询对象主体,当然也可以使用模型Type,只要两表之间有外键关联即可。
- 设置select_related的参数值为“type”,该参数值是模型Product定义的type字段。
- 如果在查询过程中需要使用另一个数据表的字段,可以使用“外键字段名”来指向该表的字段。如type__type_name代表由模型Product的外键type指向模型Type的字段type_name,type代表模型Product的外键type,双下画线"-" 代表连接符,type_name是模型Type的字段。 除此之外,select
related还可以支持三个或三个以上的数据表同时查询。
|