(1)创建项目: django-admin startproject bookmanager
(2)创建应用:python manager.py startapp book
(3)更换python解释器:按需选择
# 进入指定虚拟环境
which python
# python2
/home/python/.virtualenvs/py_django/bin/python
# python3
/home/python/.virtualenvs/py3_django/bin/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)模板路径:在应用同级目录下,创建templates模板文件夹
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR,'template')],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
(7)项目中匹配urls
正则 : 路径只要不是admin/就算匹配成功。并包含到应用中的urls.py
from django.conf.urls import url,include
from django.contrib import admin
urlpatterns = [
url(r'^admin/', admin.site.urls),
#正则为:只要不是 admin/ 就算匹配成功
url(r'^',include('book.urls'))
]
(8)应用中匹配urls.py
正则 : 路径中包含booklist/,就调用视图中对应的bookList函数
from django.conf.urls import url
from book.views import bookList
urlpatterns = [
# 匹配书籍列表信息的URL,调用对应的bookList视图
url(r'^booklist/$',bookList)
]
(9)准备视图
from django.shortcuts import render
from django.http import HttpResponse,HttpRequest
# Create your views here.
# 定义视图:提供书籍列表信息
def bookList(request):
return HttpResponse('OK!')
(10)开启服务器, 测试项目
# 进入项目文件中, 开启项目对应的服务器
python manage.py runserver
# 浏览器中输入网址
http://127.0.0.1:8000/booklist/
在settings.py中保存了数据库的连接配置信息,Django默认初始配置使用sqlite数据库。
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
- 使用MySQL数据库首先需要安装驱动程序: pip install PyMySQL
- 在Django的工程同名子目录的__init__.py文件中添加如下语句
import pymysql
pymysql.install_as_MySQLdb()
作用是让Django的ORM能以mysqldb的方式来调用PyMySQL。
- 修改DATABASES配置信息
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'HOST': '127.0.0.1', # 数据库主机
'PORT': 3306, # 数据库端口
'USER': 'root', # 数据库用户名
'PASSWORD': 'mysql', # 数据库用户密码
'NAME': 'book' # 数据库名字
}
}
- 在MySQL中创建数据库
create database book charset=utf8;
- 模型类的定义
(1)数据库表名
模型类如果未指明表名,Django默认以小写app应用名_小写模型类名为数据库表名。
可通过db_table指明数据库表名。
(2)关于主键
django会为表创建自动增长的主键列,每个模型只能有一个主键列,如果使用选项设置某属性为主键列后django不会再创建自动增长的主键列。
默认创建的主键列属性为id,可以使用pk代替,pk全拼为primary key。
(3)属性命名限制
不能是python的保留关键字。
不允许使用连续的下划线,这是由django的查询方式决定的。
定义属性时需要指定字段类型,通过字段类型的参数指定选项,语法如下:
属性=models.字段类型(选项)
(4)字段类型
(5)选项
null是数据库范畴的概念,blank是表单验证范畴的
(6)外键
在设置外键时,需要通过on_delete选项指明主表删除数据时,对于外键引用表数据如何处理,在django.db.models中包含了可选常量:
CASCADE级联,删除主表数据时连通一起删除外键表中数据
PROTECT保护,通过抛出ProtectedError异常,来阻止删除主表中被外键应用的数据
SET_NULL设置为NULL,仅在该字段null=True允许为null时可用
SET_DEFAULT设置为默认值,仅在该字段设置了默认值时可用
SET()设置为特定值或者调用特定方法
DO_NOTHING不做任何操作,如果数据库前置指明级联性,此选项会抛出IntegrityError异常
在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)生成迁移文件:python manage.py makemigrations
(2)同步到数据库中:python manage.py migrate
- 添加测试数据
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:python manage.py shell
导入两个模型类,以便后续使用
from book.models import BookInfo,PeopleInfo
查看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方法
# 方式1:会把新生成的对象返回回来,需要手动调用save方法
book = BookInfo(
name = 'python',
pub_date = '2020-7-20'
)
book.save()
# 方式2:会把新生成的对象返回回来,直接入库
# objects模型的管理类,对模型的增删改查都可以用
BookInfo.objects.create(
name = 'java',
pub_date = '2020-7-20'
)
# 方式1
# 先查询获取数据,然后直接修改实例属性,再手动调用save方法
book = BookInfo.objects.get(id=1)
book.readcount = 20
book.save()
# 方式2
# 用模型类.objects.filter().update(),会返回受影响的行数
BookInfo.objects.filter(id=1).update(
readcount = 100,
commentcount = 200
)
# 方式1
# 先查询获取数据,然后直接删除实例属性,
book = BookInfo.objects.get(id=6)
book.delete()
2)模型类.objects.filter().delete()
# 方式2
# 模型类.objects.filter().delete()
BookInfo.objects.filter(id=5).delete()
(1)基础条件查询
1)基本查询get、all、count
# get 获取不到数据捕获异常信息
try:
book = BookInfo.objects.get(id=1)
except BookInfo.DoesNotExist:
pass
# all 以列表形式返回所有结果
BookInfo.objects.all()
# count 返回结果数量
BookInfo.objects.count()
2)过滤查询fileter、get、exclude
相当于where查询,SQL语句:select from bookinfo where 条件语句
fileter(字段名_运算符 = 值)
属性名称__比较运算符=值
①相等:exact(表示判等)
# exact(判相等):例:查询编号为1的图书。
BookInfo.objects.filter(id__exact=1)
# 可简写为:
BookInfo.objects.filter(id=1)
②模糊查询:contains(是否包含) 说明:如果要包含%无需转义,直接写即可。
# 查询书名包含'湖'的图书
BookInfo.objects.filter(name__contains='湖')
③startswith、endswith:以指定值开头或结尾。
# 查询书名以'部'结尾的图书
BookInfo.objects.filter(name__endswith='部')
注: 以上运算符都区分大小写,在这些运算符前加上i表示不区分大小写,如iexact、icontains、istartswith、iendswith.
3) 空查询:isnull(是否为null)
# 查询书名为空的图书
BookInfo.objects.filter(name__isnull=True)
4) 范围查询:in(是否包含在范围内)
# 查询编号为1或3或5的图书
BookInfo.objects.filter(id__in=[1,3,5])
5)比较查询: gt大于 (greater then)、gte大于等于 (greater then equal)、lt小于 (less then)、lte小于等于 (less then equal)
# 查询编号大于3的图书
BookInfo.objects.filter(id__gt=3)
# 查询编号大于等于3的图书
BookInfo.objects.filter(id__gte=3)
# 查询编号小于3的图书
BookInfo.objects.filter(id__lt=3)
# 查询编号小于等于3的图书
BookInfo.objects.filter(id__lte=3)
# 查询编号不等于3的图书
BookInfo.objects.exclude(id=3)
6)日期查询:year、month、day、week_day、hour、minute、second(对日期时间类型的属性进行运算)
# 查询1980年发表的图书
BookInfo.objects.filter(pub_date__year=1980)
# 查询1990年1月1日后发表的图书
BookInfo.objects.filter(pub_date__gt='1990-1-1')
(2)F(两个属性之间的比较)和Q对象(多个过滤器逐个调用)
1)F对象(两个属性之间的比较)
①导入F模块:from django.db.models import F
②语法:F(属性名)
(属性1__运算符=F(属性2))
from django.db.models import F
# 查询阅读量大于等于评论量的图书
BookInfo.objects.filter(readcount__gt=F('commentcount'))
# 查询阅读量大于2倍评论量的图书。
BookInfo.objects.filter(readcount__gt=F('commentcount')*2)
# 查询id大于2 并且 阅读量大于20的书籍
# 方式1:filter().filter()
BookInfo.objects.filter(readcount__gt=20).filter(id__lt=3)
# 方式2:filter(条件1,条件2)
BookInfo.objects.filter(readcount__gt=20,id__lt=3)
from django.db.models import Q
Q(属性名__运算符=值)
Q( )|Q( )
Q( )&Q( )
~Q( )
# 实现逻辑运算
from django.db.models import Q
# 逻辑运算or
# 查询id大于2 或者 阅读量大于20的书籍
BookInfo.objects.filter(Q(id__gt = 2)|Q(readcount__gt = 20))
# 逻辑运算and
# 查询id大于2 且 阅读量大于20的书籍
BookInfo.objects.filter(Q(id__gt = 2)&Q(readcount__gt = 20))
# 逻辑运算not
# 查询id不为3
BookInfo.objects.exclude(id = 3)
BookInfo.objects.filter(~Q(id=3))
from django.db.models import 聚合函数
# 查询图书的总阅读量
from django.db.models import Sum
BookInfo.objects.aggregate(Sum('readcount'))
# 默认升序
BookInfo.objects.all().order_by('readcount')
# 降序
BookInfo.objects.all().order_by('-readcount')
(4)关联查询
1)一到多的访问语法:主表模型(实例对象).从表模型类名小写_set.all()
书籍对人物是1:n
书籍中没有任何关于人物的字段
查询书籍为1的所有人物信息(已知主表数据,关联查询从表数据):
# 1.查询书籍
book = BookInfo.objects.get(id=1)
# 2.根据书籍查询关联查询书籍
book.peopleinfo_set.all()
2)由多到一的访问语法:从表模型(实例对象).外键
人物对书籍n:1
人物中有关于书籍的字段book id
通过人物查询对应的书籍信息(已知从表数据,关联查询主表数据)
# 1.查询人物信息
person = PeopleInfo.objects.get(id=1)
# 2.根据人物关联查询书籍信息
person.book
(5)关联过滤查询
1)1的条件查找n的访问语法:外键__从表字段__条件运算符=值
书籍对人物是1:n
需要从表数据,已知主表信息
# 查询书名为“天龙八部”的所有人物
people = PeopleInfo.objects.filter(book__name='天龙八部')
# 查询图书阅读量大于30的所有人物
people = PeopleInfo.objects.filter(book__readcount__gt=30)
2)由n的条件查找1的访问语法:从表模型类名小写__字段__条件运算符=值
人物对书籍n:1
需要主表数据,已知从表信息
# 查询书籍人物为‘郭靖’的图书
BookInfo.objects.filter(peopleinfo__name__exact = '郭靖')
# 简写为
BookInfo.objects.filter(peopleinfo__name= '郭靖')
(6)查询集QuerySet
1)概念
当调用如下过滤器方法时,Django会返回查询集(而不是简单的列表):
all():返回所有数据。
filter():返回满足条件的数据。
exclude():返回满足条件之外的数据。
order_by():对结果进行排序。
也就意味着查询集可以含有零个、一个或多个过滤器。过滤器基于所给的参数限制查询的结果。 判断某一个查询集中是否有数据:
exists():判断查询集中是否有数据,如果有则返回True,没有则返回False。
2)两大特性
①惰性执行
创建查询集不会访问数据库,直到调用数据时,才会访问数据库,调用数据的情况包括迭代、序列化、与if合用
例如,当执行如下语句时,并未进行数据库查询,只是创建了一个查询集books
books = BookInfo.objects.all()
继续执行遍历迭代操作后,才真正的进行了数据库的查询
for book in books:
print(book.name)
可以通过mysql日志证明
②缓存
使用同一个查询集,第一次使用时会发生数据库的查询,然后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异常。
文档
#查询数据
books = BookInfo.objects.all()
#导入分页类
from django.core.paginator import Paginator
#创建分页实例
paginator=Paginator(books,2)
#获取指定页码的数据
page_skus = paginator.page(1)
#获取分页数据
total_page=paginator.num_pages