django基础知识(三)
文章目录
静态文件
-
什么是静态文件:图片, css, js, 音频, 视频
-
静态文件配置 -settings.py中
-
配置静态文件的访问路径【该配置默认存在】
通过哪个url地址找静态文件:STATIC_URL = '/static/'
-
说明:
指定访问静态文件时是需要通过/static/xxx或http://127.0.0.1:8000/static/xxx [xxx表示具体的静态资源位置]
-
-
配置静态文件的存储路径 STATICFILES_DIRS
STATICFILES_DIRS保存的是静态文件在服务器端的存储位置#file: setting.py STATICFILES_DIRS = (os.path.join(BASE_DIR,"static"),)
-
-
静态文件访问:-img标签为例
-
方案一:直接拼接访问路径
<img src="/static/images/lena.jpg> #或 <img src="http://127.0.0.1:8000/static/images/lena.jpg>
-
√方案二:通过{% static %}标签访问静态文件
1.加载static-{% load static %} 2.使用静态资源-{% static '静态资源路径‘ %} e.g. <img src="{% static 'images/lena.jpg' %}>
-
Django应用及分布式路由
应用:
应用在Django项目中是一个独立的业务模块,可以包含自己的路由,视图,模块,模型
-
创建应用:
步骤1:用manage.py中的子命令startapp创建应用文件夹 python3 manage.py startapp music 步骤2:settings.py的INSTALLED_APPS列表中配置安装此应用 INSTALLED_APPS = [...,'user','music']
-
应用下的模板:
-
应用内部可以配置模板目录
1.应用下手动创建templates文件夹 2.settings.py中开启应用模板功能 TEMPLATE配置项中的'APP_DIRS'值为True即可
-
应用下templates和外层templates都存在时,django得查找模板规则
1.优先查找外层templates目录下的模板 2.按INSTALLED_APPS配置下的应用顺序逐层查找
-
分布式路由:
Django中,主路由由配置文件(urls.py)可以不处理用户具体路由,主路由由配置文件的可以做请求的分发(分布式请求处理)。具体的请求可以由各自的应用来进行处理
-
配置分布式路由:e.g.http://127.0.0.1:8000/music/index
步骤1:主路由中调用include函数:include('app名字.url模块名') from django.urls import include path('music/',include('music.urls')) -->作用:用于将当前路由转到各个应用的路由配置文件的urlpatterns进行分布式处理 步骤2:应用下配置urls.py 应用下手动创建urls.py文件 内容结构同主路由完全一样 path('index',views.index_view)
模型层及ORM介绍
模型层 -负责跟数据库之间进行通信
-
Django配置mysql
安装mysqlclient 创建数据库 进入MySQL数据库执行 cmd: mysql -uroot -p create database 数据库 default charset utf8 通常数据库名跟项目名保持一致 settings.py里进行数据库的配置 ENGINE - 指定数据库存储引擎:修改DATABASES配置项的内容,由sqlite3变为mysql NAME - 指定要连接的数据库的名字 USER - 指定登录到数据库的用户名 PASSWORD - 数据库密码 HOST/PORT - 连接具体数据库的IP和端口
-
什么是模型?
- 模型是一个Python类,它是由django.db.models.Model派生出的子类
- 一个模型类代表数据库中的一张数据表
- 模型类中每一个类属性都代表数据库中的一个字段
- 模型是数据交互的接口,是表示和操作数据库的方法和方式
ORM框架
-
定义:ORM(Object Relational Mapping)即对象关系映射,它是一种程序技术,它允许你使用类和对象对数据库进行操作,从而避免sql语句操作数据库
-
作用:
- 建立模型类和表之间的对应关系,允许我们通过面向对象的方式来操作数据库【不需要面向数据库】
- 根据设计的模型类生成数据库中的表格
- 通过简单的配置就可以进行数据库的切换【实现数据模型与数据库的解耦,屏蔽了不同数据库操作上的差异】
-
缺点:
- 对于复杂的业务,使用成本较高
- 根据对象的操作转换成sql语句,根据查询的结果转化成对象,在映射过程中有性能损失
-
框架
ORM DB
类 <---->数据表
对象<---->数据行
属性<----> 字段
模型示例:
此示例为添加一个bookstore_book数据表来存放图书馆中书目的信息
1.添加一个bookstore的app:
python manage.py startapp bookstore
2.添加模型类并注册app
from django.db import models
class 模型类名(models.Model)
字段名 = models.字段类型(字段选项)
3.数据库迁移
迁移是Django同步对模型所做更改(添加字段,删除模型等)到数据库模式的方式
生成迁移文件 - 执行 python manage.py makemigrations,将应用下的models.py文件生成一个中间文件,并保存在migrations文件夹中
执行迁移脚本程序 - 执行python manage.py migrate,执行迁移程序实现迁移。将每个应用下的migrations目录中的中间文件同步回数据库
ORM-基础字段及选项
模型类 - 字段类型
- BooleanField()
- 数据库类型:tinyint
- 编程语言中:使用True或False来表示值
- 在数据库中:使用1或0来表示具体的值
- CharField()
- 数据库类型:varchar
**注意:**必须指定max_length参数值
- 数据库类型:varchar
- DateField()
- 数据库类型:date
- 作用:表示日期
- 参数:只能三选一
- auto_now:每次保存对象时,自动设置该字段为当前时间(取值:True/False)
- auto_now_add:当对象第一次被创建时自动设置当前时间(取值:True/False)
- default:设置当前时间(取值:字符串格式时间如:‘2019-6-1’)
- DateTimeField()
- 数据库类型:datetime(6)
- 作用:表示日期和时间
- 参数同DateField
- FloatField()
- 数据库类型:double
- 编程语言中和数据库中都使用小数表示值
- DecimalField()
- 数据库类型:decimal(x,y)
- 编程语言中:使用小数表示该列的值
- 数据库中:使用小数表示该列的值
- 参数:
- max_digits:位数总数,包括小数点后的位数。该值必须大于等于decimal_places
- decimal_place:小数点后的数字数量
- EmailField()
- 数据库类型:varchar
- 编程语言和数据库中使用字符串
- IntegerField()
- 数据库类型:int
- 编程语言和数据库中使用整数
- ImageField()
- 数据库类型:varchar(100)
- 作用:在数据库中为保存图片的路径(编程语言和数据库中使用字符串)
- TextField()
- 数据库类型:longtext
- 作用:表示不定长的字符数据
模型类 - 字段选项
字段选项,指定创建的列的额外信息
允许出现多个字段选项,多个选项之间使用’,'隔开
- primary_key
如果设置为True,表示该列为主键,如果指定一个字段为主键,则此数库表不会创建id字段 - blank
当设置为True时,字段可以为空。设置为False时,字段是必须填写的 - null
如果设置为True,表示该列值允许为空
默认为False,如果此选项为False建议加入default选项来设置默认值 - default:
设置所在列的默认值,如果字段选项null=false建议添加此项 - db_index
如果设置为True,表示该列增加索引 - unique
如果设置为True,表示该字段在数据库中的值必须是唯一(不能重复出现) - db_column
指定列的名称,如果不指定的话则采用属性名作为列名 - verbose_name
设置此字段在admin界面上显示名称
字段选项样例:
name = models.CharField(max_length=20, unique=True,null=False,db_index=True)
模型类 - Meta类
-
定义:使用内部Meta类来给模型赋予属性,Meta类下有很多内建的类属性,可对模型类做一些控制
-
示例:
class Book(models.Model): ... class Meta: db_table = 'book' #可改变当前模型类对应的表名
ORM-基本操作
ORM-操作:
基本操作包括增删改查,即(CRUD操作)。
-
CRUD是指在做计算处理时的增加(create)、读取查询(Read)、更新(Update)和删除(Delete)
-
ORM DRUD核心 -> 模型类.管理器对象
- 管理器对象:
每个继承自models.Model的模型类,都会有一个objects对象被同样继承下来。这个对象叫管理器对象
数据库的增删改查可以通过模型的管理器实现
- 管理器对象:
*Django Shell
在Django提供了一个交互式的操作项目叫Django Shell 它能够在交互模式用项目工程的代码执行相应的操作。利用Django Shell可以代替编写view的代码来进行直接操作
**注意:**项目代码发生变化时,重写进入Django Shell
-
启动方式:
python manage.py shell (from bookstore.models import Author)
创建数据
Django ORM使用一种直观的方式把数据库表中的数据表示成Python对象,创建数据中每一条记录就是创建一个对象
方案一:MyModel.objects.create(属性1=值1,属性2=值2,...)
成功:返回创建好的实体对象
失败:抛出异常
方案二:创建MyModel实例对象,并调用save()进行保存
obj = MyModel(属性=值,属性=值)
obj.属性=值
obj.save()
查询操作
-
查询简介
数据库的查询需要使用管理器对象进行:MyModel.objects
-
all()
-
用法:
MyModel.objects.all()
-
作用:查询MyModel实体中所有的数据
-
等同于select * from tabe
-
返回值:QuerySet容器对象,内部存放MyModel实例
from bookstore.models import Book books = Book.objects.all() for book in books: print("书名",book.title,'出版社',book.pub)
-
*可在模型类中定义_str_方法,自定义QuerySet中的输出格式,
例如:在Book模型类中定义如下
def __str__(self): return '%s_%s_%s_%s'(self.title,self.price,self.pub,self.market_price)
-
-
-
values(‘列1’,‘列2’)
-
用法:
MyModel.objects.values(...)
-
作用:查询部分列的数据并返回
-
等同于select 列1,列2 from xxx
-
返回值:QuerySet容器对象,内部存放字典,每个字典代表一条数据,格式为:{‘列1’:值1,‘列2’:值2}
books = Book.object.values('title','pub') for book in books: print(book['title'])
-
-
values_list
-
用法:
MyModel.objects.values_list(...)
-
作用:返回元组形式的查询结果
-
等同于select 列1,列2 from xxx
-
返回值:QuerySet容器对象,内部存放’元组‘
books = Book.object.values_list('title','pub') for book in books: print(book[0])
-
-
order_by()
-
用法:
MyBody.objects.order_by('-列','列')
-
作用:与all()方法不同,他会用SQL语句的ORDER BY子句对查询结果进行根据某个字段选择性的进行排序
-
说明:默认是按照升序排序,降序排序则需要在列前增加’-'表示
a5 = MyBody.objects.values('title').order_by('-price') print(a5.query)--> SELECT 'book'.'title' FROM 'book' ORDER BY 'book'.'price' DESC
-
-
-
条件查询-方法
-
filter(条件)
-
语法:
MyBody.objects.filter(属性1=值1,属性2=值2)
-
作用:返回包含此条件的全部的数据集
-
返回值:QuerySet容器对象,内部存放MyModel实例
-
说明:当多个属性在一起时为“与”关系
authors = Author.objects.filter(name='王老师',age=28)
-
-
exclude(条件)
- 语法:
MyModel.objects.exclude(条件)
- 作用:返回不包含此 条件 的 全部的数据集
books = models.Book.objects.exclude(pub='清华大学出版社')
- 语法:
-
get(条件)
- 语法:
MyModel.objects.get(条件)
- 作用:返回满足条件的唯一一条数据
- 说明:
- 该方法只能返回一条数据,查询结果多于一条数据则抛出Model.MultipleObjectsReturned异常
- 查询结果如果没有数据,则抛出Model.DoseNotExit异常
- 语法:
- 查询谓词:类属性 + ‘’ + 谓词
-
定义:做更灵活的条件查询时需要使用查询谓词
-
说明:每一个查询谓词是一个独立的查询功能
__exact:等值匹配** Author.objects.filter(idexact=1) 等同于select * from author where id = 1 __contains:包含指定值** Author.objects.filter(name__contains='w') __startswith:以xxx开始 __endswith:以xxx结束 __gt:大于指定值 Author.objects.filter(age__gt=50) __gtr:大于等于 __lt:小于 __lte:小于等于 __in:查找数据是否在指定范围内 Author.objects.filter(country__in=['','','']) 等同于select * from author where country in ('','','') __range:查找数据是否在指定的区间范围内 Author.objects.filter(age__range=(35,50)) 等同于select ... WHERE Author BETWEEN 35 and 50
-
ORM-更新操作
-
更改单个数据
查:-通过get()得到要修改的实体对象 改:-通过 对象.属性 的方式修改数据 保存:-通过对象.save()保存数据
-
批量更新数据
直接调用QuerySet的update(属性=值)实现批量修改 books = Book.objects.filter(id__gt=3) books.update(price=0)
ORM-删除操作
-
单个数据删除
1.查找查询结果对应的一个数据对象 2.调用这个数据对象的delete()方法实现删除 try: author = Author.objects.get(id=1) author.delete() except: print(删除失败)
-
批量删除
1.查找查询结果集中满足条件的全部QuerySet查询集合对象 2.调用这个查询集合对象的delete()方法实现删除 author = Author.objects.filter(age_gt=65) author.delete()
-
伪删除
通常不会轻易在业务里把数据真正删除,取而代之的是做伪删除,
即在表中添加一个布尔型字段(is_active),默认是True;执行删除时,改成False
**注意:**用伪删除时,确保显示数据的地方,均加了 is_active=True的过滤查询
F对象和Q对象
F对象
一个F对象代表数据库中某条记录的字段的信息
-
作用:
-
通常是对数据库中的字段值在不获取的情况下进行操作
Book.objects.all().update(market_price=F('market_price')+10)
-
用于类属性(字段)之间的比较
示例:列出零售价高于定价的书from django.db.models import F from bookstore.models import Book books = Book.objects.filter(markert_price__gt=F('price'))
-
-
语法:
from django.db.models import F F('列名')
Q对象
当在获取查询结果集使用复杂的逻辑或|、逻辑非~等操作时可以借助于Q对象进行操作
from django.db.models import Q
Book.objects.filter(Q(price__lt=20)|Q(pub="清华大学出版社"))
-
语法:
from django.db.models import Q Q(条件1)|Q(条件2) #条件1成立或条件2成立 Q(条件1)&Q(条件2) #条件1和条件2同时成立 Q(条件1)&~Q(条件2) #条件1成立且条件2不成立
聚合查询和原生数据库操作
聚合查询
-
定义:聚合查询是指对一个数据表中的一个字段的数据进行部分或全部进行统计查询,查bookstore_book数据表中的全部书的平均价格,查询所有书的总个数等,都要使用聚合查询
-
聚合查询分为:
-
整表聚合
- 导入方法:
from django.db.models import *
- 聚合函数:Sum,Avg,Count,Max,Min
- 语法:
MyModel.objects.aggregate(结果变量名=聚合函数('列'))
- 返回结果:{“结果变量名”:值}
- 导入方法:
-
分组聚合
-
语法:QuerySet.annotate(结果变量名=聚合函数(‘列’))
-
返回值:QuerySet
-
用法:
1.通过先用查询结果MyModel.objects.values查找查询要分组聚合的列 MyModel.objects.values('列1','列2') 2.通过返回结果的QuerySet.annotate方法分组聚合得到分组结果 QuerySet.annotate(名=聚合函数('列'))
-
示例:
bs = Book.objects.values('pub') bs.annotate(res=Count('id')) --> <QuerySet [{'pub': '清华大学出版社', 'res': 2}, {'pub': '机械工业出版社','res': 2}]> bs.annotate(res=Count('id')).filter(res__gt=2)
-
-
原生数据库操作
Django也可以支持直接用sql语句的方式通信数据库
-
查询:使用
MyModel.objects.raw()
进行数据库查询操作查询 -
语法:
MyModel.objects.raw(sql语句,拼接参数)
-
返回值:RawQuerySet集合对象【只支持基础操作,比如循环】
books = models.Book.objects.raw('select * from bookstore_book') for book in books: print(book);
-
SQL注入
-
定义:用户通过数据上传,将恶意的sql语句提交给服务器,从而达到攻击效果
-
示例:
s1 = Book.objects.raw('select * from bookstore_book where id=%s'%('1 or 1=1')) --id = 3 or 1 = 1 -->s2 = Book.objects.raw('select * from bookstore_book where id=%s'['3 or 1=1']) --id = '3 or 1=1'
-
-
原生数据库操作-cursor
完全跨过模型类操作数据库? - 查询/更新/删除
1.导入cursor所在的包 from django.db import connection 2.用创建cursor类的构造函数创建cursor对象,再使用cursor对象,为保证在出现异常时能释放cursor资源, 通常使用with语句进行创建操作 with connextion.cursor() as cur: cur.execute('执行SQL语句','拼接参数')