软件框架是由其中的各个模块组成的,每个模块负责特定的功能,模块与模块之间相互协作来完成软件开发。软件框架的设计,也是针对某一类软件问题而设计的,其目的主要是提高软件开发效率。
MVC框架的核心思想是:解耦,让不同的代码块之间降低耦合,增强代码的可扩展性和可移植性,实现向后兼容。
Django的主要目的是简便、快速的开发数据库驱动的网站。它强调代码复用,多个组件可以很方便的以"插件"形式服务于整个框架,Django有许多功能强大的第三方插件,你甚至可以很方便的开发出自己的工具包。这使得Django具有很强的可扩展性。它还强调快速开发和DRY(DoNotRepeatYourself)原则。
django官方网站
django源码
Django框架遵循MVC设计,并且有一个专有名词:MVT
虚拟环境是真实python环境的复制版本。
在虚拟环境中使用的python是复制的python,安装python包也是安装在复制的python中。
安装好virtualenv后在.bashrc
中添加下面2行:
export WORKON_HOME=$HOME/.virtualenvs
source /usr/local/bin/virtualenvwrapper.sh
命令 | 含义 |
---|---|
sudo pip install virtualenv |
安装虚拟环境 |
sudo pip install virtualenvwrapper |
安装虚拟环境扩展包 |
export WORKON_HOME=$HOME/.virtualenvs |
在配置文件中设置 WORKON_HOME |
mkvirtualenv 虚拟环境名 |
创建虚拟环境 |
mkvirtualenv -p python3 环境名 |
创建指定python版本的虚拟环境 |
workon 虚拟环境名 |
进入虚拟环境 |
workon tab-tab |
查看所有环境 |
deactivate |
退出当前虚拟环境 |
rmvirtualenv 虚拟环境名 |
删除虚拟环境: |
pip install 包名 |
在当前虚拟环境中安装包 (注意不能加sudo,否则就是给系统环境安装) |
pip install django==1.8.2 |
指定版本安装包 |
pip freeze > requirements.txt |
将当前python环境的包信息导出,为了让别的环境安装依赖时方便 |
注意:在虚拟环境中不可使用
sudo pip install 包名称
来安装python包,这样安装的包实际是安装在了真实的主机环境上。
安装django环境
创建django项目
设计模型类并利用模型类和数据库进行交互
使用django后台管理数据
编写视图函数,进行URL配置
模板的使用
图书-英雄案例完成
在Django中,一个程序包含多个app
,每个app
负责不同的功能模块:
步骤:
app
django-admin startproject 项目名称
目录/文件 | 作用 |
---|---|
manage.py |
是项目管理文件,通过它管理项目。 |
与项目同名的目录,此处为test1。 | 主模块 |
__init__.py |
是一个空文件,作用是这个目录test1可以被当作包使用。 |
settings.py |
是项目的整体配置文件。 |
urls.py |
是项目的URL配置文件。 |
wsgi.py |
是项目与WSGI兼容的Web服务器入口,详细内容会在布署中讲到。 |
python manage.py startapp booktest
目录/文件 | 作用 |
---|---|
admin.py |
文件跟网站的后台管理相关。 |
__init.py__ |
是一个空文件,表示当前目录booktest可以当作一个python包使用。 |
migrations 文件夹 |
数据库迁移相关 |
models.py |
文件跟数据库操作相关。 |
tests.py |
文件用于开发测试用例,在实际开发中会有专门的测试人员,这个事情不需要我们来做。 |
views.py |
跟接收浏览器请求,进行处理,返回页面相关。相当于controller |
应用创建成功后,需要安装才可以使用,也就是建立应用和项目之间的关联。
在主模块的 settings.py
中INSTALLED_APPS
下添加应用的名称就可以完成安装。
在开发阶段,为了能够快速预览到开发的效果,django提供了一个纯python编写的轻量级web服务器,仅在开发阶段使用。
python manage.py runserver ip:端口
例:
python manage.py runserver
可以不写IP和端口,默认IP是127.0.0.1,默认端口为8000。
如果增加、修改、删除文件,服务器会自动重启;
O是object,也就类对象的意思,R是relation,翻译成中文是关系,也就是关系数据库中数据表的意思,M是mapping,是映射的意思。在ORM框架中,它帮我们把类和数据表进行了一个映射,可以让我们通过类和类对象就能操作它所对应的表格中的数据。ORM框架还有一个功能,它可以根据我们设计的类自动帮我们生成数据库中的表格,省去了我们自己建表的过程。
django中内嵌了ORM框架,不需要直接面向数据库编程,而是定义模型类,通过模型类和对象完成数据表的增删改查操作。
步骤:
在每个app
的model.py
中定义模型类,继承自models.Model
:
说明:不需要定义主键列,在生成时会自动添加,并且值为自动增长。
from django.db import models
# Create your models here.
class BookInfo(models.Model):
btitle = models.CharField(max_length= 20)
bpub_date = models.DateField()
class HeroInfo(models.Model):
hname = models.CharField(max_length=20)
hgender = models.BooleanField()
hcomment = models.CharField(max_length=100)
hbook = models.ForeignKey('BookInfo',on_delete = models.CASCADE)
on_delete
Django2以上,ForeignKey
字段一定要写on_delete
参数,可选的如下(都在django.db.models
内):
参数 | 说明 |
---|---|
CASCADE | 级联删除 |
PROTECT | 阻止引用对象删除,会抛出异常ProtectedError |
SET_NULL | 设置为NULL, 只有当null 参数为True 时才可以 |
SET_DEFAULT | 设置成默认值,所以一定要传递参数default |
SET | on_delete=models.SET(get_sentinel_user), |
manage.py makemigrations, migrate
迁移由两步完成:
生成迁移文件:根据模型类生成创建表的迁移文件。
python manage.py makemigrations
执行迁移:根据第一步生成的迁移文件在数据库中创建表。
python manage.py migrate
Django框架根据我们设计的模型类生成了迁移文件,在迁移文件中我们可以看到fields列表中每一个元素跟BookInfo类属性名以及属性的类型是一致的。同时我们发现多了一个id项,这一项是Django框架帮我们自动生成的,在创建表的时候id就会作为对应表的主键列,并且主键列自动增长。
Django默认采用sqlite3数据库,上图中的db.sqlite3就是Django框架帮我们自动生成的数据库文件。
sudo apt-get install sqliteman
数据库的设置在settings.py
中:
生成的列名和自己定义的列名相同,并且多了一个id项,这一项是Django框架帮我们自动生成的,在创建表的时候id就会作为对应表的主键列,并且主键列自动增长。
关系属性生成的字段名为: 关系属性名_id
应用名_model名
_
manage.py shell
python manage.py shell
完成数据表的迁移之后,下面就可以通过进入项目的shell,进行简单的API操作。如果需要退出项目,可以使用ctrl+d快捷键或输入quit()。
基本查询命令 | 说明 |
---|---|
BookInfo.objects.all() |
查询所有图书 |
图书对象.save() |
保存当前图书信息到数据库/ 修改图书信息 |
b=BookInfo.objects.get(id=1) |
根据主键查询图书 |
图书对象.delete() |
删除图书信息 |
关联对象查询命令 | 说明 |
---|---|
b.heroinfo_set.all() |
返回该图书关联的所有英雄信息 |
h.hbook_id |
获取外键值 |
h.hbook |
获取外键引用对象 |
多的一方可以直接使用属性值来访问一 的一方, 而一的一方获取多的一方时,需要使用
xxx_set
from booktest.models import BookInfo,HeroInfo # 引入类
from datetime import date
b1 = BookInfo()
b1.btitle= "金庸新著"
b1.bpub_date = date(1991,1,1)
b1.save() # 保存
b2 = BookInfo()
b2.btitle= "屠龙宝刀"
b2.bpub_date = date(1995,5,6)
b2.save() # 保存
BookInfo.objects.all() # 获取所有
BookInfo.objects.get(id=1) # 根据id获取
BookInfo.objects.get(pk=1) # 根据主键获取
b1.btitle="点击就送"
b1.save() # 修改
b.delete() # 删除
b1 = BookInfo.objects.get(id=1)
h = HeroInfo()
h.hname = "张无忌"
h.hgender = True
h.hbook = b1
h.save()
h.hbook_id # 获取外键值
h.hbook # 获取引用对象
b1.heroinfo_set.all() # 反向获取对象
admin
步骤:
在主模块的settings.py
中,设置:
LANGUAGE_CODE = 'zh-hans' #使用中国语言
TIME_ZONE = 'Asia/Shanghai' #使用中国上海时间
manage.py createsuperuser
python manage.py createsuperuser
然后启动:
python manage.py runserver
进入URL:
http://127.0.0.1:8000/admin/
要让自己创建的模型类,可以被admin页面管理,需要对他们进行注册:
进入主模块的admin.py
:
from django.contrib import admin
from booktest.models import BookInfo,HeroInfo
# 后台管理相关文件
# Register your models here.
# 注册模型类
admin.site.register(BookInfo)
admin.site.register(HeroInfo)
再刷新
Django提供了自定义管理页面的功能,比如列表页要显示哪些值。
进入主模块的admin.py
,创建自己的ModelAdmin
类,然后在里面的list_display
类属性决定了显示哪些 属性:
from django.contrib import admin
from booktest.models import BookInfo,HeroInfo
# 后台管理相关文件
# Register your models here.
# 自定义模型管理类
class BookInfoAdmin(admin.ModelAdmin):
'''图书模型管理类'''
list_display = ['id', 'btitle', 'bpub_date']
class HeroInfoAdmin(admin.ModelAdmin):
'''英雄人物模型管理类'''
list_display = ['id', 'hname', 'hcomment']
# 注册模型类
# admin.site.register(BookInfo)
admin.site.register(BookInfo, BookInfoAdmin)
admin.site.register(HeroInfo, HeroInfoAdmin)
步骤:
views.py
中request
django.http.HttpResponse对象
django.shortcuts
中有快捷方式render、 redirect
from django.shortcuts import render
from django.http import HttpResponse
import time
# Create your views here.
def index(request):
currenttime = str(time.localtime().tm_min) +":"+ str(time.localtime().tm_sec)
return HttpResponse(currenttime )
https://docs.djangoproject.com/en/2.1/topics/http/urls/
django查找URL的顺序是这样子的:
settings.py
中的ROOT_URLCONF
, 但是如果发送来的HttpRequest object
中有 urlconf
属性(set by middleware), 那么这个值就会覆盖ROOT_URLCONF
设置urlpatterns
的内容,它应该是一个list
,并且都是django.urls.path()
或者django.urls.re_path()
的实例。view
来调用,which is a simple Python function (or a class-based view). The view gets passed the following arguments:
主模块的urls.py
中:
from django.contrib import admin
from django.urls import path
from django.urls import include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('booktest.urls'))
]
booktest应用中的urls.py
(需要自己创建):
from django.conf.urls import url
from django.urls import re_path
from .views import index
urlpatterns = [
re_path(r'.*', index),
# url(r'index', index),
# url('^',index)
]
习惯统一以/
开头,这样就会从host开始拼接,如果不写/
,则会当成相对地址
<a href="/create">新增</a>
步骤:
settings.py
中配置模板路径view
中加载模板文件对象直接在项目名底下建立目录templates
, 然后在该目录中,为每个app建立同名文件夹:
在settings.py
中,找到TEMPLATES
的DIR
, 加上模板路径:
'DIRS': [os.path.join(BASE_DIR, 'templates')],
{{变量名}}
{%代码段%}
比如:
{% for i in data %}
循环内部代码
{% empty %}
如果循环列表长度为0则运行这部分
{% endfor %}
from django.http import HttpResponse
from django.template import loader,RequestContext
def index(request):
'''使用模板文件'''
# 使用模板文件
# 1.加载模板文件, 模板对象
temp = loader.get_template('booktest/index.html')
# 2.定义模板上下文:给模板文件传递数据
context = RequestContext(request, {} )
# 3.模板渲染:产生标准的html内容
res_html = temp.render(context)
# 4.返回给浏览器
return HttpResponse(res_html)
def index(request):
# 进行处理,和M和T进行交互。。。
# return HttpResponse('老铁,没毛病')
# return my_render(request, 'booktest/index.html')
return render(request, 'booktest/index.html', {'content':'hello world', 'list':list(range(1,10))})
对象-关系映射ORM系统一般以中间件的形式存在
在settings.py
中:
DATABASES = {
'default': {
# 'ENGINE': 'django.db.backends.sqlite3',
'ENGINE': 'django.db.backends.mysql',
# 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
'NAME': 'test2', #数据库名字,
'USER': 'root', #数据库登录用户名
'PASSWORD': 'mysql', #数据库登录密码
'HOST': 'localhost', #数据库所在主机
'PORT': '3306', #数据库端口
}
}
注意:数据库test2 Django框架不会自动生成,需要我们自己进入mysql数据库去创建。
pip install pymysql
在主模块的__init__.py
内写入:
import pymysql
pymysql.install_as_MySQLdb()
Django根据属性的类型确定以下信息:
django会为表创建自动增长的主键列,每个模型只能有一个主键列,如果使用选项设置某属性为主键列后django不会再创建自动增长的主键列
属性=models.字段类型(选项)
字段类型都在django.db.models
内
字段 | 描述 | 自己的属性及其作用 |
---|---|---|
AutoField |
自动增长的IntegerField,通常不用指定,不指定时Django会自动创建属性名为id的自动增长属性。 | |
BooleanField |
布尔字段,值为True或False | |
NullBooleanField |
可空布尔型,支持Null、True、False三种值 | |
CharField |
字符串 | 参数max_length表示最大字符个数 |
TextField |
大文本字段,一般超过4000个字符时使用。 | |
IntegerField |
整数 | |
DecimalField |
十进制浮点数 | (max_digits=None, decimal_places=None) 参数max_digits表示总位数。 参数decimal_places表示小数位数。 |
FloatField |
浮点数 | |
DateField |
日期 | [auto_now=False, auto_now_add=False] 参数auto_now表示每次保存对象时,自动设置该字段为当前时间,用于"最后一次修改"的时间戳,它总是使用当前日期,默认为false。 参数auto_now_add表示当对象第一次被创建时自动设置当前时间,用于创建的时间戳,它总是使用当前日期,默认为false。 参数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。 |
default
和blank
不影响表结构。默认情况下mysql的日志文件没有产生,需要修改mysql的配置文件
修改配置文件
sudo vi /etc/mysql/mysql.conf.d/mysqld.cnf
重启mysql
sudo service mysql restart
查看日志文件
sudo tail -f /var/log/mysql/mysql.log #可以实时查看数据库的日志内容
所有的查询都是使用的 对象.objects
里面的方法:
函数名 | 功能 | 返回值 | 说明 |
---|---|---|---|
get |
返回表中满足条件的一条且只能有一条数据。 | 返回值是一个模型类对象。 | 参数中写查询条件。 1) 如果查到多条数据,则抛异常 MultipleObjectsReturned 。2)查询不到数据,则抛异常: DoesNotExist 。 |
all |
返回模型类对应表格中的所有数据。 | 返回值是QuerySet 类型 |
查询集 |
filter |
返回满足条件的数据。 | 返回值是QuerySet 类型 |
参数写查询条件。 |
exclude |
返回不满足条件的数据。 | 返回值是QuerySet 类型 |
参数写查询条件。 |
order_by |
对查询结果进行排序。 | 返回值是QuerySet 类型 |
参数中写根据哪些字段进行排序。 |
条件格式:模型类属性名__条件名=值
条件运算 | 说明 | 例子 |
---|---|---|
exact |
是否全等, 区分大小写 | .filter(id__exact=1) |
contains |
是否包含,区分大小写 | filter(btitle__contains='传') |
endswith , startswith |
是否以xx开始、结束,区分大小写 | .filter(btitle__endswith='部') |
isnull |
是否为空 | .filter(btitle__isnull=False) |
in |
是否在范围内 | .filter(id__in=[1, 3, 5]) |
gt、gte、lt、lte |
大于小于等等 | .filter(id__gt=3) |
日期类型比较… | .filter(bpub_date__year=1980) .filter(bpub_date__gt=date(1990, 1, 1)) |
exact
或者直接写 =
BookInfo.objects.get(id=1)
BookInfo.objects.filter(id__exact=1)
contains
, endswith
, startswith
BookInfo.objects.filter(btitle__contains='传')
BookInfo.objects.filter(btitle__endswith='部')
以上运算符都区分大小写,在这些运算符前加上i表示不区分大小写,如iexact、icontains、istartswith、iendswith.
isnull
BookInfo.objects.filter(btitle__isnull=False)
in
BookInfo.objects.filter(id__in = [1,3,5])
gt,lt,gte, lte
BookInfo.objects.filter(id__gt=3)
BookInfo.objects.filter(bpub_date__year=1980)
from datetime import date
BookInfo.objects.filter(bpub_date__gt=date(1980,1,1))
order
方法内加上 字段名,如果多个字段,使用,
隔开; 默认是从小到大排序,如果逆序,需要在字段名前加上-
。
# 查询所有图书的信息,按照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')
filter
等函数可以传入多个参数,用于指定多个条件,不过这些条件都是 and
方式:
BookInfo.objects.filter(btitle__exact="abc", bread__gt = 10)
而Q对象可以用来与或非:&|~
from django.db.models import Q
BookInfo.objects.filter(Q(id__gt=3)&Q(bread__gt=30))
BookInfo.objects.filter(Q(id__gt=3)|Q(bread__gt=30))
BookInfo.objects.filter(~Q(id=3))
用于类属性之间的比较
from django.db.models import F
BookInfo.objects.filter(bread__gt=F('bcomment')) # 阅读量大于评论
BookInfo.objects.filter(bread__gt=F('bcomment')*2) # 还可以进行直接计算
对查询结果进行聚合操作
2个方法
方法 | 含义 |
---|---|
aggregate |
聚合的函数,配合聚合类来使用,返回字典 |
count |
统计返回的数据个数,返回的是数字 |
from django.db.models import Sum,Count,Max,Min,Avg
聚合类 |
---|
Sum |
Count |
Max |
Min |
Avg |
BookInfo.objects.all().aggregate(Count('id'))
# {'id__count': 5}
BookInfo.objects.aggregate(Sum('bread')) # all()可以省略
# {'bread__sum': 126}
BookInfo.objects.all().count()
BookInfo.objects.count()
BookInfo.objects.filter(id__gt=3).count()
aggregate
返回值是一个字典类型:
{'聚合类小写__属性名':值}
如:{'sum__bread':3}
返回查询集的过滤器:
返回单个值的过滤器如下:
exist
查询集对象.exists()
返回值为True/False
每个查询集都包含一个缓存来最小化对数据库的访问。在新建的查询集中,缓存为空,首次对查询集求值时,会发生数据库查询,django会将查询的结果存在查询集的缓存中,并返回请求的结果,接下来对查询集求值将重用缓存中的结果。
方式 | 说明 |
---|---|
b[0] | 如果b[0]不存在,会抛出IndexError 异常 |
b[0:1].get() | 如果b[0:1].get()不存在,会抛出DoesNotExist 异常。 |
models.ForeignKey()
定义在多的类中。models.ManyToManyField
定义在哪个类中都可以。models.OneToOneField
定义在哪个类中都可以由一类的对象查询多类的时候:
一类的对象.多类名小写_set.all() #查询所用数据
比如: b.heroinfo_set.all()
由多类的对象查询一类的时候:
多类的对象.关联属性 #查询多类的对象对应的一类的对象
比如: h.hbook
由多类的对象查询一类对象的id时候:
多类的对象. 关联属性_id
比如: h.hbook_id
一类名.objects.filter(多类名小写__多类属性名__条件)
多类名.objects.filter(关联属性__一类属性名__条件)
例:查询图书信息,要求图书关联的英雄的描述包含'八'。
BookInfo.objects.filter(heroinfo__hcomment__contains='八')
例:查询图书信息,要求图书中的英雄的id大于3.
BookInfo.objects.filter(heroinfo__id__gt=3)
例:查询书名为“天龙八部”的所有英雄。
HeroInfo.objects.filter(hbook__btitle='天龙八部')
也是使用ForeignKey
,只不过里面参数是写self
class CityInfo(models.Model):
cname = models.CharField(max_length=50)
cparent = models.ForeignKey(to="self", on_delete=models.CASCADE, blank=True, null=True)
每个模型类 都以一个类属性叫做objects
,它的类型是django.db.models.Manager
。 它是Django帮我自动生成的管理器对象,通过这个管理器可以实现对数据的查询。
可以在模型类中自己增加一个Manager
字段,如果自己增加了,那么默认的就失效了:
class BookInfo(models.Model):
book = models.Manager()
小提示:
super().xxx()
调用原来的方法self.model()
创建对应模型类的对象自己定义一个类,继承自 models.Manager
,可以就写在models.py
中:
在管理器对象中使用self.model()
就可以创建一个跟自定义管理器对应的模型类对象。
from django.db import models
# Create your models here.
class BookInfoManager(models.Manager):
'''图书模型管理器类'''
# 1.改变原有查询的结果集
def all(self):
# 1.调用父类的all方法,获取所有数据
books = super().all() # QuerySet
# 2.对books中的数据进行过滤
books = books.filter(isDelete=False)
# 返回books
return books
# 2.封装方法,操作模型类对应的数据表(增删改查)
def create_book(self, btitle, bpub_date):
'''添加一本图书'''
# 1.创建一个图书对象
# 获取self所在的模型类
model_class = self.model
book = model_class()
# book = BookInfo()
book.btitle = btitle
book.bpub_date = bpub_date
# 2.添加进数据库
book.save()
# 3.返回book
return book
class BookInfo(models.Model):
...
objects = BookInfoManager() # 自定义一个BookInfoManager类的对象
默认的objects管理器对象中已经有
create
方法,传参的时候必须使用关键字参数来指定列名
因为django默认生成的表名为appname_modelname
的小写名字, 如果app的名字改变了,那么表名也会失效。 为了防止这种情况,可以自定义表名:
Meta
,在里面定义一个类属性db_table
就可以指定表名。class BookInfo(models.Model):
...
class Meta:
db_table = 'bookinfo' # 指定模型类对应表名
path
或者re_path
函数。正确:index/
正确:index
错误:/index
错误:/index/
进行url匹配时,把所需要的捕获的部分设置成一个正则表达式组,这样django框架就会自动把匹配成功后相应组的内容作为参数传递给视图函数。
注意:两种参数的方式不要混合使用,在一个正则表达式中只能使用一种参数方式。
位置参数,参数名可以随意指定
url(r'^delete(\d+)/$',views.show_arg),
在位置参数的基础上给正则表达式组命名即可。
?P<组名>
关键字参数,视图中参数名必须和正则表达式组名一致.
re_path(r'index/(?P\d+)'
def index(request, num):
pass
网站开发完成后,要修改settings.py
配置:
'*'
] ——— 配置可以访问的IP如果此时出现错误,Django自己会返回标准的错误页面。 如果需要修改,则需要的templates目录下面自定义一个404.html文件, 或者 500.html 等等。
DEBUG模式下看不到错误视图,只能看到调试信息
request_path
找不到了
{{request_path}}
属性 | 说明 |
---|---|
request.POST |
保存的是POST提交的参数(QueryDict 类型) |
request.GET |
保存的是GET提交的参数(QueryDict 类型) |
request.method |
返回请求方式字符串 |
request,path |
返回请求路径字符串,不包含域名和url参数 |
request.encoding |
请求方式,如果返回None,代表是浏览器默认encoding,一般是UTF-8 这个属性是可写的,可以通过修改它来修改访问表单数据使用的编码,接下来对属性的任何访问将使用新的encoding值。 |
request.FILES |
一个类似于字典的对象,包含所有的上传文件。 |
request.COOKIES |
一个标准的Python字典,包含所有的cookie,键和值都为字符串。 |
request.session |
一个既可读又可写的类似于字典的对象,表示当前的会话,只有当Django 启用会话的支持时才可用,详细内容见"状态保持"。 |
django.http.QueryDict
类似于字典,和一般字典不同的是,它可以处理一个key带有多个value的情况。
方法 | 说明 |
---|---|
对象[key] | 没有值就报错,一个键同时拥有多个值将获取最后一个值 |
get(key) | 没有值就返回None,一个键同时拥有多个值将获取最后一个值 |
getlist(key) | 返回List |
from django.http.request import QueryDict
q = QueryDict('a=123&b=456`)
q['a'] # 获取值,没有值就报错
q.get('a') # 获取值,没有值就返回None
q.get('a', 'default') # 获取值,没有对应的key就返回默认值
q.getlist('a') # 获取一个key的多个值,返回类型为list
取消django防止跨域访问的保护:
将settings.py
中的'django.middleware.csrf.CsrfViewMiddleware',
注释掉
django.http.HttpResponse
视图在接收请求并处理后,必须返回HttpResponse对象或子对象
属性 | 说明 |
---|---|
content | 表示返回的内容。 |
charset | 表示response采用的编码字符集,默认为utf-8。 |
status_code | 返回的HTTP响应状态码。 |
content-type | 指定返回数据的的MIME类型,默认为’text/html ’。 |
方法 | 说明 |
---|---|
__init__ |
创建HttpResponse对象后完成返回内容的初始化。 |
set_cookie |
设置Cookie信息。set_cookie(key, value='', max_age=None, expires=None) |
delete_cookie(key) |
删除指定的key的Cookie,如果key不存在则什么也不发生。 |
write |
向响应体中写数据。 |
JsonResponse继承自HttpResponse,它的 content-type为 application/json
,创建对象时接收字典作为参数
return JsonResponse({'h1':'hello','h2':'world'})
继承自 HttpResponse,状态码为302
return HttpResponseRedirect('/')
实现状态保持主要有两种方式:
cookie和session的应用场景
Cookie是由服务器端生成,发送给User-Agent(一般是浏览器),浏览器会将Cookie的key/value保存到某个目录下的文本文件内,下次请求同一网站时就发送该Cookie给服务器。
Cookies最典型记住用户名。
Cookie是存储在浏览器中的一段纯文本信息,建议不要存储敏感信息如密码,因为电脑上的浏览器可能被其它人使用
response.set_cookie
设置cookie是使用一个HttpResponse对象,或者它的子类对象, 里面的set_cookie
方法,是以键值对保存的
response.set_cookie(key,value, max_age, expires)
`max_age`是一个整数,表示在指定秒数后过期。
`expires`是一个datetime或timedelta对象,会话将在这个指定的日期/时间过期。
max_age与expires二选一。
如果不指定过期时间,在关闭浏览器时cookie会过期。
例子:
response = HttpResponse('这是响应')
response.set_cookie('mykey1', 1123415)
return response
response.set_cookie( 'num', 1, max_age = 秒数) #
request.COOKIES
def cookie_get(request):
response = HttpResponse("读取Cookie,数据如下:
")
if 'h1' in request.COOKIES:
response.write(''
+ request.COOKIES['h1'] + '')
return response
session就像是去健身房办卡,办好卡后,健身房那边保存了卡的信息和对应用户的信息,而用户只需要记住卡号就可以使用了。
在服务器内,session就是一张表, 里面是键值对的方式来存储: session_key和session_data
django的框架中,session叫做 django_session
,保存在 request.session
中,设置也是使用这个属性,类似于使用字典
django会在cookie中让客户端保存key为sessionid
的cookie,用来维护session
cookie无论保存的是什么类型的数据,取出来的时候都是字符串,而 session数据因为是保存在服务器中,所以取出来的类型不变
sessionid
** cookie中。默认是启用的。打开test3/settings.py文件,在项MIDDLEWARE_CLASSES中启用Session中间件。
在settings.py
文件,设置SESSION_ENGINE
项指定Session数据存储的方式,可以存储在数据库、缓存、Redis等。
存储在缓存中:存储在本机内存中,如果丢失则不能找回,比数据库的方式读写更快。
SESSION_ENGINE='django.contrib.sessions.backends.cache'
存储在数据库中,如下设置可以写,也可以不写,这是默认存储方式。
SESSION_ENGINE='django.contrib.sessions.backends.db'
混合存储:优先从本机内存中存取,如果没有则从数据库中存取。
SESSION_ENGINE='django.contrib.sessions.backends.cached_db'
request.session
使用 | 说明 |
---|---|
request.session['键']=值 |
以键值对的格式写session。 |
request.session['键'] |
获取session |
request.session.get('键',默认值) |
根据键读取值。 |
request.session.clear() |
清除所有session,在存储中删除值部分。 |
request.session.flush() |
清除session数据,在存储中删除session的整条数据。 |
del request.session['键'] |
删除session中的指定键及值,在存储中只删除某个键及对应的值。 |
request.session.set_expiry(value) |
设置会话的超时时间,如果没有指定过期时间则两个星期后过期。 |
session保存的值是有类型的
pip install django-redis-sessions
SESSION_ENGINE = 'redis_sessions.session'
SESSION_REDIS_HOST = 'localhost'
SESSION_REDIS_PORT = 6379
SESSION_REDIS_DB = 2
SESSION_REDIS_PASSWORD = ''
SESSION_REDIS_PREFIX = 'session'
模板文件包含两部分内容:
模板语言的使用都在django.template
中,settings.py
内定义了配置:
Django处理模板分为两个阶段:
# 1.加载模板文件,获取一个模板对象
temp = loader.get_template(template_path)
# 2.定义模板上下文,给模板文件传数据
context = RequestContext(request, context)
# 3.模板渲染,产生一个替换后的html内容
res_html = temp.render(context)
# 4.返回应答
return HttpResponse(res_html)
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')]
,
'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',
],
},
},
]
templates文件夹
去找模板文件,前提是应用中必须有templates文件夹。INSTALLED_APPS = (
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'booktest',
)
模板语言包括4种类型,分别是:
* 变量
* 标签
* 过滤器
* 注释
{{模板变量名}}
{{ book.btitle }}
{{book.0}}
★如果解析失败,则产生内容时用空字符串填充模板变量。
内建标签
{% 代码段 %}
for循环:
{% for x in 列表 %}
# 列表不为空时执行
{% empty %}
# 列表为空时执行
{% endfor %}
可以使用{{ forloop.counter }}
得到循环遍历了第几次
{% if 条件 %}
代码
{% elif 条件 %}
代码
{% else %}
代码
{% endif %}
> < >= <= == !=
and or not
{% for book in books %}
{% if book.id <= 2 %}
<li class="red">{{ forloop.counter }}--{{ book.btitle }}</li>
{% elif book.id <= 5 %}
<li class="yellow">{{ forloop.counter }}--{{ book.btitle }}</li>
{% else %}
<li class="green">{{ forloop.counter }}--{{ book.btitle }}</li>
{% endif %}
{% endfor %}
语法如下:
|
来应用过滤器,用于进行计算、转换操作,可以使用在变量、标签中。:
传递参数。变量|过滤器:参数
官方文档
模板变量|过滤器:参数
book | length
data|default:'默认值'
value|date:"Y年m月j日 H时i分s秒"
自定义过滤器其实就是一个python的函数
官方文档
比如模板代码中不能使用%
取余,所以需要自定义过滤器:
步骤:
templatetags
, 里面要有__init__.py
py
文件,里面写方法 (文件名和方法名都不一定)from django.template import library
register = Library() # 自定义过滤器需要使用它
@register.filter # 这个装饰必须要
def mod(num): # 方法名字不一定,参数就是过滤器可以接收的参数( | 之前)
return num % 2 == 0
@register.filter
def mod_val(num, val): # 定义一个带参数的过滤器
pass
# 页面中
{{ load.filters }} # filters 是那个py文件的名字
...
{{ if book.id | mod_val : 2 %}}
自定义过滤器的参数至少有一个,最多2个
templatetags也可以创建在app目录下
django的注释代码不会被编译,不会输出到客户端
{# {% if book.id|mod %}#}
{% comment %}
...
{% endcomment %}
为了更好的可读性,建议给endblock
标签也写上名字,这个名字与对应的block名字相同。父模板中也可以使用上下文中传递过来的数据。
{% block 块名 %}
预留区域,可以编写默认内容,也可以没有默认内容
{% endblock 块名%}
子模板去继承父模板之后,可以重写父模板中的某一块的内容。
子模版不用填充父模版中的所有预留区域,如果子模版没有填充,则使用父模版定义的默认值。
首行写继承格式:{% extends 父模板文件路径%}
{% extends 父模板文件路径%}
...
{% block 块名 %}
{{ block.super}} #获取父模板中块的默认内容
重写的内容
{% endblock 块名%}
base.html
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{% block title %}父模板文件{% endblock title %}title>
head>
<body>
<h1>导航条h1>
{% block b1 %}
<h1>这是父模板b1块中的内容h1>
{% endblock b1 %}
{% block b2 %}
<h1>这是父模板b2块中的内容h1>
{% endblock b2 %}
<h1>版权信息h1>
body>
html>
child.html
{% extends 'booktest/base.html' %}
{% block title %}子模板文件{% endblock title %}
{% block b1 %}
{{ block.super }}
<h1>这是子模板b1块中的内容h1>
{% endblock b1 %}
{% block b2 %}
{{ block.super }}
<h1>这是子模板b2块中的内容h1>
{% endblock b2 %}
一般的变量使用,默认是{{t1|escape}}
,所以 escape
可以不写。
{{ 模板变量|safe}}
——只关闭这一个{% autoescape off %}
模板语言代码
{% endautoescape %}
def login_required(view_func):
'''登录判断装饰器'''
def wrapper(request, *view_args, **view_kwargs):
# 判断用户是否登录
if request.session.has_key('islogin'):
# 用户已登录,调用对应的视图
return view_func(request, *view_args, **view_kwargs)
else:
# 用户未登录,跳转到登录页
return redirect('/login')
return wrapper
CSRF全拼为Cross Site Request Forgery,译为跨站请求伪造。CSRF指攻击者盗用了你的身份,以你的名义发送恶意请求。CSRF能够做的事情包括:以你名义发送邮件,发消息,盗取你的账号,甚至于购买商品,虚拟货币转账…造成的问题包括:个人隐私泄露以及财产安全。
登录了的网站,保存了sessionid, 然后登录一个钓鱼网站的时候,它骗你点击一个地方,然后从它向你已登录的网站发送一个请求,用来装作是你来操作。
{% csrf_token %}
{% csrf_token %}
生成为一个名字叫做csrfmiddlewaretoken
的隐藏域(input:hidden)。将验证码的内容保存在session内,然后生成一张图片发送给用户,让它输入,之后和服务器session的内容对比。
代码不用自己背,网上有很多:
pip install Pillow==3.4.1
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 = 'ABCD123EFGHIJK456LMNOPQRS789TUVWXYZ0'
#随机选取4个值作为验证码
rand_str = ''
for i in range(0, 4):
rand_str += str1[random.randrange(0, len(str1))]
#构造字体对象,ubuntu的字体路径为“/usr/share/fonts/truetype/freefont”
font = ImageFont.truetype('FreeMono.ttf', 23)
#构造字体颜色
fontcolor = (255, random.randrange(0, 255), random.randrange(0, 255))
#绘制4个字
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')
<script type="text/javascript" src="/static/jquery-1.12.4.min.js">script>
<script type="text/javascript">
$(function(){
$('#change').css('cursor','pointer').click(function() {
$('#yzm').attr('src',$('#yzm').attr('src')+1)
});
});
script>
...
<img id="yzm" src="/verify_code/?1"/>
<span id="change">看不清,换一个span>
给一个自己配置的route URL命名,这样当URL改变时,其他跳转的连接如果是名字引用,那么就不需要在每个HTML页面中修改跳转地址。
步骤:
include
中指定参数namespace
name
参数在模板中使用url标签
在视图中使用reverse函数
在模板文件中跳转的时候,书写:
<a href="{% url 'namespace:name' %}"> 跳转a>
普通链接:<a href="/fan2/">fan2a>
<hr>
反向解析:<a href="{%url 'booktest:fan2'%}">fan2a>
url(r'^show_args/(\d+)/(\d+)$', views.show_args, name='show_args'), # 捕获位置参数
跳转
url(r'^show_kwargs/(?P\d+)/(?P\d+)$' , views.show_kwargs, name='show_kwargs'), # 捕获关键字参数
跳转
from django.core.urlresolvers import reverse
...
def index(request):
url = reverse('booktest:index')
url = reverse('booktest:index', args=(1,2)) # 传递位置参数
url = reverse('booktest:index', kwargs={'c':3, 'd':4}) # 传递关键字参数
return redirect(url)
# return redirect(reverse('booktest:fan2'))
return redirect(reverse('booktest:fan2', args=(2,3)))
return redirect(reverse('booktest:fan2', kwargs={'id':100,'age':18}))
项目中的CSS、图片、js都是静态文件。一般会将静态文件放到一个单独的目录中,以方便管理
静态文件可以放在项目根目录下,也可以放在应用的目录下,由于有些静态文件在项目中是通用的,所以推荐放在项目的根目录下,方便管理。
步骤:
STATIC_URL
设置访问静态文件对应的url。STATICFILES_DIRS
设置静态文件所在的物理目录。<script src="/static/img/a.jpg ">script>
如果每次都在模板文件中写固定的路径,那么STATIC_URL
一改,维护起来就很麻烦。
步骤:
{% load staticfiles %}
或者
{% load static from staticfiles %}
...
下面使用动态的方式获取静态文件的路径
拿到 /static/images/a.jpg
说明:这种方案可以隐藏真实的静态文件路径,但是结合Nginx布署时,会将所有的静态文件都交给Nginx处理,而不用转到Django部分,所以这项配置就无效了。
STATICFILES_DIRS
中查找static
文件夹from django.conf import settings
print(settings.STATICFILES_FINDERS)
# ('django.contrib.staticfiles.finders.FileSystemFinder', 这个负责在配置的静态目录下找
# 'django.contrib.staticfiles.finders.AppDirectoriesFinder') 这个负责在app下的static文件夹找
中间件方法 | 作用 | 参数 | 返回值 |
---|---|---|---|
__init__ |
:服务器启动之后接收第一个请求的时候调用。 | self | 无 |
process_request |
是对每个请求产生request对象之后,进行url匹配之前调用。 | self, request | None或者 HttpResponse |
process_view |
是在url匹配之后,调用视图函数之前。 | self,request,view_func, *view_args, **view_kwargs | None或者 HttpResponse |
process_response |
视图函数调用之后,内容返回给浏览器之前,要将response返回。 | self, request, response | HttpResponse |
process_exception |
视图函数出现异常,会调用这个函数。 | self, request, exception | HttpResponse |
★注:
process_request
中返回了Response的话,那么之后的url匹配还有view就不会被调用了,直接调用process_response
返回结果process_view
中返回了Response的话,那么之后的view就不会调用了,直接调用process_response
返回结果process_exception
的中间件类,那么会先调用 后注册的异常处理视图函数中
request.META['REMOTE_ADDR']
步骤:
class TestMiddleware(object):
'''中间件类'''
def __init__(self):
'''服务器重启之后,接收第一个请求时调用'''
print('----init----')
def process_request(self, request):
'''产生request对象之后,url匹配之前调用'''
print('----process_request----')
# return HttpResponse('process_request')
def process_view(self, request, view_func, *view_args, **view_kwargs):
'''url匹配之后,视图函数调用之前调用'''
print('----process_view----')
return HttpResponse('process_view')
def process_response(self, request, response):
'''视图函数调用之后,内容返回浏览器之前'''
print('----process_response----')
return response
MIDDLEWARE_CLASSES = (
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'django.middleware.security.SecurityMiddleware',
# 'booktest.middleware.BlockedIPSMiddleware', # 注册中间件类
# 'booktest.middleware.TestMiddleware',
'booktest.middleware.ExceptionTest1Middleware',
'booktest.middleware.ExceptionTest2Middleware',
)
管理类可以定义在admin.py
中, 继承自models.AdminModel
管理类属性 | 含义 |
---|---|
list_per_page = 10 | 控制每页显示多少条 |
list_display = [] | 控制显示哪些列属性/方法 |
actions_on_bottom = True | |
actions_on_top = False | |
list_filter = [‘atitle’] # 列表页右侧过滤栏 | |
search_fields = [‘atitle’] # 列表页上方的搜索框 |
管理类有两种使用方式:
class AreaAdmin(admin.ModelAdmin):
pass
...
admin.site.register(AreaInfo,AreaAdmin)
@admin.register(AreaInfo)
class AreaAdmin(admin.ModelAdmin):
pass
class AreaAdmin(admin.ModelAdmin):
list_per_page = 10 # 每页显示多少条
actions_on_top=True # 操作选项的位置
actions_on_bottom=False
list_display=[模型字段1,模型字段2,...] # 显示的列字段
list_display = ['id','atitle','title'] # 还能将 方法作为列
list_filter=['atitle'] # 右侧过滤栏
search_fields=['atitle'] # 搜索框
class AreaInfo(models.Model):
...
def title(self):
return self.atitle
# 方法列是不能排序的,如果需要排序需要为方法指定排序依据。
title.admin_order_field='atitle'
# 指定列标题
title.short_description='区域名称'
# 访问关联对象
# 无法直接访问关联对象的属性或方法,可以在模型类中封装方法,访问关联对象的成员。
def parent(self):
if self.aParent is None:
return ''
return self.aParent.atitle
parent.short_description='父级区域名称'
class AreaAdmin(admin.ModelAdmin):
...
fields=['aParent','atitle'] # 可编辑字段
fieldset=( # 分组显示, 和fields二选一使用
('组1标题',{'fields':('字段1','字段2')}),
('组2标题',{'fields':('字段3','字段4')}),
)
inlines = [AreaStackedInline] # 关联对象
# inlines = [AreaTabularInline]
class AreaStackedInline(admin.StackedInline):
model = AreaInfo #关联子对象
extra = 2#额外编辑2个子对象
class AreaTabularInline(admin.TabularInline):
model = AreaInfo#关联子对象
extra = 2#额外编辑2个子对象
from django.db import models
class AreaInfo(models.Model):
'''地址模型类'''
# 地区名称
atitle = models.CharField(verbose_name='标题', max_length=20)
# 自关联属性
aParent = models.ForeignKey('self', null=True, blank=True)
def __str__(self):
return self.atitle
def title(self):
return self.atitle
title.admin_order_field = 'atitle' # 控制这个方法,是按照哪个属性排序
title.short_description = '地区名称' # 控制这个方法显示对应列名
def parent(self):
if self.aParent is None:
return ''
return self.aParent.atitle
parent.short_description = '父级地区名称'
class PicTest(models.Model):
'''上传图片'''
goods_pic = models.ImageField(upload_to='booktest')
from django.contrib import admin
from booktest.models import AreaInfo,PicTest
# Register your models here.
class AreaStackedInline(admin.StackedInline):
# 写多类的名字
model = AreaInfo
extra = 2
class AreaTabularInline(admin.TabularInline):
model = AreaInfo
extra = 2
class AreaInfoAdmin(admin.ModelAdmin):
'''地区模型管理类'''
list_per_page = 10 # 指定每页显示10条数据
list_display = ['id', 'atitle', 'title', 'parent']
actions_on_bottom = True
actions_on_top = False
list_filter = ['atitle'] # 列表页右侧过滤栏
search_fields = ['atitle'] # 列表页上方的搜索框
# fields = ['aParent', 'atitle'] 指定详细页面中字段顺序
fieldsets = ( # 分组显示, 这个字段和 fields只能二选一使用
('基本', {'fields':['atitle']}),
('高级', {'fields':['aParent']})
)
# inlines = [AreaStackedInline]
inlines = [AreaTabularInline]
admin.site.register(AreaInfo, AreaInfoAdmin)
admin.site.register(PicTest)
步骤:
templates
文件夹下创建admin
文件夹,里面创建base_site.html
/home/python/.virtualenvs/py_django/lib/python3.5/site-packages/django/contrib/admin/templates/admin
步骤:
1. 配置上传文件的保存目录
可以创建在静态文件目录下,也可以不。 创建一个media
文件夹
2. 配置上传文件保存目录
其中创建一个 ImageField
的字段,upload_to
属性指定的是文件夹名称, 这个名称是 配置的上传文件保存目录下的文件夹名称
迁移生成这个模型类对应的表格 —— 内部的这个ImageField
字段就i变成一个列,用于存放图片保存到的地址信息,而不是完整图片内容。
注册模型类,使得后台可以访问
http://python.usyiyi.cn/documents/django_182/topics/http/file-uploads.html
http://python.usyiyi.cn/documents/django_182/ref/files/uploads.html#django.core.files.uploadedfile.UploadedFile
request.FILES[name属性]
可以访问到对应的上传文件处理器chunks
方法,来遍历获取文件内容,然后自行保存在文件内def upload_handle(request):
'''上传图片处理'''
# 1.获取上传文件的处理对象
pic = request.FILES['pic']
# 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')
如果之前在别的项目中使用的是同一个数据库,那么在执行迁移的时候,django是根据app名字+迁移文件名来执行迁移的,那么在之前的app+迁移文件名都相等的情况下,之后项目的迁移不会被执行。
解决办法:
Paginator
类对象的属性
属性名 | 说明 |
---|---|
count |
返回对象总数。 |
num_pages | 返回分页之后的总页数 |
page_range | 返回分页后页码的列表 |
Paginator
类对象的方法:
方法名 | 说明 |
---|---|
__init__(obj_list, int) |
返回分页对象,第一个参数为列表数据,第二个参数为每页数据的条数 |
page(self, number) | 返回第number页的Page 类实例对象 |
Page
类对象的属性
属性名 | 说明 |
---|---|
number | 返回当前页的页码 |
object_list | 返回包含当前页的数据的查询集 |
paginator | 返回对应的Paginator类对象 |
Page
类对象的方法
属性名 | 说明 |
---|---|
has_previous | 判断当前页是否有前一页 |
has_next | 判断当前页是否有下一页 |
previous_page_number | 返回前一页的页码 |
next_page_number | 返回下一页的页码 |
from django.core.paginator import Paginator # 分页对象
paginator = Paginator(areas, 10) #按每页10条数据进行分页
currentPage = paginator.page( currentPageNumber)
<html lang="en">
<head>
<meta charset="UTF-8">
<title>分页title>
head>
<body>
<ul>
{# 遍历获取每一条数据 #}
{# {% for area in page.object_list %}#}
{% for area in page %}
<li>{{ area.atitle }}li>
{% endfor %}
ul>
{# 判断是否有上一页 #}
{% if page.has_previous %}
<a href="/show_area{{ page.previous_page_number }}"><上一页a>
{% endif %}
{# 遍历显示页码的链接 #}
{% for pindex in page.paginator.page_range %}
{# 判断是否是当前页 #}
{% if pindex == page.number %}
{{ pindex }}
{% else %}
<a href="/show_area{{ pindex }}">{{ pindex }}a>
{% endif %}
{% endfor %}
{# 判断是否有下一页 #}
{% if page.has_next %}
<a href="/show_area{{ page.next_page_number }}">下一页>a>
{% endif %}
body>
html>