1.模型层
1.1简介
你可能已经注意到我们在例子视图中返回文本的方式有点特别。 也就是说,HTML被直接硬编码在 Python代码之中。
def current_datetime(request):now = datetime.datetime.now()html = "<html><body>It is now %s.</body></html>" % nowreturn HttpResponse(html)
尽管这种技术便于解释视图是如何工作的,但直接将HTML硬编码到你的视图里却并不是一个好主意。 让我们来看一下为什么:
- 对页面设计进行的任何改变都必须对 Python 代码进行相应的修改。 站点设计的修改往往比底层 Python 代码的修改要频繁得多,因此如果可以在不进行 Python 代码修改的情况下变更设计,那将会方便得多。
- Python 代码编写和 HTML 设计是两项不同的工作,大多数专业的网站开发环境都将他们分配给不同的人员(甚至不同部门)来完成。 设计者和HTML/CSS的编码人员不应该被要求去编辑Python的代码来完成他们的工作。
- 程序员编写 Python代码和设计人员制作模板两项工作同时进行的效率是最高的,远胜于让一个人等待另一个人完成对某个既包含 Python又包含 HTML 的文件的编辑工作。
基于这些原因,将页面的设计和Python的代码分离开会更干净简洁更容易维护。 我们可以使用 Django的 *模板系统* (Template System)来实现这种模式,这就是本章要具体讨论的问题
1.2模板语法重点
python的模板:HTML代码+模板语法
def current_time(req):# ================================原始的视图函数# import datetime# now=datetime.datetime.now()# html="<html><body>现在时刻:<h1>%s.</h1></body></html>" %now# ================================django模板修改的视图函数# from django.template import Template,Context# now=datetime.datetime.now()# t=Template('<html><body>现在时刻是:<h1>{{current_date}}</h1></body></html>')# #t=get_template('current_datetime.html')# c=Context({'current_date':str(now)})# html=t.render(c)## return HttpResponse(html)#另一种写法(推荐)import datetimenow=datetime.datetime.now()return render(req, 'current_datetime.html', {'current_date':str(now)[:19]})
变量:{{ 变量名 }}
1 深度查询 用句点符
2 过滤器
3 标签:{{% % }}
1.3模板语法之变量
views.py
def template_test(request):name = 'lqz'li = ['lqz', 1, '18']dic = {'name': 'lqz', 'age': 18}ll2 = [{'name': 'lqz', 'age': 18},{'name': 'lqz2', 'age': 19},{'name': 'egon', 'age': 20},{'name': 'kevin', 'age': 23}]ll3=[]class Person:def __init__(self, name):self.name = namedef test(self):print('test函数')return 11@classmethoddef test_classmethod(cls):print('类方法')return '类方法'@staticmethoddef static_method():print('静态方法')return '静态方法'lqz = Person('lqz')egon = Person('egon')person_list = [lqz, egon]bo = Truete = test()import datetimenow=datetime.datetime.now()link1='<a href="https://www.baidu.com">点我<a>'from django.utils import safestringlink=safestring.mark_safe(link1)# html特殊符号对照表(http://tool.chinaz.com/Tools/htmlchar.aspx)# 这样传到前台不会变成特殊字符,因为django给处理了dot='♠'# return render(request, 'template_index.html', {'name':name,'person_list':person_list})return render(request, 'template_index.html', locals())
html
<p>{{ name }}</p><p>{{ li }}</p><p>{{ dic }}</p><p>{{ lqz }}</p><p>{{ person_list }}</p><p>{{ bo }}</p><p>{{ te }}</p><hr><h3>深度查询句点符</h3><p>{{ li.1 }}</p><p>{{ dic.name }}</p><p>{{ lqz.test }}</p><p>{{ lqz.name }}</p><p>{{ person_list.0 }}</p><p>{{ person_list.1.name }}</p><hr><h3>过滤器</h3>{#注意:冒号后面不能加空格#}<p>{{ now | date:"Y-m-d H:i:s" }}</p>{#如果变量为空,设置默认值,空数据,None,变量不存在,都适用#}<p>{{ name |default:'数据为空' }}</p>{#计算长度,只有一个参数#}<p>{{ person_list |length }}</p>{#计算文件大小#}<p>{{ 1024 |filesizeformat }}</p>{#字符串切片,前闭后开,前面取到,后面取不到#}<p>{{ 'hello world lqz' |slice:"2:-1" }}</p><p>{{ 'hello world lqz' |slice:"2:5" }}</p>{#截断字符,至少三个起步,因为会有三个省略号(传负数,1,2,3都是三个省略号)#}<p>{{ '刘清政 world lqz' |truncatechars:"4" }}</p>{#截断文字,以空格做区分,这个不算省略号#}<p>{{ '刘清政 是 大帅比 谢谢' |truncatewords:"1" }}</p><p>{{ link1 }}</p><p>{{ link1|safe }}</p><p>{{ link }}</p><p>♠</p><p>{{ dot }}</p>{#add 可以加负数,传数字字符串都可以#}<p>{{ "10"|add:"-2" }}</p><p>{{ li.1|add:"-2" }}</p><p>{{ li.1|add:2 }}</p><p>{{ li.1|add:"2" }}</p><p>{{ li.1|add:"-2e" }}</p>{#upper#}<p>{{ name|upper }}</p><p>{{ 'LQZ'|lower }}</p><hr><h3>模版语法之标签</h3>{#for 循环 循环列表,循环字典,循环列表对象#}<ui>{% for foo in dic %}{{ foo }}{% endfor %}{#也可以混用html标签#}{% for foo in li %}<ul>foo</ul>{% endfor %}</ui>{#表格#}<table border="1">{% for foo in ll2 %}<tr><td>{{ foo.name }}</td><td>{{ foo.age }}</td></tr>{% endfor %}</table><table border="1">{#'parentloop': {}, 'counter0': 0, 'counter': 1, 'revcounter': 4, 'revcounter0': 3, 'first': True, 'last': False}#}{% for foo in ll2 %}<tr><td>{{ forloop.counter }}</td><td>{{ foo.name }}</td><td>{{ foo.age }}</td></tr>{% endfor %}</table>{% for foo in ll5 %}<p>foo.name</p>{% empty %}<p>空的</p>{% endfor %}<hr><h3>if判断</h3>{% if name %}<a href="">hi {{ name }}</a><a href="">注销</a>{% else %}<a href="">请登录</a><a href="">注册</a>{% endif %}{#还有elif#}<hr><h3>with</h3>{% with ll2.0.name as n %}{{ n }}{% endwith %}{{ n }}{% load my_tag_filter %}{{ 3|multi_filter:3 }}{#传参必须用空格区分#}{% multi_tag 3 9 10 %}{#可以跟if连用#}{% if 3|multi_filter:3 > 9 %}<p>大于</p>{% else %}<p>小于</p>{% endif %}
1.4常用和非常用字段
AutoField(Field)- int自增列,必须填入参数 primary_key=TrueBigAutoField(AutoField)- bigint自增列,必须填入参数 primary_key=True注:当model中如果没有自增列,则自动会创建一个列名为id的列from django.db import modelsclass UserInfo(models.Model):# 自动创建一个列名为id的且为自增的整数列username = models.CharField(max_length=32)class Group(models.Model):# 自定义自增列nid = models.AutoField(primary_key=True)name = models.CharField(max_length=32)
SmallIntegerField(IntegerField):- 小整数 -32768 ~ 32767PositiveSmallIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)- 正小整数 0 ~ 32767
IntegerField(Field)- 整数列(有符号的) -2147483648 ~ 2147483647PositiveIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)- 正整数 0 ~ 2147483647BigIntegerField(IntegerField):- 长整型(有符号的) -9223372036854775808 ~ 9223372036854775807BooleanField(Field)- 布尔值类型NullBooleanField(Field):- 可以为空的布尔值CharField(Field)- 字符类型- 必须提供max_length参数, max_length表示字符长度TextField(Field)- 文本类型EmailField(CharField):- 字符串类型,Django Admin以及ModelForm中提供验证机制IPAddressField(Field)- 字符串类型,Django Admin以及ModelForm中提供验证 IPV4 机制URLField(CharField)- 字符串类型,Django Admin以及ModelForm中提供验证 URLSlugField(CharField)- 字符串类型,Django Admin以及ModelForm中提供验证支持 字母、数字、下划线、连接符(减号)CommaSeparatedIntegerField(CharField)- 字符串类型,格式必须为逗号分割的数字UUIDField(Field)- 字符串类型,Django Admin以及ModelForm中提供对UUID格式的验证FilePathField(Field)- 字符串,Django Admin以及ModelForm中提供读取文件夹下文件的功能- 参数:path, 文件夹路径match=None, 正则匹配recursive=False, 递归下面的文件夹allow_files=True, 允许文件allow_folders=False, 允许文件夹FileField(Field)- 字符串,路径保存在数据库,文件上传到指定目录- 参数:upload_to = "" 上传文件的保存路径storage = None 存储组件,默认django.core.files.storage.FileSystemStorageImageField(FileField)- 字符串,路径保存在数据库,文件上传到指定目录- 参数:upload_to = "" 上传文件的保存路径storage = None 存储组件,默认django.core.files.storage.FileSystemStoragewidth_field=None, 上传图片的高度保存的数据库字段名(字符串)height_field=None 上传图片的宽度保存的数据库字段名(字符串)DateTimeField(DateField)- 日期+时间格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ]DateField(DateTimeCheckMixin, Field)- 日期格式 YYYY-MM-DDTimeField(DateTimeCheckMixin, Field)- 时间格式 HH:MM[:ss[.uuuuuu]]DurationField(Field)- 长整数,时间间隔,数据库中按照bigint存储,ORM中获取的值为datetime.timedelta类型FloatField(Field)- 浮点型DecimalField(Field)- 10进制小数- 参数:max_digits,小数总长度decimal_places,小数位长度BinaryField(Field)- 二进制类型
1.5常用字段和非常用字段参数
# null
如果为True,Django 将用NULL 来在数据库中存储空值。 默认值是 False.
# blank 后台管理---》admin中会用,咱们一般用的少
如果为True,该字段允许不填。默认为False。
要注意,这与 null 不同。null纯粹是数据库范畴的,而 blank 是数据验证范畴的。
如果一个字段的blank=True,表单的验证将允许该字段是空值。如果字段的blank=False,该字段就是必填的。# default
字段的默认值。可以是一个值或者可调用对象。如果可调用 ,每有新对象被创建它都会被调用。# primary_key
如果为True,那么这个字段就是模型的主键。如果你没有指定任何一个字段的primary_key=True,
Django 就会自动添加一个IntegerField字段做为主键,所以除非你想覆盖默认的主键行为,
否则没必要设置任何一个字段的primary_key=True。# unique
如果该值设置为 True, 这个数据字段的值在整张表中必须是唯一的# db_index :该字段建立索引# choices
由二元组组成的一个可迭代对象(例如,列表或元组),用来给字段提供选择项。 如果设置了choices ,默认的表单将是一个选择框而不是标准的文本框,<br>而且这个选择框的选项就是choices 中的选项。
get_type_book_display()# 关于Meta中
class UserInfo(models.Model):nid = models.AutoField(primary_key=True,index=True)username = models.CharField(max_length=32)mobile=models.CharField(max_length=32)class Meta:# 数据库中生成的表名称 默认 app名称 + 下划线 + 类名db_table = "table_name"# 联合索引index_together = [("username", "mobile"),]# 联合唯一索引unique_together = (("username", "mobile"),)# admin中显示的表名称verbose_name='图书表'# verbose_name加sverbose_name_plural
1.6settings配值
# orm 可以操作:sqlite,mysql,oracle,postgresql。。。。# 配置文件中的配置
### 默认配置:操作sqlite
DATABASES = {'default': {'ENGINE': 'django.db.backends.sqlite3','NAME': BASE_DIR / 'db.sqlite_lqz',}
}#### 操作mysql
# 配置文件:
DATABASES = {'default': {'ENGINE': 'django.db.backends.mysql','NAME': 'day05','HOST':'127.0.0.1','PORT':3306,'USER':'root','PASSWORD':'1234',}
}#装模块:pymsql模块,mysqlclientpip3 install mysqlclient #其他不需要任何操作----》有可能在你机器装不上,macpip3 install pymysql --upgrade# 保证它执行,放在配置文件中import pymysqlpymysql.install_as_MySQLdb()
1.7基本操作整删改查(增加删除字段,增加记录,删除记录,查询记录)
1.增加字段:只需要在表模型,增加,注释字段,增加删除字段参数,在迁移就可以了。(不要轻易的删除迁移记录)
2.增加表记录:
# 方案一:Book.object.create()#方案二:book=Book(参数)book.save()
3.删除记录
-删除方式一:查出来再删Book.objects.all().delete()-删除方式二:#可以重写类中得delete方法book=Book.objects.filter(pk=1).first()book.delete() #Book 类中有个delete方法,咱们没有写---》父类的--》可以重写
4.更新
-更新方式一:查出来再删Book.objects.all().update()-更新方式二: book=Book.objects.filter(pk=1).first()book.name='ss'book.save()
5.查
# all(): 查询所有结果
# filter(**kwargs): 它包含了与所给筛选条件相匹配的对象
# get(**kwargs): 返回与所给筛选条件相匹配的对象,返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有都会抛出错误。# exclude(**kwargs): 它包含了与所给筛选条件不匹配的对象# order_by(*field): 对查询结果排序('-id')# reverse(): 对查询结果反向排序# count(): 返回数据库中匹配查询(QuerySet)的对象数量。# first(): 返回第一条记录# last(): 返回最后一条记录# exists(): 如果QuerySet包含数据,就返回True,否则返回False#values(*field): 返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一系列model的实例化对象,而是一个可迭代的字典序列
#values_list(*field): 它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列# distinct(): 从返回结果中剔除重复纪录
1.8多表操作-创建关系
class Book(models.Model):name = models.CharField(max_length=32)price = models.DecimalField(max_digits=5, decimal_places=2)publish_date = models.DateField()publish = models.ForeignKey(to='Publish',on_delete=models.CASCADE)#这不是个字段authors=models.ManyToManyField(to='Author')def __str__(self):return self.nameclass Author(models.Model):name = models.CharField(max_length=32)age = models.IntegerField()author_detail = models.OneToOneField(to='AuthorDatail',unique=True,on_delete=models.CASCADE)class AuthorDatail(models.Model):telephone = models.BigIntegerField()birthday = models.DateField()addr = models.CharField(max_length=64)class Publish(models.Model):name = models.CharField(max_length=32)city = models.CharField(max_length=32)email = models.EmailField()# 关联关系有如下几种- 一对一:本质就是一对多,只不过多的字段唯一-一对多:外键关联-多对多:必须要有中间表# OneToOneField,ForeignKey 必须写on_delete,不写报错on_delete可选的参数有哪些#1 models.CASCADE 级联删除---》删除出版社---》当前出版社下所有的图书数据都会被删除#2 models.SET_NULL 删除出版社---》当前出版社下所有的图书数据都会的publish_id字段都是置为空publish = models.ForeignKey(to='Publish',on_delete=models.SET_NULL,null=True)#3 models.SET_DEFAULT 删除出版社---》当前出版社下所有的图书数据都会的publish_id字段都设为默认值publish = models.ForeignKey(to='Publish',on_delete=models.SET_DEFAULT,default=1)#4 models.SET(值/可调用对象)删除出版社---》当前出版社下所有的图书数据都会的publish_id字段都设为SET传入的值,如果是可调用对象,会执行可调用对象,把return变# 5 models.DO_NOTHING 删除出版社---》当前出版社下所有的图书数据都会的publish_id字段 原封不动publish = models.ForeignKey(to='Publish',on_delete=models.DO_NOTHING,db_constraint=False)
1.9基于对象跨表查询
1.假设拿到book对象
book.namebook.pricebook.publish_id ---->数字---》出版社id号---》咱们可以通过出版社id,再去出版社表,查出当前出版社---》很麻烦-----快捷方式-----book.publish---->拿到的是 publish对象---》当前图书的出版社对象book.publish.继续往后点击# 上面这种查询方式,称之为基于对象的跨表查询对象=对象.字段publish=book.pulish上面这种查询方式,称之为基于对象的跨表查询对象=对象.字段publish=book.pulish# 有正向查询和 反向查询---》拿到的都是对象-正向:当前表中,有那个字段,类似于:book.pulish author.author_detail-通过字段-反向:当前表中,没有那个字段 author_detail.author 通过author_detail拿到author-通过表名小写# 一对一正反向太简单
# 一对多和多对多的正反向# 正向简单publish=book.pulish# 反向publish对象---》拿到当前publish对象下所有出版过的图书-->反向查询puhlish.book_set.all() # 如果是反向,多条,就要用 表名小写_set.all()# 多对多正反向# 正向: 拿到当前图书所有作者book.authors.all() # 正向--》对象.字段.all()# 反向 拿到当前作者写的所有图书author.book_set.all() #反向--》多条,就要用 表名小写_set.all()import os
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'django_05.settings')
import django
django.setup()
from app01.models import Book,Author,AuthorDatail,Publish
if __name__ == '__main__':#res=Book.objects.all().values("title",'price') # select title,price---》qs中套字典 有key,有value# res=Book.objects.all().values_list("title",'price') # select title,price---》qs中套元组,只有value# print(res)### 一对一正反向# 正向:# author = Author.objects.all().first()# print(author.author_detail.addr)# 反向# author_detail=AuthorDatail.objects.filter(pk=3).first()# print(author_detail.author.name)# 一对多# 正向:# book=Book.objects.all().first()# print(book.publish.name)# 反向# publish=Publish.objects.filter(pk=2).first()# print(publish.book_set.all())# 多对多# 正# book=Book.objects.filter(pk=3).first()# book=Book.objects.filter(pk=2).first()# print(book.authors.all())# 反# author=Author.objects.all().first()# print(author.book_set.all())
1.10基于链表的跨表查询
正向和反向# 想把作者和作者详情链接正:author到 author_detail反:author_detail到author
### 通过 __ 链表#### 一对一链表- 正反向# 拿出id为1的作者(作者表) 的地址(作者详情表)# 正向---》字段名 author_detail# res=Author.objects.filter(pk=1).values('id','name','age','author_detail__addr')# print(res)# 反向---》查询 作者地址是 北京 的作者名和作者年龄# 反向--》表名小写# res=AuthorDatail.objects.filter(addr='北京').values('addr','author__name','author__age')# print(res)### 一对多正反向# 查询北京出版社出版过的所有书籍的名字与价格(一对多)# 反 :表名小写# res=Publish.objects.filter(name='北京出版社').values('name','book__name','book__price')# print(res)# 正: 按字段# res=Book.objects.filter(publish__name='北京出版社').values('publish__name','name','price')# print(res)#####查询红楼梦这本书出版社的名字####### 多对多关系#练习: 查询lqz出过的所有书籍的名字(多对多)# 反res=Author.objects.filter(name='lqz').values("name","book__name")# print(res)# 正res=Book.objects.filter(authors__name='lqz').values('authors__name','name')# print(res)#### # 查询红楼梦这本书出版社的名字##### 查询北京出版社出版过的所有书籍的名字以及作者的姓名# res=Publish.objects.filter(name='北京出版社').values('book__name','book__authors__name','book__authors__author_detail__addr')# print(res)res=Book.objects.filter(publish__name='北京出版社').values('name','authors__name')# print(res)res = Author.objects.filter(book__publish__name='北京出版社').values('book__name','name')print(res)
2.过滤器
2.1编写步骤
1 注册app
2 在某个app下:创建templatetags模块(模块名只能是templatetags)
3 在包下写一个py文件,随便命名
4 在py文件中:写入
from django import template
register = template.Library() # register的名字是固定的,不可改变5 定义自己的标签或过滤器
@register.filter
def filter_words(content: str) -> str:l = ['妈的', '傻逼', '退游']# 把content中所有关键词,替换,返回for item in l:content = content.replace(item, "**")return content@register.simple_tag
def my_input(id,arg):result = "<input type='text' id='%s' class='%s' />" %(id,arg)return mark_safe(result)6 在模板中使用{% load common_filter %} 使用
<p>{{ content|filter_words}}</p>
{% my_input 7 'red' %}