Django
提醒:本文依据 b 站黑马 python 课整顿
链接指引 => 黑马程序员 python 企业级开发我的项目 - 手把手从 0 到 1 开发《美多商城》
MVT 图解
我的项目筹备
1. 创立我的项目
django-admin startproject bookmanager
2. 创立利用
python manager.py startapp book
3. 更换 python 解释器
# 进入指定虚拟环境
which python
4. 装置利用
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
#增加子利用
'book.apps.BookConfig'
]
5. 本地化
# 设置中文
LANGUAGE_CODE = 'zh-Hans'
#亚洲上海时区
TIME_ZONE = 'Asia/Shanghai'
6. 我的项目中匹配 urls
门路只有不是 admin/ 就算匹配胜利。并蕴含到利用中的 urls.py
from django.contrib import admin
from django.urls import path,include
urlpatterns = [path('admin/', admin.site.urls),
path('',include('book.urls'))
]
7. 利用中匹配 urls.py
利用中创立 urls.py
from django.urls import path
from book.views import index
urlpatterns = [path('index/',index)
]
8. 筹备视图
from django.http import HttpResponse
def index(request):
return HttpResponse("OK")
9. 开启服务器, 测试项目
# 进入我的项目文件中, 开启我的项目对应的服务器
python manage.py runserver
# 浏览器中输出网址
http://127.0.0.1:8000/index/
配置
在 settings.py 中保留了数据库的连贯配置信息,Django 默认初始配置应用 sqlite 数据库。
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
1. 在 MySQL 中创立数据库
create database book charset=utf8;
2. 批改 DATABASES 配置信息
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'HOST': '127.0.0.1', # 数据库主机
'PORT': 3306, # 数据库端口
'USER': 'root', # 数据库用户名
'PASSWORD': 'mysql', # 数据库用户明码
'NAME': 'book' # 数据库名字
}
}
3. 运行测试
发现错误
-
虚拟环境中,没有装置 MySQL 数据库的客户端驱动
装置mysqlclient==1.4.6
# 进入虚拟环境 pip install mysqlclient==1.4.6 -i https://pypi.tuna.tsinghua.edu.cn/simple/
4. 如果依照 mysqlclient 报错须要在以后操作系统中装置 libmysqlclient-dev
sudo apt-get install libmysqlclient-dev
定义模型类
- 模型类被定义在 ” 利用
/models.py
“ 文件中。 -
模型类必须继承自
Model
类,位于包django.db.models
中。
接下来首先以 ” 图书 - 人物 ” 治理为例进行演示。1. 定义
在 models.py 文件中定义模型类。
from django.db import models # Create your models here. # 筹备书籍列表信息的模型类 class BookInfo(models.Model): # 创立字段,字段类型... name = models.CharField(max_length=20, verbose_name='名称') pub_date = models.DateField(verbose_name='公布日期',null=True) readcount = models.IntegerField(default=0, verbose_name='浏览量') commentcount = models.IntegerField(default=0, verbose_name='评论量') is_delete = models.BooleanField(default=False, verbose_name='逻辑删除') class Meta: db_table = 'bookinfo' # 指明数据库表名 verbose_name = '图书' # 在 admin 站点中显示的名称 def __str__(self): """定义每个数据对象的显示信息""" return self.name # 筹备人物列表信息的模型类 class PeopleInfo(models.Model): GENDER_CHOICES = ((0, 'male'), (1, 'female') ) name = models.CharField(max_length=20, verbose_name='名称') gender = models.SmallIntegerField(choices=GENDER_CHOICES, default=0, verbose_name='性别') description = models.CharField(max_length=200, null=True, verbose_name='形容信息') book = models.ForeignKey(BookInfo, on_delete=models.CASCADE, verbose_name='图书') # 外键 is_delete = models.BooleanField(default=False, verbose_name='逻辑删除') class Meta: db_table = 'peopleinfo' verbose_name = '人物信息' def __str__(self): return self.name
1)数据库表名
模型类如果未指明表名,Django 默认以小写 app 利用名_小写模型类名为数据库表名。
可通过 db_table 指明数据库表名。
2)对于主键
django 会为表创立主动增长的主键列,每个模型只能有一个主键列,如果应用选项设置某属性为主键列后 django 不会再创立主动增长的主键列。
默认创立的主键列属性为 id,能够应用 pk 代替,pk 全拼为 primary key。
3)属性命名限度
不能是 python 的保留关键字。
不容许应用间断的下划线,这是由 django 的查问形式决定的。
定义属性时须要指定字段类型,通过字段类型的参数指定选项,语法如下:
属性 =models. 字段类型(选项)
4)字段类型
类型 | 阐明 |
---|---|
AutoField | 主动增长的 IntegerField,通常不必指定,不指定时 Django 会主动创立属性名为 id 的主动增长属性 |
BooleanField | 布尔字段,值为 True 或 False |
NullBooleanField | 反对 Null、True、False 三种值 |
CharField | 字符串,参数 max_length 示意最大字符个数 |
TextField | 大文本字段,个别超过 4000 个字符时应用 |
IntegerField | 整数 |
DecimalField | 十进制浮点数,参数 max_digits 示意总位数,参数 decimal_places 示意小数位数 |
FloatField | 浮点数 |
DateField | 日期,参数 auto_now 示意每次保留对象时,主动设置该字段为以后工夫,用于 ” 最初一次批改 ” 的工夫戳,它总是应用以后日期,默认为 False;参数 auto_now_add 示意当对象第一次被创立时主动设置以后工夫,用于创立的工夫戳,它总是应用以后日期,默认为 False; 参数 auto_now_add 和 auto_now 是互相排挤的,组合将会产生谬误 |
TimeField | 工夫,参数同 DateField |
DateTimeField | 日期工夫,参数同 DateField |
FileField | 上传文件字段 |
ImageField | 继承于 FileField,对上传的内容进行校验,确保是无效的图片 |
5)选项
选项 | 阐明 |
---|---|
null | 如果为 True,示意容许为空,默认值是 False |
blank | 如果为 True,则该字段容许为空白,默认值是 False |
db_column | 字段的名称,如果未指定,则应用属性的名称 |
db_index | 若值为 True, 则在表中会为此字段创立索引,默认值是 False |
default | 默认 |
primary_key | 若为 True,则该字段会成为模型的主键字段,默认值是 False,个别作为 AutoField 的选项应用 |
unique | 如果为 True, 这个字段在表中必须有惟一值,默认值是 False |
null 是数据库领域的概念,blank 是表单验证领域的
6)外键
在设置外键时,须要通过 on_delete 选项指明主表删除数据时,对于外键援用表数据如何解决,在 django.db.models 中蕴含了可选常量:
- CASCADE 级联,删除主表数据时连通一起删除外键表中数据
- PROTECT 爱护,通过抛出 ProtectedError 异样,来阻止删除主表中被外键利用的数据
- SET_NULL 设置为 NULL,仅在该字段 null=True 容许为 null 时可用
- SET_DEFAULT 设置为默认值,仅在该字段设置了默认值时可用
- SET()设置为特定值或者调用特定办法
- DO_NOTHING 不做任何操作,如果数据库前置指明级联性,此选项会抛出 IntegrityError 异样
2 迁徙
将模型类同步到数据库中。
1)生成迁徙文件
python manage.py makemigrations
2)同步到数据库中
python manage.py migrate
3 增加测试数据
insert into bookinfo(name, pub_date, readcount,commentcount, is_delete) values
('射雕英雄传', '1980-5-1', 12, 34, 0),
('天龙八部', '1986-7-24', 36, 40, 0),
('笑傲江湖', '1995-12-24', 20, 80, 0),
('雪山飞狐', '1987-11-11', 58, 24, 0);
insert into peopleinfo(name, gender, book_id, description, is_delete) values
('郭靖', 1, 1, '降龙十八掌', 0),
('黄蓉', 0, 1, '打狗棍法', 0),
('黄药师', 1, 1, '弹指神通', 0),
('欧阳锋', 1, 1, '蛤蟆功', 0),
('梅超风', 0, 1, '九阴白骨爪', 0),
('乔峰', 1, 2, '降龙十八掌', 0),
('段誉', 1, 2, '六脉神剑', 0),
('虚竹', 1, 2, '天山六阳掌', 0),
('王语嫣', 0, 2, '神仙姐姐', 0),
('令狐冲', 1, 3, '独孤九剑', 0),
('任盈盈', 0, 3, '弹琴', 0),
('岳不群', 1, 3, '华山剑法', 0),
('东方不败', 0, 3, '葵花宝典', 0),
('胡斐', 1, 4, '胡家刀法', 0),
('苗若兰', 0, 4, '黄衣', 0),
('程灵素', 0, 4, '医术', 0),
('袁紫衣', 0, 4, '六合拳', 0);
shell 工具和查看 MySQL 数据库日志
1 shell 工具
Django 的 manage 工具提供了 shell 命令,帮忙咱们配置好以后工程的运行环境(如连贯好数据库等),以便能够间接在终端中执行测试 python 语句。
通过如下命令进入 shell
python manage.py shell
导入两个模型类,以便后续应用
from book.models import BookInfo,PeopleInfo
2 查看 MySQL 数据库日志(后果集个性应用)
查看 mysql 数据库日志能够查看对数据库的操作记录。mysql 日志文件默认没有产生,须要做如下配置:
sudo vi /etc/mysql/mysql.conf.d/mysqld.cnf
把 68,69 行后面的 #去除,而后保留并应用如下命令重启 mysql 服务。
sudo service mysql restart
应用如下命令关上 mysql 日志文件。
tail -f /var/log/mysql/mysql.log # 能够实时查看数据库的日志内容
# 如提醒须要 sudo 权限,执行
# sudo tail -f /var/log/mysql/mysql.log
数据库操作 - 增、删、改
1 减少
减少数据有两种办法。
1)save
通过创立模型类对象,执行对象的 save()办法保留到数据库中。
>>> from book.models import BookInfo,PeopleInfo
>>> book = BookInfo(
... name='python 入门',
... pub_date='2010-1-1'
... )
>>> book.save()
>>> book
<BookInfo: python 入门 >
2)create
通过模型类.objects.create()保留。
>>> PeopleInfo.objects.create(
... name='itheima',
... book=book
... )
<PeopleInfo: itheima>
2 批改
批改更新有两种办法
1)save
批改模型类对象的属性,而后执行 save()办法
>>> person = PeopleInfo.objects.get(name='itheima')
>>> person.name = 'itcast'
>>> person.save()
>>> person
<PeopleInfo: itcast>
2)update
应用模型类.objects.filter().update()
,会返回受影响的行数
>>> PeopleInfo.objects.filter(name='itcast').update(name='传智播客')
3 删除
删除有两种办法
1)模型类对象 delete
>>> person = PeopleInfo.objects.get(name='传智播客')
>>> person.delete()
(1, {'book.PeopleInfo': 1})
2)模型类.objects.filter().delete()
>>> BookInfo.objects.filter(name='python 入门').delete()
(1, {'book.BookInfo': 1, 'book.PeopleInfo': 0})
查问
根底条件查问
1 根本查问
get 查问繁多后果,如果不存在会抛出模型类.DoesNotExist 异样。
all 查问多个后果。
count 查问后果数量。
>>> BookInfo.objects.get(id=1)
<BookInfo: 射雕英雄传 >
>>> BookInfo.objects.get(pk=2)
<BookInfo: 天龙八部 >
>>> BookInfo.objects.get(pk=20)
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/home/python/.virtualenvs/py3_django_1.11/lib/python3.5/site-packages/django/db/models/manager.py", line 85, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/home/python/.virtualenvs/py3_django_1.11/lib/python3.5/site-packages/django/db/models/query.py", line 380, in get
self.model._meta.object_name
book.models.DoesNotExist: BookInfo matching query does not exist.
>>> BookInfo.objects.all()
<QuerySet [<BookInfo: 射雕英雄传 >, <BookInfo: 天龙八部 >, <BookInfo: 笑傲江湖 >, <BookInfo: 雪山飞狐 >]>
>>> BookInfo.objects.count()
4
2 过滤查问
实现 SQL 中的 where 性能,包含
- filter过滤出多个后果
- exclude排除掉符合条件剩下的后果
- get过滤繁多后果
- 对于过滤条件的应用,上述三个办法雷同,故仅以 filter 进行解说。
过滤条件的表白语法如下:
属性名称__比拟运算符 = 值
# 属性名称和比拟运算符间应用两个下划线,所以属性名不能包含多个下划线
查问编号为 1 的图书
查问书名蕴含 '湖' 的图书
查问书名以 '部' 结尾的图书
查问书名为空的图书
查问编号为 1 或 3 或 5 的图书
查问编号大于 3 的图书
查问 1980 年发表的图书
查问 1990 年 1 月 1 日后发表的图书
1)相等
exact:示意判等。
例:查问编号为 1 的图书。
BookInfo.objects.filter(id__exact=1)
可简写为:BookInfo.objects.filter(id=1)
2)含糊查问
contains:是否蕴含。
阐明:如果要蕴含 % 无需本义,间接写即可。
例:查问书名蕴含 ’ 传 ’ 的图书。
BookInfo.objects.filter(name__contains='传')
<QuerySet [<BookInfo: 射雕英雄传 >]>
startswith、endswith:以指定值结尾或结尾。
例:查问书名以 ’ 部 ’ 结尾的图书
>>> BookInfo.objects.filter(name__endswith='部')
<QuerySet [<BookInfo: 天龙八部 >]>
以上运算符都辨别大小写,在这些运算符前加上 i 示意不辨别大小写,如 iexact、icontains、istartswith、iendswith.
3)空查问
isnull:是否为 null。
例:查问书名为空的图书。
>>> BookInfo.objects.filter(name__isnull=True)
<QuerySet []>
4)范畴查问
in:是否蕴含在范畴内。
例:查问编号为 1 或 3 或 5 的图书
>>> BookInfo.objects.filter(id__in=[1,3,5])
<QuerySet [<BookInfo: 射雕英雄传 >, <BookInfo: 笑傲江湖 >]>
5)比拟查问
- gt 大于 (greater then)
- gte 大于等于 (greater then equal)
- lt 小于 (less then)
-
lte 小于等于 (less then equal)
例:查问编号大于 3 的图书BookInfo.objects.filter(id__gt=3)
不等于的运算符,应用 exclude()过滤器。
例:查问编号不等于 3 的图书
>>> BookInfo.objects.filter(id__gt=3)
<QuerySet [<BookInfo: 雪山飞狐 >]>
6)日期查问
year、month、day、week_day、hour、minute、second:对日期工夫类型的属性进行运算。
例:查问 1980 年发表的图书。
>>> BookInfo.objects.filter(pub_date__year=1980)
<QuerySet [<BookInfo: 射雕英雄传 >]>
例:查问 1990 年 1 月 1 日后发表的图书。
>>> BookInfo.objects.filter(pub_date__gt='1990-1-1')
<QuerySet [<BookInfo: 笑傲江湖 >]>
F 和 Q 对象
1.F 对象
之前的查问都是对象的属性与常量值比拟,两个属性怎么比拟呢?答:应用 F 对象,被定义在django.db.models
中。
语法如下:
F(属性名)
例:查问浏览量大于等于评论量的图书。
>>> from django.db.models import F
>>> BookInfo.objects.filter(readcount__gt=F('commentcount'))
<QuerySet [<BookInfo: 雪山飞狐 >]>
能够在 F 对象上应用算数运算。
例:查问浏览量大于 2 倍评论量的图书。
>>> BookInfo.objects.filter(readcount__gt=F('commentcount')*2)
<QuerySet [<BookInfo: 雪山飞狐 >]>
2.Q 对象
多个过滤器一一调用示意逻辑与关系,同 sql 语句中 where 局部的 and 关键字。
例:查问浏览量大于 20,并且编号小于 3 的图书。
>>> BookInfo.objects.filter(readcount__gt=20,id__lt=3)
<QuerySet [<BookInfo: 天龙八部 >]>
或者
>>> BookInfo.objects.filter(readcount__gt=20).filter(id__lt=3)
<QuerySet [<BookInfo: 天龙八部 >]>
如果须要实现逻辑或 or 的查问,须要应用 Q()对象联合 | 运算符,Q 对象被义在 django.db.models 中。
语法如下:
Q(属性名__运算符 = 值)
例:查问浏览量大于 20 的图书,改写为 Q 对象如下。
BookInfo.objects.filter(Q(readcount__gt=20))
Q 对象能够应用 &、| 连贯,& 示意逻辑与,| 示意逻辑或。
例:查问浏览量大于 20,或编号小于 3 的图书,只能应用 Q 对象实现
>>> BookInfo.objects.filter(Q(readcount__gt=20)|Q(id__lt=3))
<QuerySet [<BookInfo: 射雕英雄传 >, <BookInfo: 天龙八部 >, <BookInfo: 雪山飞狐 >]>
Q 对象前能够应用~ 操作符,示意非 not。
例:查问编号不等于 3 的图书。
>>> BookInfo.objects.filter(~Q(id=3))
<QuerySet [<BookInfo: 射雕英雄传 >, <BookInfo: 天龙八部 >, <BookInfo: 雪山飞狐 >]>
聚合函数和排序函数
1. 聚合函数
应用 aggregate()过滤器调用聚合函数。聚合函数包含:Avg 均匀,Count 数量,Max 最大,Min 最小,Sum 求和,被定义在 django.db.models
中。
例:查问图书的总浏览量。
>>> from django.db.models import Sum
>>> BookInfo.objects.aggregate(Sum('readcount'))
{'readcount__sum': 126}
留神 aggregate 的返回值是一个字典类型,格局如下:
{'属性名__聚合类小写': 值}
如:{'readcount__sum': 126}
应用 count 时个别不应用 aggregate()过滤器。
例:查问图书总数。
BookInfo.objects.count()
留神 count 函数的返回值是一个数字。
2. 排序
应用 order_by 对后果进行排序
# 默认升序
>>> BookInfo.objects.all().order_by('readcount')
<QuerySet [<BookInfo: 射雕英雄传 >, <BookInfo: 笑傲江湖 >, <BookInfo: 天龙八部 >, <BookInfo: 雪山飞狐 >]>
# 降序
>>> BookInfo.objects.all().order_by('-readcount')
<QuerySet [<BookInfo: 雪山飞狐 >, <BookInfo: 天龙八部 >, <BookInfo: 笑傲江湖 >, <BookInfo: 射雕英雄传 >]>
级联查问
1. 关联查问
查问书籍为 1 的所有人物信息
查问人物为 1 的书籍信息
由一到多的拜访语法:
一对应的模型类对象. 多对应的模型类名小写 _set
例:
>>> book = BookInfo.objects.get(id=1)
>>> book.peopleinfo_set.all()
<QuerySet [<PeopleInfo: 郭靖 >, <PeopleInfo: 黄蓉 >, <PeopleInfo: 黄药师 >, <PeopleInfo: 欧阳锋 >, <PeopleInfo: 梅超风 >]>
由多到一的拜访语法:
多对应的模型类对象. 多对应的模型类中的关系类属性名 例:
person = PeopleInfo.objects.get(id=1)
person.book
<BookInfo: 射雕英雄传 >
拜访一对应的模型类关联对象的 id 语法:
多对应的模型类对象. 关联类属性_id
例:
>>> person = PeopleInfo.objects.get(id=1)
>>> person.book_id
2. 关联过滤查问
由多模型类条件查问一模型类数据:
语法如下:
关联模型类名小写 __属性名__
条件运算符 = 值
留神:如果没有 ”__运算符
“ 局部,示意等于。
查问图书,要求图书人物为 ” 郭靖 ”
查问图书,要求图书中人物的形容蕴含 ” 八 ”
例:
查问图书,要求图书人物为 ” 郭靖 ”
>>> book = BookInfo.objects.filter(peopleinfo__name='郭靖')
>>> book
<QuerySet [<BookInfo: 射雕英雄传 >]>
查问图书,要求图书中人物的形容蕴含 ” 八 ”
>>> book = BookInfo.objects.filter(peopleinfo__description__contains='八')
>>> book
<QuerySet [<BookInfo: 射雕英雄传 >, <BookInfo: 天龙八部 >]>
由一模型类条件查问多模型类数据:
语法如下:
一模型类关联属性名 __一模型类属性名__
条件运算符 = 值
留神:如果没有 ”__运算符
“ 局部,示意等于。
查问书名为“天龙八部”的所有人物
查问图书浏览量大于 30 的所有人物
例:
查问书名为“天龙八部”的所有人物。
>>> people = PeopleInfo.objects.filter(book__name='天龙八部')
>>> people
<QuerySet [<PeopleInfo: 乔峰 >, <PeopleInfo: 段誉 >, <PeopleInfo: 虚竹 >, <PeopleInfo: 王语嫣 >]>
查问图书浏览量大于 30 的所有人物
>>> people = PeopleInfo.objects.filter(book__readcount__gt=30)
>>> people
<QuerySet [<PeopleInfo: 乔峰 >, <PeopleInfo: 段誉 >, <PeopleInfo: 虚竹 >, <PeopleInfo: 王语嫣 >, <PeopleInfo: 胡斐 >, <PeopleInfo: 苗若兰 >, <PeopleInfo: 程灵素 >, <PeopleInfo: 袁紫衣 >]>
查问集 QuerySet
1 概念
Django 的 ORM 中存在查问集的概念。
查问集,也称查问后果集、QuerySet,示意从数据库中获取的对象汇合。
当调用如下过滤器办法时,Django 会返回查问集(而不是简略的列表):
- all():返回所有数据。
- filter():返回满足条件的数据。
- exclude():返回满足条件之外的数据。
-
order_by():对后果进行排序。
对查问集能够再次调用过滤器进行过滤,如>>> books = BookInfo.objects.filter(readcount__gt=30).order_by('pub_date') >>> books <QuerySet [<BookInfo: 天龙八部 >, <BookInfo: 雪山飞狐 >]>
也就意味着查问集能够含有零个、一个或多个过滤器。过滤器基于所给的参数限度查问的后果。
从 SQL 的角度讲,查问集与 select 语句等价,过滤器像 where、limit、order by 子句。
判断某一个查问集中是否有数据:
- exists():判断查问集中是否有数据,如果有则返回 True,没有则返回 False。
2 两大个性
2.1 惰性执行
创立查问集不会拜访数据库,直到调用数据时,才会拜访数据库,调用数据的状况包含迭代、序列化、与 if 合用
例如,当执行如下语句时,并未进行数据库查问,只是创立了一个查问集 books
books = BookInfo.objects.all()
继续执行遍历迭代操作后,才真正的进行了数据库的查问
for book in books:
print(book.name)
2.2 缓存
应用同一个查问集,第一次应用时会产生数据库的查问,而后 Django 会把后果缓存下来,再次应用这个查问集时会应用缓存的数据,缩小了数据库的查问次数。
状况一:如下是两个查问集,无奈重用缓存,每次查问都会与数据库进行一次交互,减少了数据库的负载。
from book.models import BookInfo
[book.id for book in BookInfo.objects.all()]
[book.id for book in BookInfo.objects.all()]
状况二:通过存储后,能够重用查问集,第二次应用缓存中的数据。
books=BookInfo.objects.all()
[book.id for book in books]
[book.id for book in books]
3 限度查问集
能够对查问集进行取下标或切片操作,等同于 sql 中的 limit 和 offset 子句。
留神:不反对正数索引。
对查问集进行切片后返回一个新的查问集,不会立刻执行查问。
如果获取一个对象,间接应用 [0],等同于[0:1].get(),然而如果没有数据,[0] 引发 IndexError 异样,[0:1].get()如果没有数据引发 DoesNotExist 异样。
示例:获取第 1、2 项,运行查看。
>>> books = BookInfo.objects.all()[0:2]
>>> books
<QuerySet [<BookInfo: 射雕英雄传 >, <BookInfo: 天龙八部 >]>
4. 分页
文档
# 查问数据
books = BookInfo.objects.all()
#导入分页类
from django.core.paginator import Paginator
#创立分页实例
paginator=Paginator(books,2)
#获取指定页码的数据
page_books = paginator.page(1)
#获取分页数据
total_page=paginator.num_pages
总结
以上就是 Django 第二局部,之后会继续更新,欢送大家点赞关注呀~~