Django框架学习笔记
本文讲解"Django框架学习笔记",用于解决相关问题。
django框架
MVC框架
简介
MVC的产生理念:分工。让专门的人去做专门的事。
MVC的核心思想:解耦
M:model模型,和数据库进行交互
V:view视图,产生HTML页面
C:controller控制器,接收请求,进行处理,与M,V进行交互,返回应答
Django的MVT框架
本质上还是MVC的思想
M:model模型,和MVC中M功能相同,和数据库进行交互
V:View视图,和MVC中C功能相同,接收请求,进行处理,与M和T进行交互,返回应答
T:template模板,和MVC中V功能相同,产生HTML页面
虚拟环境
pip install virtualenv #安装虚拟环境 pip install virtualenvwrapper #安装虚拟环境扩展包 vim .bashrc #添加以下两行 export WORKON_HOME=$HOME/.vitualenvs source /usr/bin/virtualenvwrapper.sh 使用source .bashrc使其生效 创建python3虚拟环境 mkvirtualenv -p python3 虚拟环境名 workon 虚拟环境名 #进入虚拟环境 deactivate #退出虚拟环境
项目创建
命令:django-admin startproject myobj
项目下各文件说明
init:说明myobj是一个python包
settings.py:项目的配置文件
urls.py:进行url路由的配置
wsgi.py:web服务器和Django交互的入口
manage.py:项目的管理文件
应用创建
命令:python manage.py startapp appname
应用下生成的文件说明
init .py:说明目录是一个Python模块
models.py:写和数据库项目的内容
views.py:接收请求,进行处理,与M和T进行交互,返回应答。定义处理函数,视图函数
test.py:写测试代码文件
admin.py:网站后台管理相关的文件
建立应用和项目之间的联系,需要对应用进行注册
修改settings.py的INSTALLED_APPS的内容,添加应用名字
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'test1', ]
运行一个应用
python manage.py runserver 访问127.0.0.1:8000可以查看创建的应用
后台管理
本地化
语言和时区的本地化
修改settings.py文件
LANGUAGE_CODE = 'zh-hans' #使用中文 TIME_ZONE = 'Asia/Shanghai' #中国时区
创建管理员
命令:python manage.py createsuperuser 登录后台 浏览器输入"127.0.0.1/admin"进入后台管理页面
注册模型类
在应用下的admin.py下注册模型类
告诉Django框架根据注册的模型来生成对应表管理页面
b=Bookinfo()
str(b)
列表页选项
页大小
- 每页中显示多少条数据,默认为每页显示100条数据,属性如下:
list_per_page=100
打开booktest/admin.py文件,修改AreaAdmin类如下:class AreaInfoAdmin(admin.ModelAdmin): '''地区模型管理类''' list_per_page=10 #指定每页显示10条数据
操作选项的位置
顶部显示的属性,设置为True在顶部显示,设置为False不在顶部显示,默认为True
actions_on_top=True
底部显示的属性,设置为True在底部显示,设置为False不在底部显示,默认为False
actions_on_bottom=False列表中的列
属性如下:
list_display=[模型字段1,模型字段2,...]
方法列是不能排序的,如果需要排序需要为方法指定排序依据
admin_order_field=模型类字段
打开booktest/models.py文件,修改AreaInfo类如下:class AreaInfo(models.Model): ... def title(self): return self.atitle title.admin_order_field='atitle'
列标题
列标题默认为属性或方法的名称,可以通过属性设置。需要先将模型字段封装成方法,再对方法使用这个属性,模型字段不能直接使用这个属性
short_description='列标题'
vim booktest/models.py文件,修改AreaInfo类如下:class AreaInfo(models.Model): ... title.short_description='区域名称'
右侧栏过滤器
属性如下,只能接收字段,会将对应字段的值列出来,用于快速过滤。一般用于有重复值的字段。
list_filter=[]搜索框
属性如下,用于对指定字段的值进行搜索,支持模糊查询。列表类型,表示在这些字段上进行搜索。
search_fields=[]编辑页选项
显示字段顺序
属性如下:
fields=[]
vim booktest/admin.pyclass AreaAdmin(admin.ModelAdmin): ... fields=['aprent','atitle']
分组显示
属性如下:
fieldset=( ('组1标题',{'fields':('字段1','字段2')}), ('组2标题',{'fields':('字段3','字段4')}), )
vim booktest/admin.py文件,修改AreaAdmin类如下:
class AreaAdmin(admin.ModelAdmin): ... #fields=['aparent','atitle'] fieldsets=( ('基本',{'fields':['atitle']}), ('高级',{'fields':['aparent']}) )
关联对象
在一对多的关系中,可以在一端的编辑页面中编辑多端的对象,嵌入多端对象的方式包括表格、块两种。类型InlineModelAdmin:表示在模型的编辑页面嵌入关联模型的编辑。子类Tabularlnline:以表格的形式嵌入。子类StackedInline:以块的形式嵌入。
打开booktest/admin.py文件,创建AreaStackedInline类。class AreaStackedInline(admin.StackedInline): model=AreaInfo #关联子对象 extra=2 #额外编辑2个子对象
打开booktest/admin.py文件,修改AreaAdmin类如下:
class AreaAdmin(admin.ModelAdmin): ... inlines=[AreaStackedInline]
orm框架
Object:对象-类
Mapping:映射,建立类与表的对应关系
Relation:关系,关系数据库中的表
Django中内嵌了orm框架,orm框架可以通过类和对象操作对应的数据表,不需要写sql语句
django orm框架的功能
- 建立模型和表之间的对应关系,允许我们通过面向对象的方式来操作数据库
- 根据设计的模型类生成数据库中的表格。
- 通过方便的配置就可以进行数据库的切换
设计类:模型类
创建模型类
#图书类 class BookInfo(models.Model): '''图书模型类''' #图书名称,Charfield说明是一个字符串,max_length指定字符串的最大长度 btitle=models.CharField(max_length=20) #出版日期,DateField说明是一个日期类型 bpub_date=models.DateField()
orm另外一个作用:根据设计的类生成数据库中的表
模型类生成表
- 生成迁移文件
命令:python manage.py makemigrations
迁移文件是根据模型类生成的 - 执行迁移生成表
命令:python manage.py migrate
通过模型类操作数据表
往表中添加数据
python manage.py shell
>>> from test1.models import BookInfo >>> b=BookInfo() >>> b.btitle='天龙八部' >>> from datetime import date >>> b.bpub_date=date(1990,1,1) >>> b.save() >>> BookInfo.objects.get(id=1) <BookInfo: BookInfo object (1)> >>> b2=BookInfo.objects.get(id=1) >>> b2.btitle '天龙八部' >>> b2.bpub_date datetime.date(1990, 1, 1) >>> b2.id 1 >>> b2.bpub_date=date(2019,1,1) >>> b2.save() >>> b3=BookInfo.objects.get(id=1) >>> b3.bpub_date datetime.date(2019, 1, 1) >>> b2.delete() (1, {'test1.BookInfo': 1})
模型类关系和模型查询
vim models.py
class HeroInfo(models.Model): hname =models.CharField(max_length=20) #英雄名称 #性别,Booleanfield说明是bool类型,default指定默认值,False代表男 hgender=models.BooleanField(default=False) #备注 hcomment=models.CharField(max_length=128) #关系属性 hbook,建立图书类和英雄人物类之间的一对多关系 #关系属性对应的表的字段名格式:关系属性名_id hbook=models.ForeignKey('BookInfo',on_delete=models.CASCADE,)
生成迁移文件
python3 manage.py makemigrations
执行迁移文件生成表
python3 manage.py migrate
往表中操作数据
python manage.py shell
from test1.models import BookInfo,HeroInfo b=BookInfo() b.btitle='天龙八部' from datetime import date b.bpub_date=date(1990,1,1) b.save() h=HeroInfo() h.hname='段誉' h.hgender=False h.hcomment='六脉神剑' h.hbook=b h.save() h3=HeroInfo() h3.hname='乔峰' h3.hcomment='降龙十八掌' h3.hbook=b h3.save() h4=HeroInfo.objects.get(id=2) h4.hname '乔峰' h4.hgender False h4.hcomment '降龙十八掌' h4.hbook_id 3 h4.hbook.btitle '天龙八部'
模型类属性命名限制
- 不能是python保留的关键字
- 不允许使用连续的下划线,这是由Django的查询方式决定的
- 定义属性时需要指定字段类型,通过字段类型的参数指定选项,语法如下:
属性名=models.字段类型(选项)字段类型
使用时需要引入django.db.models包,字段类型如下:
类型 | 描述 |
---|---|
AutoField | 自动增长的integerfield,通常不用指定,不指定是Django会自动创建属性名为id的自动增长属性 |
BooleanField | 布尔字段,值为True或False |
NullBooleanField | 支持Null、True、False三种值 |
CharField(max_length=最大长度) | 字符串,参数max_length表示最大字符个数 |
TextField | 大文本字段,一般超过4000个 |
IntegerField | 整数 |
DecimalField(max_digits=None,decimal_place=None) | 十进制浮点数。参数max_digits表示总位。参数decimal_places表示小数位数 |
FloatField | 浮点数。参数同上 |
DateField:([auto_now=False,auto_now_add=False]) | 日期。1.参数auto_now表示每次保存对象时,自动设置该字段为当前时间,用于“最后一次修改”的时间戳,他总是使用当前日期,默认为false。2.参数auto_now_add表示当对象第一次被创建时自动设置当前时间,用于创建的时间戳,他总是使用当前日期,默认为false。3.参数auto_now_add 和auto_now是相互排斥的,组合将会发生错误。 |
TimeField | 时间,参数同datefield |
DateTimeField | 日期时间,参数同DateField |
FileField | 上传文件字段 |
ImageField | 继承于FileField,对上传的内容进行校验,确保是有效的图片 |
选项
通过选项实现对字段的约束,选项如下:
选项名 | 描述 |
---|---|
default | 默认值,设置默认值 |
primary_key | 若为True,则该字段会成为模型的主键字段,默认值为false,一般作为autofield的选项使用 |
unique | 如果为True,这个字段在表中必须唯一值,默认值是false |
db_index | 若值为True,则在表中会为此字段创建索引,默认值是false |
db_column | 字段的名称,如果未指定,则使用属性的名称 |
null | 如果为True,表示允许为空,默认值是false |
blank | 如果为True,则该字段允许为空白,默认值是false |
MVT综合案例
vim test1/urls.py
urlpatterns =[ #通过url函数设置url路由配置项 url(r'^index$',views.index), # 建立index和视图之间的关系 url(r'^index2$',views.index2), url(r'^books$',views.show_books), #显示图书信息 url(r'^books/(\d+)$',views.detail), #显示英雄信息 ]
vim views.py
def show_books(request): '''显示图书的信息''' #1.通过M查找图书表中的数据 books=BookInfo.objects.all() #2.使用模板 return render(request,'test1/show_books.html',{'books':books}) def detail(request,bid): '''查询图书关联英雄信息''' #1.根据bid查询图书信息 book=BookInfo.objects.get(id=bid) #2.查询和book关联的英雄信息 heros=book.heroinfo_set.all() #3.使用模板 return render(request,'test1/detail.html',{'book':book,'heros':heros})
vim templates/test1/show_books.html
<!DOCTYPE> <html lang="en"> <head> <meta charset="UTF-8"> <title>显示图书信息</title> </head> <body> 图书信息如下: <ul> {% for book in books %} <li><a href="/books/{{ book.id }}">{{ book.btitle }}</a></li> {% endfor %} </ul> </body> </html>
vim detail.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>显示图书关联的英雄信息</title> </head> <body> <h2>{{ book.btitle }}</h2> 英雄信息如下:<br/> <ul> {% for hero in heros %} <li>{{ hero.hname }}--{{ hero.hcomment }}</li> {% empty %} <li>没有英雄信息</li> {% endfor %} </ul> </body> </html>
配置使用mysql数据库
vim settings.py
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'booktest', #注册应用 ] DATABASES = { 'default': { #'ENGINE': 'django.db.backends.sqlite3', #'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), 'ENGINE': 'django.db.backends.mysql', 'NAME': 'booktest', #使用的数据库名字 'USER': 'root', #mysql用户名 'PASSWORD': 'root', #mysql密码 'HOST': 'localhost', #mysql主机 'PORT': 3306, } }
创建数据库
create database booktest charset=utf8;
安装pymysql
pip install pymysql
vim __init__.py
ALLOWED_HOSTS = ['60.205.177.168']
后台管理
- 本地化
- 语言和时区的本地化,修改settings.py文件
- 创建管理员
- 命令:Python manage.py createsuperuser
- 注册模型类
- 在应用下的admin.py中注册模型类
- 告诉Django框架根据注册的模型类来生成对应表管理页面
from test1.models import BookInfo # Register your models here. #注册模型类 admin.site.register(BookInfo)
vim models.py
class BookInfo(models.Model): '''图书模型类''' btitle=models.CharField(max_length=20) #出版日期,DateField说明是一个日期类型 bpub_date=models.DateField() def __str__(self): #返回书名 return self.btitle
- 自定义管理页面
自定义模型管理类。模型管理类就是告诉Django在生成的管理页面上显示哪些内容
class BookInfoAdmin(admin.ModelAdmin): '''图书模型管理类''' list_display=['id','btitle','bpub_date'] class HeroInfoAdmin(admin.ModelAdmin): '''英雄模型人物类''' list_display=['id','hname','hcomment'] #注册模型类 admin.site.register(BookInfo,BookInfoAdmin) admin.site.register(HeroInfo,HeroInfoAdmin)
视图
在Django中,通过浏览器去请求一个页面时,使用视图函数来处理这个请求的,视图函数处理之后,要给浏览器返回页面内容
返回HTML内容httpresponse,也可能重定向redirect
视图函数的使用
定义视图函数
视图函数定义在views.py中
视图函数必须有一个参数request,是一个httprequest类型的对象,参数名可以变化,进行处理之后,需要返回一个HttpResponse的类对象,hello,python就是返回给浏览器显示的内容
例:
from django.shortcuts import render from django.http import HttpResponse # Create your views here. #1.定义视图函数,HttpRequest #2.进行url配置,建立url地址和视图的对应关系 #http://127.0.0.1:8000/index def index(request): #进行处理,和M,T进行交互 return HttpResponse('老铁没毛病') def index2(request): return HttpResponse('hello python')
进行url配置
- 所有的url配置项都定义在一个叫做urlpatterns的列表中,每一个元素都是一个配置项
- 每一个配置项都会调用url函数,第一个参数是正则表达式,第二个参数是对应的处理动作,可以写一个视图函数的名字
- 和url字符串进行正则匹配,匹配成功则执行其后对应的处理动作
- 对应的动作可以是一个视图函数的名字,也可以是包含一个应用的urls.py文件
url配置的目的是建立url和视图函数的对应关系。url配置项定义在urlpatterns的列表中,每一个配置项都调用url函数。
url函数有两个参数,第一个参数是一个正则表达式,第二个是对应的处理动作。
配置url时,有两种语法格式:
- url(正则表达式,视图函数名)
- url(正则表达式,include(应用中的urls文件))
工作中在配置url时,首先在项目的urls.py文件中添加配置项时,并不写具体的url和视图函数之间的对应关系,而是包含具体应用的urls.py文件,在应用的urls.py文件中写url和视图函数的对应关系。url匹配的过程
在项目的urls.py文件中包含具体应用的urls.py文件,应用的urls.py文件中写url和视图函数的对应关系
当用户输入如127.0.0.1:8000/index时,去除域名和最前面的/,剩下index,拿index字符串到项目的urls文件中进行匹配,配置成功之后,继续到项目中的urls文件中进行正则匹配,匹配成功之后执行视图函数index,index视图函数返回内容hello python 给浏览器来显示
vim /myobj/urls.pyfrom django.contrib import admin #from django.urls import path from django.conf.urls import include,url urlpatterns = [ url(r'^admin/',admin.site.urls),#配置项 url(r'^',include('test1.urls')) #包含test1应用中的urls文件 ]
vim test1/urls.py
from django.conf.urls import url from test1 import views # /index #在应用的urls文件中进行url配置的时候: #1.严格匹配开头和结尾 urlpatterns =[ #通过url函数设置url路由配置项 url(r'^index$',views.index), # 建立index和视图之间的关系 url(r'^index2$',views.index2), ]
错误视图
404:找不到页面,关闭调试模式之后,默认会显示一个标准的错误页面,如果要显示自定义的页面,则需要templates目录下面自定义一个404.html文件
- url没有配置
- url配置错误
500:服务器端的错误 - 视图出错
网站开发完成需要关闭调试模式,在settings.py文件中: - DEBUG=False
- ALLOWED_HOST=['*']
捕获url参数
进行url匹配时,把所需要的捕获的部分设置成一个正则表达式组,这样Django框架就会自动把匹配成功后相应组的内容作为参数传递给视图函数。
- 位置参数
- 位置参数,参数名可以随意指定
vim booktest/urls.pyfrom django.conf.urls import url from booktest import views urlpatterns = [ url(r'^index$',views.index), #首页, url(r'^showarg(\d+)$',views.show_arg), #捕获url参数 ]
vim test3/urls.py
urlpatterns = [ path('admin/', admin.site.urls), url(r'^',include('booktest.urls')), ]
vim booktest/views.py
from django.shortcuts import render from django.http import HttpResponse # Create your views here. def index(request): '''首页''' return render(request,'booktest/index.html') def show_arg(request,num): return HttpResponse(num)
- 位置参数,参数名可以随意指定
- 关键字参数:在位置参数的基础上给正则表达式组命名即可
- ?P<组名>
- 关键字参数,视图中参数名必须和正则表达式组名一致
vim booktest.urlsfrom django.conf.urls import url from booktest import views urlpatterns = [ url(r'^index$',views.index), #首页, url(r'^showarg(\d+)$',views.show_arg), #捕获url参数:位置参数 url(r'^showarg(?P<num>\d+)$',views.show_arg), #捕获关键字参数 ]
登录案例
- 显示出登录页面
- 设计url,通过浏览器访问http://127.0.0.1:8000/login时显示登录页面
- 设计url对应的视图函数login
- 编写模板文件login.htnl
vim booktest/urls.pyfrom django.conf.urls import url from booktest import views urlpatterns = [ url(r'^index$',views.index), #首页, url(r'^showarg(\d+)$',views.show_arg), #捕获url参数:位置参数 url(r'^showarg(?P<num>\d+)$',views.show_arg), #捕获关键字参数 url(r'^login$',views.login), #显示登录页面 url(r'^login_check$',views.login_check), ]
vim login.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>登录页面</title> </head> <body> <form method="post" action="/login_check"> 用户名:<input type="text" name="username"><br/> 密码:<input type="password" name="password"><br/> <input type="submit" value="登录"> </form> </body> </html>
url | 视图 | 模板文件 |
---|---|---|
/login | login | login.html |
- 登录校验功能
- 设计url,点击登录页的登录按钮发起请求http://127.0.0.1:8000/login_check
- 设计url对应的视图函数login_check。接收表单提交过来的数据
注释掉settings.py文件的47行
vim booktest/views.py
from django.shortcuts import render,redirect from django.http import HttpResponse # Create your views here. def index(request): '''首页''' return render(request,'booktest/index.html') def show_arg(request,num): return HttpResponse(num) def login(request): '''显示登录页面''' return render(request,'booktest/login.html') def login_check(request): '''登录校验视图''' #request.POST保存的是post方式提交的参数 QueryDict # request.GET保存的是get方式提交的参数 #1. 获取提交的用户名和密码 username=request.POST.get('username') password=request.POST.get('password') #2. 进行登录的校验 #实际开发:根据用户和密码查找数据库 #模拟:smart 123 if username=='smart' and password=='123': #用户名密码正确,跳转到首页 return redirect('/index') else: #用户名或密码错误,跳转到登录页面 return redirect('/login')
HttpRequest对象的属性
- path:一个字符串,表示请求的页面的完整路径,不包含域名和参数部分
- method:一个字符串,表示请求使用的HTTP方法,常用值包括:'GET'、'POST'
- 在浏览器中给出地址发出请求采用get方式,如超链接
- 在浏览器中点击表单的提交按钮发起请求,如果表单的method设置为post则为post请求
- encoding:一个字符串,表示提交的数据的编码方式
- 如果为none则表示使用浏览器的默认设置,一般为utf-8
- 这个属性是可写的,可以通过修改他来修改访问表单数据使用的编码,接下来对属性的任何访问将使用新的encoding值
- GET:QueryDict类型对象,类似于字典,包含get请求方式的所有参数
- POST:QueryDict类型对象,类似于字典,包含post请求方式的所有参数
- FILES:一个类似于字典的对象,包含所有的上传文件
- COOKIES:一个标准的python字典,包含所有的cookie,键和值都为字符串
- session:一个既可读又可写的类似于字典的对象,表示当前的对话,只有当Django启用会话的支持时才可用,详细内容见“状态保持”
- 运行服务器,在浏览器中浏览首页,可以在浏览器“开发者工具”中看到请求信息如下图
Ajax登录案例
- 首先分析出请求地址时需要携带的参数
- 视图函数处理完成之后,所返回的json格式
- 显示出登录页面
- 设计url,通过浏览器访问http://127.0.0.1:8000/login_ajax时显示登录页面
- 设计url对应的视图函数login_ajax
- 编写模板文件login_ajax.html。在里面写jQuery代码发起ajax请求
- 登录校验功能
- 设计url,点击登录页的登录按钮发起请求,http://127.0.0.1:8000/login_ajax_check时进行登陆校验
- 设计url对应的视图函数login_ajax_check,接收一个提交过来的数据
- 显示出登录页面
状态保持
cookie
cookie是由服务器生成,存储在浏览器端的一小段文本信息
cookie的特点
- 以键值对方式进行存储
- 通过浏览器访问同一个网站时,会将浏览器存储的跟网站相关的所有cookie信息发送给该网站的服务器。request.COOKIES
- cookie是基于域名安全的
- cookie是有过期时间的,如果不指定,默认关闭浏览器之后cookie就会过期
cookie请求的步骤
- 服务端接收浏览器发送来的请求并进行处理
- 设置cookie,需要一个HTTPresponse类的对象,或者是它子类的对象,将cookie发送给浏览器保存
- 浏览器将cookie发送给服务器,保存request对象的COOKIES
vim booktest/urls.py
from django.shortcuts import render,redirect from django.http import HttpResponse from datetime import datetime,timedelta # /set_cookie def set_cookie(request): '''设置一个cookie信息''' response=HttpResponse('设置cookie') # 设置一个cookie信息,名字为num,值为1 response.set_cookie('num',1,max_age=14*24*3600) #response.set_cookie('num', 1, expires=datetime.now()+timedelta(days=14)) #返回response return response # /get_cookie def get_cookie(request): '''获取cookie的信息''' #取出cookie num的值 num=request.COOKIES['num'] return HttpResponse(num)
vim booktest/urls.py
urlpatterns = [ url(r'^index$',views.index), #首页, url(r'^showarg(\d+)$',views.show_arg), #捕获url参数:位置参数 url(r'^showarg(?P<num>\d+)$',views.show_arg), #捕获关键字参数 url(r'^login$',views.login), #显示登录页面 url(r'^login_check$',views.login_check), url(r'^set_cookie$',views.set_cookie), #设置cookie url(r'^get_cookie$',views.get_cookie), #获取cookie ]
记住用户名的案例
vim login.html
<form method="post" action="/login_check"> 用户名:<input type="text" name="username" value="{{ username }}"><br/> 密码:<input type="password" name="password"><br/> <input type="checkbox" name="remember">记住用户名<br/> <input type="submit" value="登录"> </form>
vim booktest/views.py
def login(request): '''显示登录页面''' #获取cookie username if 'username' in request.COOKIES: #获取记住的用户名 username = request.COOKIES['username'] else: username='' return render(request,'booktest/login.html',{'username':username}) def login_check(request): '''登录校验视图''' #request.POST保存的是post方式提交的参数 QueryDict # request.GET保存的是get方式提交的参数 #1. 获取提交的用户名和密码 username=request.POST.get('username') password=request.POST.get('password') remember=request.POST.get('remember') #2. 进行登录的校验 #实际开发:根据用户和密码查找数据库 #模拟:smart 123 if username=='smart' and password=='123': #用户名密码正确,跳转到首页 response=redirect('/index') #判断是否需要记住用户名 if remember == 'on': #设置cookie username,过期时间为一周 response.set_cookie('username',username,max_age=7*24*3600) return response else: #用户名或密码错误,跳转到登录页面 return redirect('/login')
session
session存储在服务器端
session的特点
- session是以键值对进行存储的
- session依赖于cookie。唯一的标识码保存在sessionid cookie中
- session也是有过期时间,如果不指定,默认两周就会过期
设置session
vim booktest/views.py
#/set_session def set_session(request): '''设置session''' request.session['username']='smart' request.session['age']=18 return HttpResponse('设置session') #/get_session def get_session(request): '''获取session''' username=request.session['username'] age=request.session['age'] return HttpResponse(username+':'+str(age)) #/clear_session def clear_session(request): '''清除session信息''' #request.session.clear() request.session.flush() #del request.session['age'] return HttpResponse('清除成功')
vim booktest/urls.py
url(r'^set_session$',views.set_session), #设置session url(r'^get_session$',views.get_session), #获取session url(r'^clear_session$',views.clear_session), #清除session
设置会话的超时时间
如果没有指定过期时间则两个星期后过期
request.sesion.set_expiry(value)
- 如果value是一个整数,会话的session_id cookie将在value秒没有活动后过期
- 如果value为0,那么用户会话的session_id cookie将在用户的浏览器关闭时过期
- 如果value为None,那么会话的session_id cookie两周之后过期
记住用户登录状态案例
vim views.py
def login(request): '''显示登录页面''' #判断用户是否登录 if request.session.has_key('islogin'): return redirect('/index') else: #用户未登录 #获取cookie username if 'username' in request.COOKIES: #获取记住的用户名 username = request.COOKIES['username'] else: username='' return render(request,'booktest/login.html',{'username':username}) def login_check(request): '''登录校验视图''' #request.POST保存的是post方式提交的参数 QueryDict # request.GET保存的是get方式提交的参数 #1. 获取提交的用户名和密码 username=request.POST.get('username') password=request.POST.get('password') remember=request.POST.get('remember') #2. 进行登录的校验 #实际开发:根据用户和密码查找数据库 #模拟:smart 123 if username=='smart' and password=='123': #用户名密码正确,跳转到首页 response=redirect('/index') #判断是否需要记住用户名 if remember == 'on': #设置cookie username,过期时间为一周 response.set_cookie('username',username,max_age=7*24*3600) #记住用户登录状态 #只有session中有islogin,就认为用户已登录 request.session['islogin']=True return response else: #用户名或密码错误,跳转到登录页面 return redirect('/login')
cookie和session的应用场景
- cookie:记住用户名,安全性要求不高
- session:涉及到安全性要求比较高的数据
模板
模板的功能
- 产生html,控制页面上展示的内容。模板文件不仅仅是一个html文件。模板文件包含两部分内容:
- 静态内容:css,js,html
- 动态内容:用于动态去产生一些网页内容。通过模板语言来产生
模板文件的使用
通常是在视图函数中使用模板产生html内容返回给客户端
- 创建模板文件夹
在项目目录下创建一个文件夹 - 配置模板目录
vim settings.py'DIRS': [os.path.join(BASE_DIR,'templates')],
- 使用模板文件
- 加载模板文件loader.get_template
去模板目录下面获取HTML文件的内容,得到一个模板对象 - 定义模板上下文RequeseContext
向模板文件传递数据 - 模板渲染产生html页面内容render
用传递的数据替换相应的变量,得到一个替换后的标准的HTML内容
- 加载模板文件loader.get_template
模板文件加载顺序
django.template.loaders.filesystem.Loader:/root/wanger/test4/templates/booktest/index2.html(来源不存在) django.template.loaders.app_directories.Loader:/root/.virtualenvs/wanger/lib/python3.5/site-packages/django/contrib/admin/templates/booktest/index2.html(来源不存在) django.template.loaders.app_directories.Loader:/root/.virtualenvs/wanger/lib/python3.5/site-packages/django/contrib/auth/templates/booktest/index2.html(来源不存在)
- 首先去配置的模板目录下面去找模板文件
- 去INSYALL_APPS下面的每个应用的去找模板文件,前提是应用中必须有templates文件夹
模板语言
模板语言简称为DTL(Django template language)
模板变量
模板变量名是由数字,字母,下划线和点组成的,不能以下划线开头
模板变量使用:{{ 模板变量名 }}
模板变量的解析顺序:
例如:{{ book.btitle }}
- 首先把book当成一个字典,把btitle当成键名,进行取值book['btitle']
- 把book当成一个对象,把btitle当成属性,进行取值book.btitle
- 把book当成一个对象,把btitle当成对象的方法,进行取值book.btitle
例如:{{book.0}} - 首先把book当成一个字典,把0当成键名,进行取值book[0]
- 把book当成一个列表,把0当成下标,进行取值book[0]
如果解析失败,则产生内容时用空字符串填充模板变量
使用模板变量时,前面的可能是一个字典,可能是一个对象,还可能是一个列表
vim models.py
from django.db import models # Create your models here. class BookInfo(models.Model): '''图书模型类''' #图书名称 btitle=models.CharField(max_length=20,db_column='btitle') #出版日期 bpub_date=models.DateField() #阅读量 bread=models.IntegerField(default=0) #评论量 bcomment=models.IntegerField(default=0) #删除标记 isdelete=models.BooleanField(default=False)
vim views.py
from booktest.models import BookInfo # /temp_var def temp_var(request): '''模板变量''' my_dict={'title':'字典键值'} my_list=[1,2,3] book=BookInfo.objects.get(id=1) #定义模板上下文 context={'my_dict':my_dict,'my_list':my_list,'book':book} return render(request,'booktest/temp_var.html',context)
vim urls.py
from django.conf.urls import url from booktest import views urlpatterns = [ url(r'^temp_var$',views.temp_var),#模板变量 ]
vim temp_var.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>模板变量</title> </head> <body> 使用字典属性:{{ my_dict.title }}<br/> 使用列表元素:{{ my_list.1 }}<br/> 使用对象属性:{{ book.btitle }}<br/> </body> </html>
模板标签
模板代码段:{% 代码段 %}
for循环:
{% for i in list %}
列表不为空时执行
{% empty %}
列表为空时执行
{% endfor %}
可以通过{{ forloop.counter }}得到for循环遍历到了第几次
vim urls.py
from django.conf.urls import url from booktest import views urlpatterns = [ url(r'^temp_tags$',views.temp_tags), ]
vim views.py
# /temp_tags def temp_tags(request): '''模板标签''' #1. 查找所有图书的信息 books=BookInfo.objects.all() return render(request,'booktest/temp_tags.html',{'books':books})
vim temp_tags.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>模板标签</title> </head> <body> <ul> {% for book in books %} <li>{{ forlop.counter }}--{{ book.btitle }}</li> {% endfor %} </ul> </body> </html>
{% if 条件 %} {% elif 条件 %} {% else %} {% endif %}
关系比较操作符:< > <= >= !=
注意:进行比较时,比较操作符两边必须有空格
逻辑运算:not and or
vim temp_tags.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>模板标签</title> <style> .red { background-color: red; } .yellow { background-color: yellow; } .green { background-color: green; } </style> </head> <body> <ul> {% for book in books %} {% if book.id <= 2 %} <li class="red">{{ forloop.counter }}--{{ book.btitle }}</li> {% elif book.id <= 4 %} <li class="yellow">{{ forloop.counter }}--{{ book.btitle }}</li> {% else %} <li class="green">{{ forloop.counter }}--{{ book.btitle }}</li> {% endif %} {% endfor %} </ul> </body> </html>
模板过滤器
过滤器用于对模板变量进行操作
date:改变日期的显示格式
length:求长度。字符串,列表长度
default:设置模板变量的默认值
格式:模板变量|过滤器:参数
自定义过滤器。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>模板过滤器</title> <style> .red { background-color: red; } .green { background-color: green; } </style> </head> <body> <ul> {% for book in books %} {% if book.id <= 2 %} <li class="red">{{ book.btitle }}--{{ book.bpub_date|date:'Y年-m月-d日' }}</li> {% else %} <li class="green">{{ book.btitle }}--{{ book.bpub_date }}</li> {% endif %} {% endfor %} </ul> default过滤器:<br/> {{ content|default:'hello' }} </body> </html>
自定义模板过滤器
在应用下创建一个包templatetags,包的名字固定,在包下创建一个过滤器文件
vim filters.py
#自定义过滤器 #过滤器其实就是python函数 from django.template import Library #创建一个library类的对象 register=Library() #自定义的过滤器函数,最少有一个参数,最多有两个 @register.filter def mod(num): '''判断num是否为偶数''' return num%2 == 0 @register.filter def mod_val(num,val): '''判断num是否能被val整除''' return num%val ==0
vim temp_filters.html
<!DOCTYPE html> <html lang="en"> {% load filters %} <head> <meta charset="UTF-8"> <title>模板过滤器</title> <style> .red { background-color: red; } .green { background-color: green; } </style> </head> <body> <ul> {% for book in books %} {# {% if book.id <= 2 %} #} {# {% if book.id|mod %} #} {% if book.id|mod_val:3 %} <li class="red">{{ book.id }}--{{ book.btitle }}--{{ book.bpub_date|date:'Y年-m月-d日' }}</li> {% else %} <li class="green">{{ book.btitle }}--{{ book.bpub_date }}</li> {% endif %} {% endfor %} </ul> default过滤器:<br/> {{ content|default:'hello' }} </body> </html>
模板注释
单行注释:{# 注释内容 #}
多行注释:{% comment %}
注释内容
{% endcomment %}
模板继承
把所有页面相同的内容放到父模板文件中,不需要放在块中,有些位置页面内容不同,需要在父模板中预留块。
在父模板里可以定义块,使用标签:
{% block 块名 %}
块中间可以写内容,也可以不写
{% endblock 块名 %}
字模板去继承父模板之后,可以重写父模板中的某一块内容
继承格式:
{% extends 父模板文件路径 %} {% block 块名 %} {{ block.super }} #获取父模板中块的默认内容 重写的内容 {% endblock 块名 %}
vim views.py
#/temp_inherit def temp_inherit(request): '''模板继承''' return render(request,'booktest/child.html')
vim base.html
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>父模板文件</title> </head> <body> <h2>导航条</h2> {% block b1 %} <h2>这是父模板b1块中</h2> {% endblock b1 %} <h2>版权信息</h2> </body> </html>
vim child.html
{% extends 'booktest/base.html' %} {% block b1 %} {{ block.super }} <b1>这是子模板b1块中的内容</b1> {% endblock b1 %}
vim urls.py
url(r'^temp_inherit$',views.temp_inherit), ##模板继承
html转义
编辑商品详情信息,数据表中保存的是html内容
在模板上下文中的html标记默认是会被转义的
< 转化为& lt; > 转换为& gt; ' 转换为& #39; " 转换为& quot; & 转换为& amp;
要关闭模板上下文字符串的转义:可以使用{{ 模板变量|safe }}
也可以使用
{% autoescape off %}
模板语言代码
{% endautoescape %}
模板硬编码中的字符串默认不会经过转义,如果需要转义,那需要手动进行转义
vim views.py
def html_escape(request): '''HTML转义''' return render(request,'booktest/html_escape.html',{'content':'<h2>hello</h2>'})
vim urls.py
url(r'^html_escape$',views.html_escape), #HTML转义
vim html_escap[e.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>html转义</title> </head> <body> {{ content }} 使用safe过滤器关闭转义:<br/> {{ content|safe }} </br> 模板硬编码中的字符串不会经过转义<br/> {{ test|default:'<h2>hello</h2>' }}<br/> 手动进行转义:<br/> {{ test|default:'<h2>hello</h2>' }} </body> </html>
csrf***
首先做一个登录页,让用户输入用户名和密码进行登录,登陆成功之后跳转的修改密码页面。在修改密码页面输入新密码,点击确认按钮完成密码修改
登录页需要一个模板文件login.html,修改密码页面也需要一个模板文件
change_pwd.html
显示登录页的视图login,验证登录的视图login_check,显示发帖页的视图change_pwd,处理修改密码的视图change_pwd_action
加功能:
- 只有用户登录之后才可以进行发帖操作
登录装饰器函数
vim views.py
def login_required(view_func): '''登录判断装饰器''' def wrapper(request,*views_args,**view_kwargs): #判断用户是否登录 if request.session.has_key('islogin'): #用户已登录,调用对应的视图 return view_func(request,*views_args,**view_kwargs) else: #用户未登录,跳转到登录页 return redirect('/login') return wrapper def login(request): '''显示登录页面''' #判断用户是否登录 if request.session.has_key('islogin'): return redirect('/index') else: #用户未登录 #获取cookie username if 'username' in request.COOKIES: #获取记住的用户名 username = request.COOKIES['username'] else: username='' return render(request,'booktest/login.html',{'username':username}) def login_check(request): '''登录校验视图''' username=request.POST.get('username') password=request.POST.get('password') remember=request.POST.get('remember') #2. 进行登录的校验 #实际开发:根据用户和密码查找数据库 #模拟:smart 123 if username=='smart' and password=='123': #用户名密码正确,跳转到首页 response=redirect('/index') #判断是否需要记住用户名 if remember == 'on': #设置cookie username,过期时间为一周 response.set_cookie('username',username,max_age=7*24*3600) #记住用户登录状态 #只有session中有islogin,就认为用户已登录 request.session['islogin']=True #记住登录的用户名 request.session['username']=username return response else: #用户名或密码错误,跳转到登录页面 request.session['username']=username return redirect('/change_pwd') # /change_pwd @login_required def change_pwd(request): '''显示修改密码页面''' return render(request,'booktest/change_pwd.html') # /change_pwd_action @login_required def change_pwd_action(request): '''模拟修改密码处理''' # 1.获取新密码 pwd=request.POST.get('pwd') #获取用户名 username=request.session.get('username') #2.实际开发的时候:修改对应数据库的内容 #3.返回一个应答 return HttpResponse('%s修改密码为:%s' %(username,pwd))
vim urls.py
url(r'^login$',views.login), #显示登录页面 url(r'^login_check$',views.login_check), #进行登录校验 url(r'^change_pwd$',views.change_pwd), #修改密码页面显示 url(r'^change_pwd_action$',views.change_pwd_action), #修改密码处理
vim login.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>登录页面</title> </head> <body> <form method="post" action="/login_check"> 用户名:<input type="text" name="username" value="{{ username }}"><br/> 密码:<input type="password" name="password"><br/> <input type="checkbox" name="remember">记住用户名<br/> <input type="submit" value="登录"> </form> </body> </html>
vim change_pwd.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>修改密码界面</title> </head> <body> <form method="post" action="/change_pwd_action"> 新密码:<input type="password" name="pwd"> <input type="submit" value="确认修改"> </form> </body> </html>
django防止csrf的方式:
- 默认打开CSRF中间件
- 表单post提交数据时加上{% csrf_token %}标签
防御原理:
- 渲染模板文件时在页面生成一个名字叫做csrfmiddlewaretoken的隐藏域
- 服务器交给浏览器保存一个名字为csrftoken的cookie信息
- 提交表单时,两个值都会发给服务器,服务器进行比对,如果一样,则csrf验证通过,否则失败
验证码
vim views.py
def login_check(request): '''登录校验视图''' username=request.POST.get('username') password=request.POST.get('password') remember=request.POST.get('remember') #获取用户输入验证码 vcode1=request.POST.get('vcode') #获取session中保存的验证码 vcode2=request.session.get('verifycode') #进行验证码校验 if vcode1 != vcode2: #验证码错误 return redirect('/login') #2. 进行登录的校验 #实际开发:根据用户和密码查找数据库 #模拟:smart 123 if username=='smart' and password=='123': #用户名密码正确,跳转到首页 response=redirect('/index') #判断是否需要记住用户名 ... #/验证码 from PIL import Image,ImageDraw,ImageFont from django.utils.six import BytesIO def verify_code(request): #引入随机函数模块 import random #定义变量,用于画面的背景色、宽、高 bgcolor=(random.randrange(20,100),random.randrange(20,100),255) width=100 height=25 #构建画面图像 im=Image.new('RGB',(width,height),bgcolor) #创建画笔对象 draw=ImageDraw.Draw(im) #调用画笔的point()函数绘制噪点 for i in range(0,100): xy=(random.randrange(0,width),random.randrange(0,height)) fill=(random.randrange(0,255),255,random.randrange(0,255)) draw.point(xy,fill=fill) #定义验证码的备选值 str1='ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890' #随机选取4个值作为验证码 rand_str='' for i in range(0,4): rand_str+=str1[random.randrange(0,len(str1))] #构造字体对象 font=ImageFont.truetype('/usr/share/fonts/gnu-free/FreeMonoBold.ttf',23) #构造字体的颜色 fontcolor=(255,random.randrange(0,255),random.randrange(0,255)) #绘制四个字 draw.text((5,2),rand_str[0],font=font,fill=fontcolor) draw.text((25,2),rand_str[1],font=font,fill=fontcolor) draw.text((50, 2), rand_str[2], font=font, fill=fontcolor) draw.text((75, 2), rand_str[3], font=font, fill=fontcolor) #释放画笔 del draw #存入session,用于做进一步验证 request.session['verifycode']=rand_str #内存文件操作 buf=BytesIO() #将图片保存在内存中,文件类型是png im.save(buf,'png') #将内存中的图片数据返回给客户端,mime类型为图片png return HttpResponse(buf.getvalue(),'image/png')
vim login.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>登录页面</title> </head> <body> <form method="post" action="/login_check"> {% csrf_token %} 用户名:<input type="text" name="username" value="{{ username }}"><br/> 密码:<input type="password" name="password"><br/> <input type="checkbox" name="remember">记住用户名<br/> <img src="/verify_code"><input type="text" name="vcode"><br/> <input type="submit" value="登录"> </form> </body> </html>
反向解析
当某一个url配置的地址发生变化时,页面上使用反向解析生成地址的位置不需要发生变化
根据url正则表达式的配置动态的生成url
vim booktest/views.py
url(r'^url_reverse$',viewa.url_reverse), #反向解析页面
模型
创建模型类
vim models.py
from django.db import models # Create your models here. class BookInfo(models.Model): '''图书模型类''' #图书名称 btitle=models.CharField(max_length=20) #出版日期 bpub_date=models.DateField() #阅读量 bread=models.IntegerField(default=0) #评论量 bcomment=models.IntegerField(default=0) #删除标记 isdelete=models.BooleanField(default=False) class HeroInfo(models.Model): '''英雄人物模型类''' #英雄名 hname=models.CharField(max_length=20) #性别 hgender=models.BooleanField(default=False) #备注 hcomment=models.CharField(max_length=200) #关系属性 hbook=models.ForeignKey('BookInfo',on_delete=models.CASCADE,) # 删除标记 isdelete=models.BooleanField(default=False)
执行迁移文件生成表
python manage.py makemigrations python manage.py migrate
往数据表里插入数据
insert into booktest_bookinfo(btitle,bpub_date,bread,bcomment,isdelete) 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 booktest_heroinfo(hname,hgender,hbook_id,hcomment,isdelete) valu s 掌0) ('郭靖',1,1,'降龙十八掌',0), ('黄蓉',0,1,'打狗棍法',0), ('黄药师',1,1,'弹指神 姐姐 ('欧阳锋',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,'华.剑Query OK, 17 rows affected (0.00 sec)), ('胡斐',1,4,'胡家刀法',0), ('苗春兰',0,4,'黄衣Records: 17 Duplicates: 0 Warnings: 00,4,'六合拳',0);
设计url,通过url浏览器访问url/index时显示图书信息页面
vim index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>图书信息</title> </head> <body> <a href="/create">新增</a> <ul> {% for book in books %} <li>{{ book.btitle }}--<a href="/delete{{ book.id }}">删除</a></li> {% endfor %} </ul> </body> </html>
vim booktest/views.py
from django.shortcuts import render,redirect from booktest.models import BookInfo from datetime import date from django.http import HttpResponse,HttpResponseRedirect # Create your views here. def index(request): '''显示图书信息''' #1. 查询出所有图书的信息 books=BookInfo.objects.all() #2.使用模板 return render(request,'booktest/index.html',{'books':books}) def create(request): '''新增一本图书''' #1.创建BookInfo对象 b=BookInfo() b.btitle='流星蝴蝶剑' b.bpub_date=date(1990,1,1) #2.保存进数据库 b.save() #3.返回应答,让浏览器再访问/index return HttpResponse('ok') #return HttpResponseRedirect('/index') def delete(request,bid): '''删除点击的图书''' #1.通过bid获取图书对象 book=BookInfo.objects.get(id=bid) #2.删除 book.delete() #3.重定向,让浏览器访问/index #return HttpResponseRedirect('/index') return redirect('/index')
vim test2/urls.py
from django.contrib import admin #from django.urls import path from django.conf.urls import include,url urlpatterns = [ url(r'^admin/',admin.site.urls),#配置项 url(r'^',include('booktest.urls')) #包含test1应用中的urls文件 ]
vim booktest/urls.py
from django.conf.urls import url from booktest import views urlpatterns=[ url(r'^index$',views.index), #图书信息页面 url(r'^create$',views.create), #添加图书信息 url(r'^delete(\d+)$',views.delete), #删除点击的图书 ]
查询
修改mysql的日志文件:
让其产生mysql.log,即是mysql的日志文件,里面记录的对mysql数据库的操作记录
- 使用下面的命令打开mysql的配置文件,编辑general_log=1 general_log_file= /usr/local/mysql/data/mysql.log,然后保存vi /etc/my.cnf
- 重启mysql服务,就会产生mysql日志文件mysql.server start
- 打开mysql的日志文件
tail /usr/local/mysql/data/mysql.log
查询函数
通过模型类.objects属性可以调用如下函数,实现对模型类对应的数据表的查询
函数名 | 功能 | 返回值 | 说明 |
---|---|---|---|
get | 返回表中满足条件的一条且只能有一条数据 | 返回值是一个模型类对象 | 参数中写查询条件 1.如果查到多条数据,则抛异常multipleobjectreturned。2.查询不到数据,则抛异常:doesnotexist |
all | 返回模型类对应表格中的所有数据 | 返回值是queryset类型 | 查询集 |
filter | 返回满足条件的数据 | 返回值是queryset类型 | 参数写查询条件 |
exclude | 返回不满足条件的数据 | 返回值是queryset类型 | 参数写查询条件 |
order_by | 对查询结果进行排序 | 返回值是queryset类型 | 参数中写根据哪些字段进行排序 |
filter方法示例:
- 条件格式:模型类属性名__条件名=值
- 判等 条件名:exact
- 查询编号为1的图书
- BookInfo.objects.get(id__exact=1)
- 模糊查询
- 查询书名包含传的图书
- BookInfo.objects.filter(btitle__contains='传')
- 查询书名以'部'结尾的图书endswith开头:startswith
- BookInfo.objects.filter(btitle__endswith='部')
- 空查询isnull
- 查询书名不为空的图书
- BookInfo.objects.filter(btitle__isnull=False)
- 范围查询
- 查询id为1或3或5的图书
- BookInfo.objects.filter(id__in=[1,3,5])
- 比较查询gt、lt、gte、lte
- 查询编号大于3的图书
- BookInfo.objects.filter(id__gt=3)
- 日期查询
- 查询1980年发表的图书
- BookInfo.objects.filter(bpub_date__year=1980)
- 查询1980年1月1日后发表的书
- from datetime importdate
- BookInfo.objects.filter(bpub_date__gt=date(1980,1,1))
- 判等 条件名:exact
order by方法示例
- 作用:进行查询结果的排序
- 查询所有图书信息,按照id从小到大进行排序
- BookInfo.objects.all().order_by('id')
- 查询所有图书的信息,按照id从大到小进行排序
- BookInfo.objects.all().order_by('-id')
- 把id大于3的图书信息按阅读量从大到小进行排序
- BookInfo.objects.filter(id__gt=3).order_by('-bread')
Q对象
作用:用于查询时条件之间的逻辑关系。mot and or,可以对Q对象进行&|~操作
使用之前需要先导入:
from Django.db.models import Q
例:查询id大于3且阅读量大于30的图书的信息
BookInfo.objects.filter(id__gt=3,bread__gt=30)
BookInfo.objects.filter(Q(id__gt=3)&Q(bread__gt=30))
例:查询id大于3或者阅读量大于30的图书的信息
BookInfo.objects.filter(Q(id__gt=3)|Q(bread__gt=30))
例:查询id不等于3图书的信息
BookInfo.objects.filter(~Q(id=3))
F对象
作用:用于类属性之间的比较
使用之前需要先导入:
from django.db.models import F
例:查询图书阅读量大于评论量图书的信息
BookInfo.objects.filter(bread__gt=F('bcomment'))
例:查询图书阅读量大于2倍评论量图书信息
BookInfo.objects.filter(bread__gt=F('bcomment')*2)
聚合函数
作用:对查询结果进行聚合操作
sum count avg max min
aggregate:调用这个函数来使用聚合。返回值是一个字典。
使用前需先导入聚合类:
from django.db.models import Sum,Count,Max,Min,Avg
例:查询所有图书的数目
select count(*) from booktest_bookinfo; BookInfo.objects.all().aggregate(Count('id')) BookInfo.objects.aggregate(Count('id'))
例:查询所有图书阅读量的总和
BookInfo.objects.aggregate(Sum('bread'))
查询集
all,filter,exclude,order_by调用这些函数会产生一个查询集
QuerySet类对象可以继续调用上面的所有函数
查询集特性:
- 惰性查询:只有在实际使用查询集中的数据的时候才会发生对数据库的真正查询
- 缓存:当使用的是同一个查询集时,第一次的时候会发生实际数据库的查询,然后把结果缓存起来,之后再使用这个查询集时,使用的是缓存中的结果。
限制查询集
可以对一个查询集进行取下标或者切片操作来限制查询集的结果
对一个查询集进行切片操作会产生一个新的查询集,下标不允许为负数。
取出查询集第一条数据的两种方式:
方式 | 说明 |
---|---|
b[0] | 如果b[0]不存在,会抛出IndexError异常 |
b[0:1].get() | 如果b[0:1].get()不存在,会抛出DoesNotExist异常 |
- exists:判断一个查询集中是否有数据。True False
模型类关系
- 一对多关系
例:图书类-英雄类
models.ForeignKey()定义多的类中- 多对多关系
例:新闻类-新闻类型类 体育新闻 国际新闻
models.ManyToManyField()定义在哪个类中都可以 - 一对一关系
例:员工基本信息表-员工详细信息类
models.OneToOneField定义在哪个类中都可以
- 多对多关系
关联查询(一对多)
在一对多关系中,一对应的类我们把他叫做一类,多对应的类我们把它叫做多类,我们把多类中定义的建立关联的类属性叫做关联属性。
例:查询id为1的图书关联的英雄的信息。
b=BookInfo.objects.get(id=1) b.heroinfo_set.all()
通过模型类查询:
HeroInfo.objects.filter(hbook__id=1)
例:查询id为1的英雄关联的图书信息
h=HeroInfo.objects.get(id=1) h.hbook()
通过模型类查询:
BookInfo.objects.filter(heroinfo__id=1)
通过模型类查询
- 由一类的对象查询多类的时候
- 一类的对象.多类名小写_set.all() #查询所用数据
- 由多类的对象查询一类的时候
- 多类的对象.关联属性 #查询多类的对象对应的一类的对象
- 由多类的对象查询一类的对象的id的时候
- 多类的对象.关联属性_id
插入、更新和删除
- 调用一个模型类对象的save方法的时候就可以实现对模型类对应数据表的插入和更新
- 调用一个模型类对象的delete方法的时候就可以实现对模型类对应数据表数据的删除
自关联
自关联是一种特殊的一对多的关系
管理器
BookInfo.objects.all()->ojects是一个什么东西呢?
答:
- objects是Django帮我自动生成的管理器对象,通过这个管理器可以实现对数据的查询
- objects是models.Manger类的一个对象。自定义管理器之后Django不再帮我们生成默认的objects管理器
- 自定义一个管理器类,这个类继承models.Manger类
- 再在具体的模型类里定义一个自定义管理器类的对象
class BookInfoManager(models.Manager): '''图书模型管理器类''' # 1.改变查询的结果集 def all(self): #1.调用父类的all,获取所有数据 books=super().all() #QuerySet #2. 对数据进行过滤 books=books.filter(isDelete=False) #3.返回books return books #2.封装函数:操作模型类对应的数据表(增删改查) def create_book(self,btitle,bpub_date): #1.创建一个图书对象 model_class=self.model book=model_class() #book=BookInfo() book.btitle=btitle book.bpub_date=bpub_date #2.保存进数据库 book.save() #3.返回book return book
自定义管理器类的应用场景
- 改变查询的结果集
- 比如调用BookInfo.boks.all()返回的是没有删除的图书的数据
- 添加额外的方法
- 管理器类中定义一个方法帮我们操作模型类对应的数据表
- 使用self.model()就可以创建一个跟自定义管理器对应的模型 类对象
元选项
- Django默认生成的表名:
- 应用名小写_模型类名小写
- 元选项:
- 需要在模型类中定义一个Meta,在里面定义一个类属性db_table就可以指定表名
- 以BookInfo模型类为例,在BookInfo中定义一个元类
class BookInfo(models.Model): class Meta: db_table='bookinfo'
其他
静态文件
使用
在网页使用的css文件,js文件和图片叫做静态文件
新建静态文件夹
- static
- images
- css
- js
配置静态文件所在的物理目录。
vim settings.py
#设置访问静态文件对应的url地址 STATIC_URL = '/static/' #设置静态文件存放的物理目录 STATICFILES_DIRS=[os.path.join(BASE_DIR,'static')]
vim static_test.html
<!DOCTYPE html> {% load staticfiles %} <html lang="en"> <head> <meta charset="UTF-8"> <title>静态文件</title> </head> <body> <img src="/static/images/mm.jpg"><br/> 动态获取STATIC_URL,拼接静态文件路径:<br/> <img src="{% static 'images/mm.jpg' %}"> </body> </html>
vim views.py
from django.shortcuts import render from django.conf import settings # Create your views here. # /static_test def static_test(request): '''静态文件''' print(settings.STATICFILES_FINDERS) return render(request,'booktest/static_test.html')
vim urls.py
from django.conf.urls import url from booktest import views urlpatterns = [ url(r'^static_test$',views.static_test), #静态文件 ]
加载目录
STATICFILES_FINDERS=('django.contrib.staticfiles.finders.FileSystemFinder','django.contrib.staticfiles.finders.AppDirectoriesFinder')
中间件
中间件函数是Django框架给我们预留的函数接口,让我们可以干预请求和应答的过程
获取浏览器端的ip地址
使用request对象的meta属性:request.META['REMOTE_ADDR']
使用中间件
新建middleware.py文件
vim booktest/middleware.py
定义中间件类
- 在类中定义中间件预留函数
- __init__:服务器响应第一个请求的时候调用
- process_request:是在产生request对象,进行url匹配之前调用
- process_view:是url匹配之后,调用视图函数之前
- process_response:视图函数调用之后,内容返回给浏览器之前
- process_exception:视图函数出现异常,会调用这个函数
如果注册的多个中间件类中包含process_exception函数的时候,调用的顺序跟注册的顺序是相反的
vim booktest/middleware.py
from django.http import HttpResponse from django.utils.deprecation import MiddlewareMixin class BlockedIPSMiddleware(object): EXCLUDE_IPS=['223.71.207.106'] def process_view(self,request,view_func,*view_arg,**view_kwargs): '''视图函数调用之前会调用''' user_ip=request.META['REMOTE_ADDR'] if user_ip in BlockedIPSMiddleware.EXCLUDE_IPS: return HttpResponse('<h2>Forbidden</h2>')
注册中间件类
vim settings.py
MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', 'booktest.middleware.BlockedIPSMiddleware', #注册中间件类 ]
上传图片
配置上传文件保存目录
- 新建上传文件保存目录
在static下创建目录media/booktest - 配置上传文件保存目录
vim settings.py#设置上传文件的保存目录 MEDIA_ROOT=os.path.join(BASE_DIR,'static/media')
后台管理页面上传图片
设计模型类
vim models.py
from django.db import models # Create your models here. class PicTest(models.Model): '''上传图片''' goods_pic=models.ImageField(upload_to='booktest')
迁移生成表格
python manage.py makimigrations
python manage.py migrate
注册模型类
vim admin.py
from django.contrib import admin from booktest.models import PicTest admin.site.register(PicTest)
自定义页面上传
- 定义用户上传图片的页面并显示,是一个自定义的表单
vim upload_pic.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>上传图片</title> </head> <body> <form method="post" enctype="multipart/form-data" action="upload_handle"> {% csrf_token %} <input type="file" name="pic"><br/> <input type="submit" value="上传"> </form> </body> </html>
- 定义接收上传文件的视图函数
request对象有一个FILES的属性,类似于字典,通过request.FILES可以获取上传文件的处理对象
vim views.py
from booktest.models import PicTest def show_upload(request): '''显示上传图片页面''' return render(request,'booktest/upload_pic.html') def upload_handle(request): '''上传图片处理''' # 1.获取上传的图片 pic =request.FILES['pic'] #print (pic.name) #2.创建一个文件 save_path= '%s/booktest/%s' %(settings.MEDIA_ROOT,pic.name) with open(save_path,'wb') as f: #3.获取上传文件的内容并写到创建的文件中 for content in pic.chunks(): f.write(content) #4. 在数据库中保存上传记录 PicTest.objects.create(goods_pic='booktest/%s' %pic.name) #5.返回 return HttpResponse('ok')
上传文件不大于2.5M,文件放在内存中
上传文件大于2.5M,文件内容写到一个临时文件中
分页
查询出所有省级地区的信息,显示在页面上。
AreaInfo.objects.filter(aparent_isnull)
- 查询出所有省级地区的信息
- 按每页显示10条信息进行分页,默认显示第一页的信息,下面并显示出页码
- 点击i页链接的时候,就显示第i页的省级地区信息。
from django.core.paginator import Paginator paginator=Paginator(areas,10) #按每页10条数据进行分页
Paginator类对象的属性
属性名 | 说明 |
---|---|
num_pages | 返回分页之后的总页数 |
page_range | 返回分页页码的列表 |
Paginator
方法名 | 说明 |
---|---|
page(self,number) | 返回第number页的page类实例对象 |
Page类对象的属性
属性名 | 说明 |
---|---|
number | 返回当前页的页码 |
object_list | 返回包含当前页的数据的查询 |
paginator | 返回对应的Paginator类对象 |
Page类对象的方法
属性名 | 说明 |
---|---|
has_previous | 判断当前页是否有前一页 |
has_next | 判断当前页是否有下一页 |
previous_page_number | 返回前一页的页码 |
next_page_number | 返回下一页的页码 |
关于 "Django框架学习笔记" 就介绍到此。希望多多支持编程宝库。
本文讲解"Myeclipse 中的注释",用于解决相关问题。 注释也是一门艺术,好的注释不仅便于后期维护,还可以生成接口文档便于前端查阅。 有必要的话可以将自己的注释写成一个模板,以后用 ...