##Django是python写的重量级开源web框架,它组件丰富、向用户提供完整的开发文档,使用Django可以用少量的代码就能完成一个网站的大部分内容,极大的提高了开发效率。
##Django基于MVC模型(模型+视图+控制器)设计,该模型应用使Django项目的修改、拓展和代码复用变得更加方便和容易,同时Django还强调快速开发和DRY原则(Do Not Repeat Youself),而基于MVC框架Django有一个自己的名字MVT。
当用户点击注册时,用户名密码被提交到服务器;由控制器C去接收页面提交的数据;再由M将用户名和密码保存进数据库,然后数据库返回保存结果,并将结果传回给控制器C,然后通过V产生html页面,再由C将页面返回给浏览器。
安装Django环境:
pip install django
或 pip install django==版本号
创建项目:
django-admin startproject 项目名
创建应用(先要进入到项目中)
python manage.py startapp 应用名
此处创建的应用为booktest。
一个项目通常由多个不同的功能模块组成,在Django中每个功能模块用一个Django应用来开发,每一个应用完成一个特定的功能,所以在开发之前先要进行功能模块的划分。
应用目录结构:
- __init__.py: 说明booktest目录是一个python模块
- models.py: 用于写和数据库相关的内容
- views.py: 接受请求,处理请求,与M和T进行交互,返回应答,在该文件中定义**视图函数**
- tests.py: 用于写测试代码
- admin.py: 用于网站后台管理
- apps.py: 表示当前应用
- 目录migrations: 存放迁移文件
至此,项目和应用都已创建,但是要开发这个应用。还需要建立项目与应用之间的关系,即注册该应用。
建立项目和应用之间的关系(注册应用)
注册应用要在项目配置文件settings.py的INSTALLED_APPS中加入刚刚创建的应用名称。
在INSTALLED_APPS项中加入刚刚创建的应用名称:
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'booktest' # 注册应用
]
启动项目,看项目有没有创建成功
# 注意要先进入项目中,默认8000端口
python manage.py runserver
# 如果提示端口被占用,换个端口
python manage.py runserver 127.0.0.1:8001
在浏览器地址栏中输入127.0.0.1:8000(此处写你自己定义的端口号)如果出现以下,说明项目创建成功。
ORM(对象关系映射),它的作用是建立对象与关系型数据库表之间的映射,通过类和对象操作对应的数据表,避免了写复杂的SQL语句;ORM另一个作用是根据模型类迁移生成对应的数据表。Django中内置了ORM框架,在应用下的models.py文件中设计模型类。
定义模型类
# 在booktest(应用)下的models.py文件中
from django.db import models
# Create your models here.
# 设计和表对应的类
# 定义图书类(一类)
class BookInfo(models.Model):
"""图书模型类"""
# id会自动生成
# 字段名称,书名
book_title = models.CharField(max_length=20)
# 出版日期
public_date = models.DateField()
我们的目的是根据这个定义的模型类,生成数据库中对应的表,在Django中生成模型类对应的表两步走:
进入项目中,在终端执行迁移:
# 第一步 生成迁移文件
python manage.py makemigrations
# 第二步 执行迁移生成表
python manage.py migrate
得到以下结果说明迁移成功:
迁移成功之后我们在pycharm右侧数据库中可以看到已成功生成数据库:
表中字段名称和模型类中的字段名称是一致的,表名格式是: 应用名_模型类名。注意Django默认数据库是sqlite3数据库,可以在项目配置文件settings.py中修改DATABASES配置项,将数据库换成mysql或其他。
先进入项目shell:
python manage.py shell
以下操作在终端中执行:
# 导入模型类
In [1]: from booktest.models import BookInfo
# 实例化模型类
In [2]: b = BookInfo()
"""添加数据"""
# 添加书名
In [3]: b.book_title = "水浒传"
# 导入日期模块
In [4]: from datetime import date
# 添加出版日期
In [5]: b.public_date = date(2000,1,1)
# 存入数据库
In [6]: b.save()
"""查询数据"""
# 模型类.objects.get(条件)
In [7]: book_sh = BookInfo.objects.get(id=1)
In [10]: book_sh.book_title
Out[10]: '水浒传'
In [11]: book_sh.public_date
Out[11]: datetime.date(2000, 1, 1)
"""修改数据"""
In [12]: book_sh.public_date = date(2001,1,1)
# 要保存一下,才能修改成功
In [13]: book_sh.save()
In [14]: book_sh.public_date
Out[14]: datetime.date(2001, 1, 1) # 可以看到出版日期已修改
"""删除"""
In [15]: book_sh.delete()
"""退出终端"""
In [16]: quit()
Django模型常用字段与属性:
字段名称 | 字段描述 |
---|---|
CharField | 字符串类型,必须设置max_length |
IntergerField | 整数类型,可设置默认值default |
FloatField | 小数类型,可设置默认值default, 其他参数同下 |
DecimalField | 小数类型,参数max_digit表示总位,参数decimal_places表示位数 |
EmailField | 邮箱格式字符串 |
TextField | 文本类型 |
DateField | 日期类型 , 参数auto_now_add=True表示创建时间,不需要给他传参数 |
FileField | 文件类型,可以保存文件路径,同时自动上传文件,必须设置upload_to上传到媒体路径下的位置 |
ImageField | 图片文件类型,可以保存文件路径,同时自动上传文件,必须设置upload_to上传到媒体路径下的位置 |
- | - |
属性名称 | 属性描述 |
default | 设置默认值 |
primary_key | 值为True,则该字段是主键,默认False |
unique | True,表示这个字段在表中只能出现一次,默认False |
db_index | True,则会在表中为此字段建立索引,默认False |
db_columen | 指定字段名称, 默认使类属性名称 |
null | True,表示允许为空,默认为False。数据库的范畴 |
blank | True,表示允许在后台管理添加数据时不填,默认为False |
建立图书类与英雄类之间一对多关系
# 定义图书类(一类)
class BookInfo(models.Model):
"""图书模型类"""
# id会自动生成
# 字段名称,书名
book_title = models.CharField(max_length=20)
# 出版日期
public_date = models.DateField()
# 英雄人物类(多类)
# 英雄名 性别 年龄 备注
# 图书类与英雄人物类之间是一对多关系
class HeroInfo(models.Model):
"""英雄人物类"""
# 英雄名
hero_name = models.CharField(max_length=20)
# 性别 BooleanField为布尔值, 默认False(男性)
hero_gender = models.BooleanField(default=False)
# 备注
hero_demo = models.CharField(max_length=128)
# 年龄
hero_age = models.IntegerField()
# 外键 图书类与英雄类之间的一对多关系,多表中有一个外键
"""多类中定义关系属性"""
hero_book = models.ForeignKey(to='BookInfo', on_delete=models.CASCADE)
一对多关系操作
以下操作在shell中执行: python manage.py shell
进入shell
"""一对多基本操作"""
# 导入模型类
In [1]: from booktest.models import BookInfo, HeroInfo
# 实例化一个图书模型类
In [2]: b = BookInfo()
# 导入日期函数
In [3]: from datetime import date
# 实例化英雄模型类
In [4]: h = HeroInfo()
# 添加一个英雄的信息
In [5]: h.hero_name = "林冲"
In [6]: h.hero_gender = False
In [7]: h.hero_age = 10
In [8]: h.hero_demo = "豹子头林冲"
# 取出水浒传(id=1)
In [9]: book_sh = BookInfo.objects.get(id=1)
"""关联"""
# 关联英雄类与图书类
In [10]: h.hero_book = book_sh
# 保存
In [11]: h.save()
"""一查多"""
# 查询一本书中所有的英雄(一查多: 一.多类名小写_set.all())
# 得到的结果是对象集合
In [12]: book_sh.heroinfo_set.all()
Out[12]: <QuerySet [<HeroInfo: HeroInfo object (1)>]>
查询函数:
通过 模型类.objects 属性可以调用如下函数,实现模型类对数据表 的快速操作
函数名 | 功能 | 返回值 | 说明 |
---|---|---|---|
get | 返回表中满足条件的一条且只能有一条数据 | 模型类对象 | 查询到多条会抛出异常 |
all | 返回表中满足条件的所有数据 | QuerySet | 返回值称作查询集 |
filter | 返回满足条件的数据 | QuerySet | filter查询方法 |
exclude | 返回不满足条件的数据 | QuerySet | 和filter用法一致,只是返回的数据和filter返回的数据相反 |
order_by | 对查询结果进行排序 | QuerySet | 参数中写根据哪些条件进行排序 |
Q对象 | 用于查询条件之间的逻辑关系,not and or,可以对Q对象进行& ~ | QuerySet | 使用之前需要先导入form django.db.models import F 使用方法 |
F对象 | 用于属性之间的比较 | QuerySet | 使用之前需要先导入form django.db.models import Q |
除上述用法之外,还有聚合函数。而QuerySet(得到的结果)还可以继续调用上述方法。query.exists()可以查询查询集是否为空,False为空。 |
后台管理的作用: 帮助我们管理数据表
Django提供了强大的后台管理功能,由应用下的admin.py管理。使用它需要执行以下步骤:
本地化
- 语言和时区本地化
- 修改项目配置文件settings.py中的语言和时区项
- `LANGUAGE_CODE = 'zh-hans'`
- `TIME_ZONE = 'Asia/Shanghai'`
创建管理员账户
python manage.py createsuperuser
登录后台管理页面:
python manage.py runserver
http://127.0.0.1:8000/admin
注册模型类
在应用下的admin.py中注册模型类,告诉Django框架根据注册的模型类来生成对应的管理界面。
from django.contrib import admin
# 导入图书模型类(其它模型类的注册方法也是一样的)
from .models import BookInfo
# Register your models here.
# 注册图书模型类
admin.site.register(BookInfo)
自定义Django后台管理页面
虽然已经将模型类注册,但是进去发现显示的信息不是我们想要的,此时就需要自定义模型管理类,来美化Django后台管理页面。
class BookInfoAdmin(admin.ModelAdmin):
"""自定义图书模型管理类"""
# 定义要显示的字段列表
list_display = ['id', 'book_title', 'public_date']
# 注册图书模型类,将自定义的模型管理类也传入register
admin.site.register(BookInfo, BookInfoAdmin)
"""其他模型类的注册方式也是一样的"""
在Django中,通过浏览器去请求一个页面时,是使用视图函数来处理这个请求的,视图函数处理之后,要给浏览器返回页面内容。
定义视图函数
视图函数定义在应用下的views.py中,此时我们只有一个应用那么就在booktest应用目录下的views.py中定义视图函数,视图函数就是python中普通的函数,定义一个index视图函数当用户输入http://127.0.0.1:8000/index显示Hello, Django!:
from django.shortcuts import render
from django.http import HttpResponse
# Create your views here.
# 第一步定义视图函数
# 第二步进行url配置,目的是建立url地址和视图之间的关系
def index(request):
"""用户输入http://127.0.0.1:8000/index显示"""
# 此处写处理,与M和T进行交互
# 最终需要返回一个HttpResponse对象
return HttpResponse("Hello, Django!")
为了让Django知道URl对应的视图函数是这个视图函数,还需要进行URL配置。
配置URL
首先在应用目录下面(此处是booktest)新建一个urls.py;然后在项目管理目录下的urls.py中加配置项:
"""项目管理目录下的urls.py中"""
from django.conf.urls import url
from django.contrib import admin
from django.urls import path, include
# 项目的urls文件
urlpatterns = [
path('admin/', admin.site.urls), # 配置项
url(r'^', include('booktest.urls')), # 包含刚刚创建的应用booktest里面的urls文件
]
然后回到刚刚新建的应用目录下面(此处是booktest)的urls.py中,通过URL函数建立视图函数和路由之间的关系:
"""应用目录下面(此处是booktest)的urls.py"""
from django.conf.urls import url
from . import views
urlpatterns = [
# 通过url函数设置url路由的配置项
url(r'^index', views.index), # 建立index视图和index路由之间的关系
]
访问http://127.0.0.1:8000/index,成功显示:
当我们通过浏览器输入一个地址时,Django拿到的是去除域名后的这部分(/不参与匹配),它会拿这一部分先到项目的urls.py中进行查找,也就是和urlpatterns中的路由配置项正则表达式进行匹配; 匹配成功就执行include里面的动作,然后找到应用中的urls.py, 继续和URL函数设置的路由配置项进行匹配,匹配成功就执行该配置项中的视图函数,然后再由视图函数返回HttpResponse,渲染到页面就是我们看到的内容。
为了让HttpResponse返回一个标准的html页面,就需要使用模板。
在上面的例子中,我们返回了一个字符串,要返回一个标准的HTML页面,就需要使用模板。Django中的模板不仅仅可以返回HTML文件,也可以返回变量,甚至是代码。
创建模板目录templates
在项目目录下新建一个模板文件夹,以后所有的模板文件将放入这个文件夹:
建好模板目录之后,需要配置模板目录。
配置模板目录
在项目管理目录下的项目管理文件settings.py中,修改TEMPLATES项下的DIRS
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
# BASE_DIR是项目所在绝对路径
'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',
],
},
},
]
使用模板文件
Django中使用模板文件有四步:
Django内部提供了一个render方法,使用时直接调用即可。
重新定义模板文件(在应用下的views.py中):
from django.shortcuts import render
from django.http import HttpResponse
# Create your views here.
# 第一步定义视图函数
# 第二步进行url配置,目的是建立url地址和视图之间的关系
# def index(request):
# """用户输入http://127.0.0.1:8000/index显示"""
# return HttpResponse("Hello, Django!")
def index(request):
"""用户输入http://127.0.0.1:8000/index显示"""
# return HttpResponse("Hello, Django!")
return render(request, 'booktest/index.html', {'content': "Hello, Django!"})
渲染模板
根据你使用的数据,替换页面上的显示的数据:
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>模板文件title>
head>
<body>
<h3>这是一个模板文件h3>
<h4>这是渲染过来的的数据:h4>
/*jinjia2渲染模板*/
<p>{{ content }}p>
body>
html>
**回顾:**
- 1.创建Django项目:django-admin startproject 项目名称
- 2.**进入项目**创建应用: python manage.py startapp 应用名称
- 3.在项目配置文件 settings.py中 注册app: 将app名加入到INSTALLED_APPS项中
- 4.本地化项目: 在 项目配置文件settings.py中 修改 LANGUAGE_CODE 与 TIME_ZONE
- 5.启动项目: python manage.py runserver
- 完成以上步骤,就可以进行基本开发了
多数时候,我们SQLITE数据库不能满足开发需要,通常我们使用MySQL数据库进行开发,那就需要配置MySQL数据库。
"""在项目配置文件settings.py中"""
DATABASES = {
'default': {
# 'ENGINE': 'django.db.backends.sqlite3',
'ENGINE': 'django.db.backends.mysql',
# 'NAME': BASE_DIR / 'db.sqlite3',
'NAME': 'test', # mysql数据库名,注意这个数据库必须手动建好,否则报错
'USER': 'root', # mysql用户名
'PASSWORD': 'root', # 用户名对应的密码
'HOST': 'localhost', # 指定mysql地址,此处是本地
'PORT': 3306 # 端口号
}
}
然后启动项目,可能会出现以下错误:
django.core.exceptions.ImproperlyConfigured: Error loading MySQLdb module.
Did you install mysqlclient?
这时候按Ctrl+C退出,在应用下的__init__.py中添加下面两句:
"""应用下的__init__.py中"""
# 未安装pymysql,先安装pymysql
import pymysql
pymysql.install_as_MySQLdb()
Django中的重定向: 当视图函数处理完成一个逻辑后,不需要向浏览器呈现数据,而是转回到其它页面(可以理解为调用其它的视图函数),给出一个大佬的博客Django重定向的几种方法。
模型类关系
一对多关系
models.ForeignKey()
定义在多的类中
比如图书模型类与英雄模型类:
# to参数为一类类名
hero_book = models.ForeignKey(to='BookInfo', on_delete=models.CASCADE)
多对多关系
models.ManyToManyField()
定义在哪个类中都可以
比如新闻模型类与新闻类型模型类:
# 新闻类型类
class NewsType(models.Model):
# 新闻类型名
type_name = models.CharField(max_length=20)
"""关系属性,也可以定义在新闻模型类中"""
type_news = models.ManyToManyField(to='NewsInfo')
# 新闻类
class NewsInfo(models.Model):
# 新闻标题
news_title = models.CharField(max_length=128)
# 发布时间
news_date = models.DateField(auto_now_add=True)
# 信息内容
news_content = models.TextField()
一对一关系
models.OneToOneField()
定义在哪个类中都可以
比如员工基本信息类与员工详细信息类,员工工号唯一
# 员工基本信息类
class EmployeeBasicInfo(models.Model):
employ_name = models.CharField(max_length=20)
employ_age = models.IntegerField()
employ_gender = models.BooleanField(default=False)
"""关系属性,也可以定义在员工详细信息模型类中"""
detail_employ = models.OneToOneField(to='EmployeeDetailInfo', on_delete=models.CASCADE)
# 员工详细信息类
class EmployeeDetailInfo(models.Model):
employ_addr = models.CharField(max_length=256)
employ_tel = models.CharField(max_length=20)
一对多关联查询(通过模型类实现)
在一对多关系中,一对应的类叫做一类,多对应的类叫做多类,我们把类中建立模型类与模型类关联的属性叫做关系属性。
通过对象查询的方法:
由一类的对象查询多类的时候:
一类的对象.多类名小写_set.all()
由多类的对象查询一类的时候:
多类的对象.关联属性
由多类的对象查询一类对象的id的时候:
多类的对象.关联属性_id
通过模型类实现关联查询的方法:
通过多类的条件查询一类的数据:
一类名.objects.filter(多类名小写__多类属性名__条件名)
通过一类的条件查询多类的数据:
多类名.objects.filter(关联属性__一类属性名__条件名)
例1:查询id为1的图书关联的英雄的信息:
原来的查询方法(根据对象去查询):
# 先查询id为1的图书
b = BookInfo.objects.get(id=1)
# 再用这个[书]去查询它里面的英雄
b.heroinfo__set.all()
通过模型类查询
# 通过一类的条件查询多类的数据
HeroInfo.objects.filter(hero_book__id=1)
例2:查询id为1的英雄关联的图书的信息:
原来的查询方法(根据对象去查询)
# 先查询id为1的英雄
h = HeroInfo.objects.get(id=1)
# 然后再用这个[英雄]去查和他相关的那本书
# hero_book是关系属性名
h_book =h.hero_book
通过模型类查询
# 通过多类的条件查询一类的数据
# 一类名.objects.filter(多类名小写__多类属性名__条件名)
BookInfo.objects.filter(heroinfo__id=1)
例3:查询图书信息,要求图书中英雄的描述包含’八’:
# 通过多类的条件查询一类的数据
# 一类名.objects.filter(多类名小写__多类属性名__条件名)
BookInfo.objects.filter(heroinfo__hero_dmeo__contains='八')
例4:查询图书信息,要求图书中的英雄的id大于3:
通过模型类查询
# 通过多类的条件查询一类的数据
# 一类名.objects.filter(多类名小写__多类属性名__条件名)
BookInfo.objects.filter(heroinfo__id__gt=3)
例5:查询书名为天龙八部的所有英雄:
通过模型类查询
# 通过一类的条件查询多类的数据
# 多类名.objects.filter(关联属性__一类属性名__条件名)
HeroInfo.objects.filter(hero_book__book_title='天龙八部')
模型-自关联
所谓的自关联是一种特殊的一对多关系,只是这种一对多关系对用的数据都在一张表里。
以地区自关联模型为例(最终结果是做一个显示徐州上下级地区的功能):
定义地区模型类
# 地区模型类
class AreaInfo(models.Model):
# 地区名称
area_title = models.CharField(max_length=128)
# 关系属性,代表当前地区的父级地区,null表示可以为空,self参数表示自关联
area_parent = models.ForeignKey('self', null=True, blank=True, on_delete=models.CASCADE)
注册模型类
"""在应用下的admin.py中"""
# 注册地区模型类
admin.site.register(AreaInfo)
迁移生成数据库
# 生成迁移文件
python manage.py makemigrations
# 执行迁移
python manage.py migrate
定义视图函数
"""在应用下的views.py中"""
def areas(request):
"""获取徐州市的上几地区和下级地区"""
# 获取徐州市的信息
area = AreaInfo.objects.get(area_title='徐州市')
# 查询徐州市的上级地区
parent = area.area_parent
# 查询江苏省的下级地区
children = area.areainfo_set.all()
# 使用模板
return render(request, 'booktest/areas.html', {'area':area, 'parent':parent, 'children':children})
配置路由
"""在应用下的urls.py中"""
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^index', views.index),
url(r'^areas', views.areas) # 显示地区
]
在地址栏输入
http://127.0.0.1:8000/areas
模型_管理器
在查询的时候,BookInfo.objetcs.all()中的objects是什么呢?其实它是Django帮我们给每一个模型类自动生成的管理器对象,通过这个管理器可以实现对数据的查询。
objects是models.Manger类的一个对象。当我们自定义管理器之后,Django不再帮我们生成默认的objects管理器。
自定义管理器步骤
自定义管理器类的应用场景:
不过一般情况下,我们也不去修改这个东西,如果需要自定义管理器请参照Django开发文档(我的电脑不知道为什么进不了Django官网,在此就不放链接了)。
模型元选项_指定模型类对应的表名
当我们指定了模型类对应的表名之后,就可以随意修改应用名而不使程序因为修改应用名发生错误了。
方法: 在模型类中再定义一个Meta类,然后将Meta类的类属性db_table = 指定的表名即可。
以图书类为例:
# Create your models here.
# 建立图书模型类, 一类
class BookInfo(models.Model):
book_title = models.CharField(max_length=20)
public_date = models.DateField()
book_read = models.IntegerField(default=0)
book_comment = models.IntegerField(default=0)
# 逻辑删除标记(软删除)
is_delete = models.BooleanField(default=False)
class Meta:
"""将图书模型类对应的表名指定为bookinfo"""
db_table = 'bookinfo'
def __str__(self):
return self.book_title
视图的功能
视图的功能:接受请求,进行处理,与M和T交互,返回应答。
返回应答是html:render,也可能是重定向:redirect,还可能是JsonResponse。
视图函数的使用
定义视图函数
视图函数就是一个普通的函数,必须要有request参数。这个request参数是一个HttpRequest类型的对象,参数名可以变化,但是不建议更改。
配置url
目的是建立url和视图函数之间的对应关系。
定义模板文件
有模板文件就在templates下面配置html文件
url配置的过程
视图_错误视图
当用户输入一个你的网站不存在的地址时,会显示Page not found(404)和项目url配置信息,这样url配置信息将会全部暴露给用户,为了避免这个问题,当项目开发完之后,要将项目配置文件settings.py中的DEBUG设置为False。然后刷新,将不会再出现项目url的配置信息,而是返回一个标准的404页面。有时候我们想返回一个自定义的404页面,那么应该怎么做?
自定义404页面
直接在Django项目模板目录templates(不是某个应用)下新建一个404.html,当用户输入一个不存在的地址或出现url配置错误或没有配置URl时,Django会自动返回这个页面。
自定义500页面
500是视图函数中出现了错误。同样的,如果你不想用Django默认的500页面,那么同样在Django项目模板目录templates下新建一个500.html,出现视图函数错误时,Django会自动返回这个页面。
视图_捕获URL参数
进行url匹配时,把所需要的捕获的部分设置成一个正则表达式组,这样Django框架就会自动把匹配成功后相应组的内容作为参数传递给视图函数。有两种类型:
捕获位置参数
参数名可以随意指定
"""在应用下的urls.py中定义url配置项"""
from django.conf.urls import url, include
from django.contrib import admin
from django.urls import path
from . import views
urlpatterns =[
url(r'^index', views.index),
# 定义一个测试的url,当输入这个地址时,Django会将组匹配到的参数传递给后面的视图函数
url(r'test(\d+)', views.test), # 捕获url位置参数,只要你捕获了参数,那么在定义相应的视图函数时,必须要有形参
]
"""在应用下的views.py中定义测试url对应的视图函数"""
def test(request, para):
# para为捕获到的参数
return HttpResponse(para)
捕获关键字参数
在位置参数的基础上给正则表达式组命名即可。需要注意的是视图函数形参命名必须和该参数对应的组名一致。
"""在应用下的urls.py中定义url配置项"""
from django.conf.urls import url, include
from django.contrib import admin
from django.urls import path
from . import views
urlpatterns =[
url(r'^index', views.index),
# 定义一个测试的url,当输入这个地址时,Django会将组匹配到的参数传递给后面的视图函数
url(r'^test(\d+)', views.test), # 捕获url位置参数,只要你捕获了参数,那么在定义相应的视图函数时,必须要有形参
# 需要注意的是视图函数形参命名必须和该参数对应的组名一致
url(r'^test(?P\d+)' , views.test), # 捕获url关键字参数,只要你捕获了参数,那么在定义相应的视图函数时,必须要有形参
]
"""在应用下的views.py中定义测试url对应的视图函数"""
def test(request, num):
# para为捕获到的参数,参数名和正则表达式捕获到的组名一致
return HttpResponse(num)
视图函数的参数的作用
默认的request
接受HttpRequest对象,也是视图的第一个参数。该对象包含了浏览器请求的参数,比如请求头、请求参数之类的东西。通过post/get请求提交的参数就保存在该对象中。
HttpRequest对象属性
在视图函数中可以直接用request.属性名调用
视图_ajax(异步加载)
在不重新加载整个页面(即浏览器不再重新请求这个页面)的情况下,对页面内容进行局部刷新,目的是为了加快响应速度,提升用户体验。
Ajax请求的过程
前端页面发起Ajax请求;后端视图函数处理Ajax请求,处理完返回JsonResponse()数据;浏览器收到返回的JSON格式数据之后,执行回调函数,改动页面内容。
例:用ajax给页面加一个提示
配置静态文件路径
在项目目录下新建一个static文件夹(和模板目录templates同级),然后在该目录下创建三个文件夹:js、css、images分别保存项目的js文件、css文件和图片文件;最后将jquery-1.12.4.min.js放在js文件夹中。最后在项目配置文件settings.py中新增STATICFILES_DIRS项,该项值为:[os.path.join(BASE_DIR, ‘static’)]。
"""在项目配置文件settings.py中"""
STATIC_URL = '/static/'
# 静态文件目录
STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static')]
创建显示AJax页面的ajax.html模板文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Ajax请求测试</title>
<!-- 导入JS文件-->
<script src="/static/js/jquery-1.12.4.min.js"></script>
<!-- 点击按钮执行的JS脚本-->
<script>
$(function () {
//绑定btn的点击事件
$('#btn').click(function () {
$.ajax({
/*ajax请求的url*/
'url': '/ajax_handle',
'type': 'get',
'dataType': 'json'
}).success(function (data) {
//进行处理,data是Django后台(视图函数返回的数据)
//alert(data.res)
if (data.res == 1) {
/*显示提示信息*/
$('#msg').show().html('提示信息!')
}
})
})
})
</script>
<!-- ajax响应成功返回后在页面做的修改-->
<style>
#msg {
/*默认不显示*/
display: none;
color: red;
}
</style>
</head>
<body>
<!--发送Ajax请求的按钮-->
<input type="button" id="btn" value="Ajax请求">
<div id="msg"></div>
</body>
</html>
定义视图函数
def ajax_test(request):
"""显示ajax页面"""
return render(request, 'booktest/ajax.html')
def ajax_handle(request):
"""处理ajax请求"""
# 视图函数返回的数据{'res': 1}
return JsonResponse({'res': 1})
配置url
"""在应用的urls.py中的urlpatterns中添加下面这两项"""
url(r'^ajax$', views.ajax_test), # 显示ajax页面
url(r'^ajax_handle$', views.ajax_handle)
cookie和session用于用户状态保持,可以让用户在一段时间内无需重复登录就可以访问网站内容。
cookie是由服务器生成,存储在浏览器端的一小段文本信息。
cookie的特点
通过HttpRequest对象的COOKIES属性进行会话的读写操作
response.set_cookie('键', '值', max_age=秒数)
,设置cookie用的是HttpResponse对象request.COOKIES['键']
键 in request.COOKIES
session和cookie不同的一点是,session存储在服务器端。
session的特点
通过HttpRequest对象的session属性进行会话的读写操作
request.session['键'] = 值
request.session.get('键', '默认值')
request.session.clear()
request.session.flush()
del request.session['键']
request.session.set_expiry(秒数)
,默认两周过期request.session.has_key('键')
cookie和session的应用场景
模板功能
产生html,控制页面上展示的内容,模板文件不仅仅是一个html文件,模板文件包含两部分内容:
模板文件的使用
通常是在视图函数中使用模板产生html内容返回给客户端。
模板文件的加载顺序
模板变量
模板变量名是由数字、字母、下划线组成的,不能以下划线开头。
使用模板变量:{{ 模板变量名 }}
模板变量的解析顺序
例如:{{ book.book_title }}
{% 代码段 %},代码段在大括号百分号中间。模板标签用于空值页面输出。
for循环
{% for x in 列表 %}
// 列表不为空时执行
{% empty %}
// 列表为空时执行
{% endfor %}
可以通过 {{ forloop.counter }}得到for循环遍历到了第几次。
if 条件控制
{% if 条件 %}
{% elif 条件 %}
{% else %}
{% endif %}
关系比较运算符:>、<、>=、<=、==、!=
逻辑运算: not and or
##注意:比较操作符两边必须有空格
过滤器用于对模板变量进行操作,改变模板变量的默认输出。
格式: {{ 模板变量 | 过滤器: 参数 }}
默认过滤器
自定义过滤器
自定义过滤器必须定义在应用下的templatetags包下,而且必须要有一个参数,最多只能有两个参数。
在应用下新建一个包,叫templatetags
然后在templatetags下新建一个py文件
"""booktest/templatetags/filter.py中"""
# 自定义过滤器
# 过滤器的本质其实就是Python函数
from django.template import Library
# 实例化一个Library对象
register = Library()
@register.filter
def mod(num):
"""自定义过滤器判断num是否为偶数"""
return num % 2 == 0
在模板目录templates下对应应用下的模板文件中使用自定义过滤器
DOCTYPE html>
<html lang="en">
{% load filter %}
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
{% if val|mod %}
<h2>val是偶数h2>
{% else %}
<h2>val不是偶数h2>
body>
html>
单行注释:{# 注释内容 #}
多行注释:
{# comment #}
注释内容
{# endcomment #}
模板继承是为了复用html页面中共有的代码,比如同一网站的导航条与版权信息。
继承
在子页面中:{% extends 'booktest/base.html' %}
,然后base.html有的内容子页面也就有了。需要注意的是,在父模板中要给子页面独有的内容预留位置,叫预留块。用: {% block 块名%}...{% endblock 块名 %}
。
子模板中重写块
在子模板中不重写块的内容,继承时就会使用父模板中的内容。
重写子模板中的内容:
{% block 块名%}
子模板内容
{% endblock 块名 %}
即用父模板内容又要重写父模板内容
{% block.super %}
// 先继承父模板block内容,然后再重写
{% block 块名%}
子模板内容
{% endblock 块名 %}
模板继承什么时候用?
将所有页面共有的内容放在父模板中,什么位置的内容不同,就在什么地方预留块,然后在子页面中重写这个块。
在模板变量中如果包含<、>、&、'、"等,会被自动转义,原样显示(被当成字符串显示)。但是我就想让它能被当成正常的html语句怎么办?办法就是在模板文件中关闭html转义。
通过safe过滤器关闭
{{ 变量名|safe }}
此时该变量会被当成html语句渲染到页面。
使用autoescape模板标签
{% autoescape %}
模板变量
{% endautoescape %}
Django是默认开启CSRF保护的,在项目配置文件settings.py中MIDDLEWARE项下:
'django.middleware.csrf.CsrfViewMiddleware', # Django默认开启CSRF,但是只针对post请求
无CSRF时,攻击者可以从其他站点发起相同的http请求,从而获取会话中的COOKIE/SESSION等用户信息,造成安全隐患。
页面中
<form action="/login/" method="POST">
{% csrf_token %}
<input type="text" name="username" placeholder="用户名"/>
<input type="password" name="password" placeholder="密码"/>
<input type="submit" value="登录"/>
form>
Ajax配置
注意要引用脚本jquery.cookie.js
<script src="/static/js/jquery-1.12.4.js"></script>
<script src="/static/js/jquery.cookie.js"></script>
<script>
// ajax csrf配置
var csrftoken = $.cookie('csrftoken');
function csrfSafeMethod(method) {
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$.ajaxSetup({
beforeSend: function(xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}
});
</script>
给视图函数添加CSRF
from django.views.decorators.csrf import csrf_exempt, csrf_protect
@csrf_protect
def login(request):
"""显示登录界面"""
# 有用户session
if request.session.has_key('isLogin'):
return redirect('/index')
# 无用户session,返回登录页
else:
# 获取cookie和username
if 'account' in request.COOKIES:
# 获取账号
account = request.COOKIES['account']
else:
account = ''
return render(request, 'booktest/login.html', {'account': account})
如果要关闭某个视图函数的CSRF,使用csrf_exempt
装饰器即可。
作用:当某一个url配置的地址发生变化时,页面上使用反向解析生成的地址不需要发生变化。
暂时没有用到,放一篇参考文献。
在网页中使用的JS、CSS、图片、JSON文件等都属于静态文件。
在项目配置文件settings.py中配置静态文件的路径
STATIC_URL = '/static/'
STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static')]
使用的时候直接: /static/css/xx.css就可以了。
中间件函数是Django框架留给我们预留的函数接口,让我们干预请求和应答过程。
还有一部分内容,后期用的时候再补充吧