Django框架总结

一、Django框架前言知识:

1、C/S和B/S的区别:

  • C/S结构软件:
    客户端/服务端软件,即客户端要自己下载,安装之后才能访问服务端,服务端为开发的服务器。
  • B/S结构软件:
    浏览器/服务端软件,即客户端不需要自己下载,客户只需要在电脑上用浏览器访问客户端即可访问服务端。
  • 一般的web框架都是B/S结构软件,在浏览器上输入http://www.127.0.0.1/(默认端口8000)即可访问。

2、HTTP协议(超文本传输协议)

  • 超文本传输协议是一个基于TCP/IP通讯协议来传递数据,是属于应用层的面向对象协议,浏览器作为HTTP客户端通过URL向HTTP服务端发送请求,WEB服务端根据收到的请求后,向客户端发送响应信息。
  • 主要特点:简单快速、无连接、无状态、主持B/S及C/S模式。

3、URL构成:

http://www.aspxfans.com:8080/news/index.aspboard?ID=5&ID=24618&page=1#


1、协议部分:http
2、域名部分:www.aspxfans.com
3、端口部分:8080
4、虚拟目录部分:从域名后’的第一个"/"到最后一个"/"为止,news
5、文件名部分:从域名红的最后一个"/"开始到"?"结束,index.aspboard
6、锚部分:从"#"开始
7、参数部分:从"?"开始,参数都是键值对形式。

二、Django框架基本流程

1.png

1、配置虚拟环境:

  • Window 10平台:

pip 升级:python -m pip install -upgrade pip
virtualenv安装: pip install virtualenv
virtualenvwrapper安装:pip install virtualenvwrapper-win
设置 WORK_HOME环境变量:设置虚拟环境的路径,将虚拟环境的文件目录添加到环境变量中 :WORKON_HOME = D: test/virtualenv

  • Ubuntu平台:

pip 安装:sudo apt install python3-pip
pip 升级:sudo python3 -m pip install --upgrade pip
Virtualenv 安装:sudo python3 -m pip install
virtualenvwrapper 安装:sudo python3 -m pip install
打开~/.bashrc 文件:
cd /usr/local/bin
sudo gedit virtualenvwrapper.sh
在结尾添加:

    export WORKON_HOME=$HOME/.virtualenvs
    export PROJECT_HOME=$HOME/workspace
    source /usr/local/bin/virtualenvwrapper.sh

然后执行: source ~/.bashrc
将设置在文件中的配置信息马上生效,而不需要经过重启。
所有的虚拟环境,都位于/home/.virtualenvs 目录下


报错: /usr/bin/python: No module named virtualenvwrapper
原因: Ubuntu 安装了 2.7 和 3.x 两个版本的 python,在安装时使用的是 sudo pip3 install virtualenvwrapper
在运行的时候默认使用的是 python2.x,但在 python2.x 中不存在对应的模块。
解决办法: 增加此环境变量:VIRTUALENVWRAPPER_PYTHON=/usr/bin/python3
注意:在 ubuntu 下以点开头命名的文件和文件夹是隐藏的,如果需要修改它们,如何看见?按 ctrl+h.就能看见以点号开头的隐藏文件.

虚拟环境的相关操作:

创建:mkvirtualenv 虚拟环境名称
进入:workon 虚拟环境名称
退出:deactivate 虚拟环境名
删除:rmvirtualenv 虚拟环境名

2、安装mysql-python:

  python 2.7 :pip install mysql-python
  python 3.0:pip3  install pymysql

3、创建django项目:

django-admin startproject 项目名

4、创建django项目中的app:

cd 项目名
python manage.py startapp 应用名

5、配置setting文件:

1.修改数据库的相关配置:

 "ENGINE":"django.db.backends.mysql",
 "NAME":"数据库名",
 "USER":"root",
 "HOST":"localhost",
 "PORT":3306,
 "PASSWORD":"密码",

2.修改模版的配置:

在模版的配置文件中加入存放模版的路径
设置 TEMPLATES 的 DIRS 值:
'DIRS': [os.path.join(BASE_DIR, 'templates')]

3.修改静态文件的配置:

在setting中配置:
STATIC_URL = '/static/'
STATICFILES_DIRS = [ os.path.join(BASE_DIR, 'static'), ]

6、注意:python3 无法正常使用 mysql 的解决办法

django 连接 mysql 默认驱动是 MySQLdb, MySQLdb 没有支持 python3 的版本,
在 django 项目配置文件同目录下的init.py 文件中加入以下代码:
import pymysql
pymysql.install_as_MySQLdb()

7、models.py的编写

from django.db import models
class BookInfo(models.Model):
      btitle = models.CharField(max_length=20)
      bpub_date = models.DateTimeField()
      def __str__(self):
            return "%d" % self.pk
class HeroInfo(models.Model):
      hname = models.CharField(max_length=20)
      hgender = models.BooleanField()
      hcontent = models.CharField(max_length=100)
      hBook = models.ForeignKey('BookInfo' ,on_delete=models.CASCADE)
      def __str__(self):
            return "%d" % self.pk

生成迁移文件,执行迁移

生成迁移之前,要把app应用添加到setting配置文件中的INSTALLED_APPS中

python manage.py makemigrations
python manage.py migrate

注意:

1.python3 无法正常使用 mysql 的解决办法

django 连接 mysql 默认驱动是 MySQLdb, MySQLdb 没有支持 python3 的版本
在 django 项目配置文件同目录下的init.py 文件中加入以下代码:

import pymysql
pymysql.install_as_MySQLdb()

2、 python3 外键定义报错

hBook = models.ForeignKey('BookInfo')
Django2.0 下运行会提示这样的错误:
typeError: init() missing 1 required positional argument:'on_delete'
解决办法:
hBook = models.ForeignKey('BookInfo',on_delete=models.CASCADE)

3、生成迁移文件报错

django.db.utils.InternalError:(1049,"Unknown database 'books'")
手工创建数据库 books

8、views.py的编写

在 django 中,视图对 WEB 请求进行回应
视图就是一个 Python 函数,被定义在 views.py 中
视图接收 reqeust 对象作为第一个参数,包含了请求的信息

from django.http import HttpResponse
    def index(request):
          return HttpResponse("home page test.")

说明:
1.第二行引入 HttpResponse,它是用来向网页返回内容。

  1. index()函数第一个参数必须是 request,与网页发来的请求有关,request 变量里面包含 get 或 post 的内容,用户浏览器,系统等信息在里面 。
  2. 函数返回了一个 HttpResponse 对象,最终显示几个字到网页上。

render简写

from django.shortcuts import render
from booktest.models import BookInfo
def index(reqeust):
       booklist = BookInfo.objects.all()
       return render(reqeust, 'booktest/index.html', {'booklist': booklist})
def detail(reqeust, id):
      book = BookInfo.objects.get(pk=id)
      return render(reqeust, 'booktest/detail.html', {'book': book})

URLconf

Django 使用正则表达式匹配请求的 URL,一旦匹配成功,则调用应用的视图。在 Django 中,定义 URLconf 包括正则表达式、视图两部分。
注意:只匹配路径部分,即除去域名、参数后的字符串
在 test1/urls.py 插入 booktest,使主 urlconf 连接到 booktest.urls 模块
url(r'^', include('booktest.urls')),
在 booktest 中的 urls.py 中添加 urlconf

from django.conf.urls import url
from . import views
urlpatterns = [
      url(r'^$', views.index),
      url(r'^([0-9]+)/$', views.detail),
]

urlpatterns 列表中来配置 url,每一个列表项就是一个由 url 函数的调用。
一个 project 中如果有多个 app,为避免 url 管理可能的混乱,在项目的 urls.py 用 include方法包含 myapp 中的 urls。

9、template.py的编写

<!DOCTYPE html>
<html>
<head>
  <title>首页</title>
</head>
<body>
  <h1>图书列表</h1>
  <ul>
  {%for book in booklist%}
    <li>
      <a href="{{book.id}}">
        {{book.btitle}}
      </a>
    </li>
  {%endfor%}
</ul>
</body>
</html>

定义 detail.html 模板

<!DOCTYPE html>
<html>
<head>
  <title>详细页</title>
</head>
<body>
  <h1>{{book.btitle}}</h1>
  <ul>
    {%for hero in book.heroinfo_set.all%}
    <li>{{hero.hname}}---{{hero.hcontent}}</li>
    {%endfor%}
  </ul>
</body>
</html>

10、启动服务器

python manage.py runserver ip:port
通过浏览器访问 http://127.0.0.1:8000/ 可进行访问服务器

11、创建超级管理员

python manage.py createsuperuser
编辑 settings.py 文件,设置编码、时区
默认值:

LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'

修改为:

LANGUAGE_CODE = 'zh-Hans'
TIME_ZONE = 'Asia/Shanghai'

向 admin 注册 booktest 的模型
打开 booktest/admin.py 文件,注册模型

from django.contrib import admin
from models import BookInfo
admin.site.register(BookInfo)

刷新管理页面,可以对 BookInfo 的数据进行增删改查操作
自定义管理页面
Django 提供了 admin.ModelAdmin 类
通过定义 ModelAdmin 的子类,来定义模型在 Admin 界面的显示方式

from django.contrib import admin
from models import BookInfo
class BookInfoAdmin(admin.ModelAdmin):
#list_display:显示字段,可以点击列头进行排序
list_display = ['id', 'btitle', 'bpub_date']
# list_filter: 过滤字段,过滤框会出现在右侧
list_filter = ['btitle']
# search_fields: 搜索字段,搜索框会出现在上侧
search_fields = ['btitle']
# list_per_page:分页,分页框会出现在下侧
list_per_page = 2
# fieldsets:属性分组
fieldsets = [
      ('基本信息', {'fields': ['btitle']}),
      ('更多信息', {'fields': ['bpub_date']}),
]
关联 BookInfor 对象
英雄和书是多对一的关系
from django.contrib import admin
from models import BookInfo,HeroInfo
class HeroInfoInline(admin.StackedInline):
model = HeroInfo
extra = 2 #额外显示关联的记录数
class BookInfoAdmin(admin.ModelAdmin):
      inlines = [HeroInfoInline]
      admin.site.register(BookInfo, BookInfoAdmin)

三、 Model

ORM 简介

ORM(Object-Relation Mapping)---对象关系映射:
它是MVC框架很重要的一部分,实现了数据模型与数据库的解耦,即数据模型的设计不需要依赖于特定的数据库,通过简单的配置就可以轻松更换数据库。
这个中间件可以独立存在于框架之外,在MVT框架中可以将用python语言书写的模型类映射成数据库表,用python语言来代替复杂的SQL语句来对数据库进行CDRU操作,最后返回对应的对象和列表。
ORM分为两种:
1、DB First:数据里先创建表,然后根据表结构,生成对应的代码
2、Code First:先书写对应的代码,再执行代码生成对应数据库表
使用ORM的优点:
-摆脱复杂的 SQL 操作;
-让数据结构变得简洁;
-数据库迁移成本更低;

开发流程

1、在 models.py 中定义模型类,要求继承自 models.Model
2、把应用加入 settings.py 文件的 installed_app 项
3、生成迁移文件
4、 执行迁移生成表
5、使用模型类进行 crud 操作

定义属性

  1. 导入 from django.db import models
  2. 通过 models.Field 创建字段类型的对象,赋值给属性Python 之:
    对于重要数据都做逻辑删除,不做物理删除,实现方法是定义 isDelete 属性,类型为BooleanField,默认值为 False

字段类型

1.AutoField:一个根据ID自动增长的 IntegerField
Django会为表自动增长的主键列,如果使用设置的主键列,django不会再生成默认的主键列
id = models.AutoField(primary_key=True)
2.BooleanField:true/false字段
3.NullBooleanField:支持null、true、false三种
4.TextField:大文本字段,一般超过4000使用
5.CharField(max_length=字符长度):字符串类型
6.IntegerField:整型
7.DecimalField(max_digits=None,decimal_places=None): 十进制浮点型
-----DecimalField.max_digits:位数总数
-----DecimalField.decimal_paleces:小数点后的数字位数
8.FloatField:浮点型
9.DateField(auto_now=False,auto_now_add=False):日期类型
-----DateField.auto_now:每次保存对象时,自动设置该字段为当前时间,用于"最后一次修改"的时间戳,它总是使用当前日期,默认为 false
-----DateField.auto_now_add:当对象第一次被创建时自动设置当前时间,用于创建的时间戳,它总是使用当前日期,默认为 false
-----auto_now_add, auto_now, and default 这些设置是相互排斥的,他们之间的任何组合将会发生错误的结果,因此只能设置一个
10.TimeField:时间字段,参数如DateField所示
11.DateTimeField:时间日期字段,参数如DateField所示
12.FieField:上传文件字段
13.ImageField:图片字段
---------上传路径设置:

STATICFILES_DIRS=[
os.path.join(BASE_DIR,'static')
]
MEDIA_ROOT=os.path.join(BASE_DIR,"static/media")

字段选项

null:如果为 True, Django 将空值以 NULL 存储到数据库中,默认值是 False
blank:如果为 True,则该字段允许为空白,默认值是 False
-----对比: null 是数据库范畴的概念, blank 是表单验证证范畴的
-----如果一个字段设置为 blank=True,表单验证时允许输入一个空值。而blank=False,则该项必需输入数据。
db_column:字段的名称,如果未指定,则使用属性的名称
db_index:若值为 True, 则在表中会为此字段创建索引
default:默认值
primary_key:若为 True, 则该字段会成为模型的主键字段
unique:如果为 True,该字段在表中必须有唯一的值
verbose_name 字段的一种说明,在 form 中不会显示,和 label 是这个 Field 在 form中会显示的文本提示
help_text:会在 form 表单控件中显示 help 文本

关系

1.OneToOneField:一对一关系,将字段定义在任意一端中
跨表访问数据库表:
——有外键字段的表:对象.外键字段
——无外键字段的表:对象.模型类小写
2.ForeignKey:一对多关系,将字段定义在多的一端中
跨表访问数据库表:
——有外键字段的表:对象.外键字段
——无外键字段的表:对象.模型类小写._set()
3.ManyToManyField:多对多关系,将字段定义在任意一端中
会在数据库中生成第三张表,例如:

class Host(models.Model):
  id = models.AutoField(primary_key=True)
  hostname = models.CharField(max_length=32)
  ip = models.GenericIPAddressField(protocol='ipv4')
  port = models.IntegerField()
  def __str__(self):
    return self.hostname

class Application(models.Model):
  name = models.CharField(max_length=32)
  r = models.ManyToManyField(to='Host') # 这个字段在表里不存在。

添加

a=Application('qq')
a.save()
h1=Host(hostname='host1',ip='192.168.1.20',port='8000')
h1.save()
h2=Host(hostname='host2',ip='192.168.1.21',port='8001')
h2.save()
h3=Host(hostname='host3',ip='192.168.1.22',port='8002')
h3.save()
a.r.add(1) #对第三张表添加 application_id=1,host_id=1

查询

a.r.all()

反向查询(在没有 ManyToManyField 字段的表中查)

h1.application_set.all()

元选项

——在模型类中定义类Meta,用于设置元信息
————元信息:db_table:定义数据库表名,推荐使用小写字母,数据库表有默认表名
———— ording:数据库表有默认排序,字符串前加-表示倒序,不加-表示正序

管理器Manager

管理器是 Django 的模型进行数据库的查询操作的接口,用于与数据库进行交互,Django应用的每个模型都拥有至少一个管理器当定义模型类时没有指定管理器,则 Django 会为模型类提供一个名为 objects 的管理器

自定义管理器:

继承 models.Manager
自定义管理器类主要用于两种情况
情况一:向管理器类中添加额外的方法:见下面“创建对象” 中的方式二
情况二:修改管理器返回的原始查询集:重写 get_queryset()方法
当为模型类指定管理器后, django 不再为模型类生成名为 objects 的默认管理器

class BookInfoManager(models.Manager):
    def get_queryset(self):
         return super(BookInfoManager,self).get_queryset().filter(isDelete=False)
class BookInfo(models.Model):
    ...
books = BookInfoManager()

查询

查询集表示从数据库中获取的对象集合返回查询集的方法,称为过滤器
过滤器基于所给的参数限制查询的结果,从 Sql 的角度,查询集和 select 语句等价,过滤器像 where 和 limit 子句,查询集是可迭代的对象.
过滤器:

  • all() : 检索所有的对象
  • filter(**kwargs) : 检索特定的对象 返回一个与参数匹配的 QuerySet
  • exclude(): 返回一个与参数不匹配的 QuerySet
  • order_by(column_name): 检索排序后的对象
  • column_name:排序的列,默认升序, 列名前加- 降序排序
  • get():返回单个满足条件的对象
    如果未找到会引发"模型类.DoesNotExist"异常
    如果多条被返回,会引发"模型类.MultipleObjectsReturned"异常
  • count():返回当前查询的总条数
  • first():返回第一个对象
  • last():返回最后一个对象
  • exists():判断查询集中是否有数据,如果有则返回 True

查询集返回列表,可以使用下标的方式进行限制,等同于 sql 中的 limit 和 offset 子句,不支持负索引

条件查询

实现 where 子名,作为方法 filter()、 exclude()、 get()的参数
语法:属性名称__比较运算符=值
表示两个下划线,左侧是属性名称,右侧是比较类型
对于外键,使用“属性名_id” 表示外键的原始值
转义: like 语句中使用了%与,匹配数据中的%与,在过滤器中直接写,例如:
filter(title__contains="%")=>where title like '%%%',表示查找标题中包含%的

比较运算符

  • 判等:exact
  • 包含:contains
  • 开头或结尾:startswith/endswith
  • 是否为空:isnull
  • 大小写不敏感:在前面加上i表示不区分大小写
  • 不连续查询
    -- in:是否包含在范围内
    --gt、gte、lt、lte:大于、大于等于、小于、小于等于
  • 时间日期查询:
    -- year、 month、 day、 week_day、 hour、 minute、 second
    -- 对日期时间类型的属性进行运算:
BookInfo.books.filter(bpub_date__year=1980)
BookInfo.books.filter(bpub_date__gt=date(1980, 12, 31))
BookInfo.books.filter(bpub_date__gt=date(1990, 12, 31))
注意:
为避免查询 month 和 day 结果为空,请在 setting.py 中设置:
USE_TZ = False

跨关联查询

语法:模型类名_属性名_比较,相当于SQL语句中inner join

聚合函数

使用aggregate()函数返回聚合函数的值
函数:Avg、Count、Max、Min、Sum

F对象

  1. 通常情况下我们更新数据时先从数据库里将原数据取出放在内存后,然后修改对应的值,最后保存到数据库。
    当框架中出现F对象时,django会使用SQL语句的方式取代标准的python操作,python唯一做的操作是生成一条SQL语句,在数据库中完成对对应属性的更改,这种方式可以在多并发的情况下提高操作的效率,减少多线程操作带来的风险。
  2. 可以使用F对象完成两个字段中值的比较,此外,F对象还能完成算数运算,例如:
    list.filter(bread__gte=F('bcommet') * 2)
    list.filter(bread__gte=F('bcommet'))
    list.filter(bpub_date__lt=F('bpub_date') + timedelta(days=1))

Q对象

在使用过滤器进行查询时,可以对查询条件进行限制,当有多个条件时,要使用Q对象够构造相应的语句。
构造符号:&(与)或者|(或) ~(非)

四、View

view1.png

视图的本质就是一个函数,被定义在view.py文件中,响应的可以是一张网页的HTML内容,一个重定向,一个404错误等

URLconf

在django框架中,提供了非常清晰简洁的url管理方法。
步骤:
1.在根级urls.py文件中加入 应用的url配置:
url('^user/',include('user.urls',namespace='user')),
2.在应用中新建urls.py文件:

from django.conf.urls import url
from . import views,viewsUtil

app_name='user'
urlpatterns = [
   url('^register/',views.register,name='register'),
   url('^register_handle/',views.register_handle,name='register_handle'),
   url(r'^verifycode/$',viewsUtil.verify,name='verifycode'),
   url('^login/',views.login,name='login'),
   url('^login_handle/',views.login_handle,name='login_handle'),
]

include()方法

include(arg, namespace=None)

  • arg:包含 应用的 urlconf
  • namespace:定义命名空间,用于反解析

url()方法

def url(regex, view, kwargs=None, name=None)

  • regex : 正则表达式
  • view: 视图函数
  • name: 名称
  • name 用来唯一区分一个视图对应多个 urlconf 的场景
  • kwargs: 就是一个字典类型的参数

编写 URLconf 的注意

  • 不需要添加一个前导的反斜杠,如应该写作'booktest/',而不应该写作'/booktest/',否则意味着从根目录匹配
  • 每个正则表达式前面的 r 表示字符串不转义,请求的 url 被看做是一个普通的 python 字符串,进行匹配时不包括 get 或 post 请求的参数及域名。

http://www.qikuedu.com/python/1/?i=1&p=new,只匹配“python/1/” 部分
性能: urlpatterns 中的每个正则表达式在第一次访问它们时被编译,这使得系统相当快

匹配url过程:

先与主URLconf匹配,成功后再用剩余的部分与应用中的URLconf匹配

请求 http://127.0.0.1:8000/booktest/1/
用 booktest/1/与项目的 urls 匹配
在项目 urls.py 中的配置:
url(r'^booktest/', include('booktest.urls')),
去除匹配过的部分,剩余部分部分是: 1/
用“1/” 与 booktest 应用的 urls 匹配
url(r'^([0-9]+)/$', views.detail, name='detail'),

URL反向解析

  • 问题: 如果在视图、模板中使用硬编码的链接,在 urlconf 发生改变时,维护非常麻烦
  • 解决: 通过指向 urlconf 的名称, 根据正则表达式动态生成链接地址
  • 视图中的使用: 使用 django.urls.reverse()函数
from django.urls import reverse
from django.http import HttpResponseRedirect

def test(reqeust, id):
    return HttpResponseRedirect(reverse('booktest:detail', args=(1,)))
  • 模板中的使用:
    -- django2.x:
    <a href="{% url 'booktest:detail' book.id %}">{{ book.btitle }}</a>
    多个参数的传递:
    <a href="{% url 'booktest:detail2' book.id book.id %}">{{ book.btitle }}</a>
    应用 url conf: url(r'^detail2/(\d+)/(\d+)/$',views.detail2,name='detail2'),
    -- django 早期版本:
    <a href="{% url 'booktest.views.detail' book.id %}">{{ book.btitle }}</a>

错误视图

404(page not found)视图

当抛出 Http404 异常时, Django 会加载一个特殊的 view 方法django.views.defaults.page_not_found 处理 404 错误。
它负责加载和渲染 404.html 模板文件。
这意味着我们必须在模板根目录定义 404.html 模板文件,该模板文件应用于所有的 404异常。
defaults.page_not_found(request, template_name='404.html')
默认的 404 视图将传递一个变量给模板: request_path,它是导致错误的 URL
如果 Django 检测 URLconf 中的每个正则表达式后没有找到匹配的内容将调用 404 视图

自定义404错误视图:
  • 在 settings.py 中修改调试:
DEBUG = False
ALLOWED_HOSTS = ['*', ]
  • 在 templates 中创建 404.html
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
    找不到了
<hr/>
    {{request_path}}
</body>
</html>

500(server error)视图

当 view 代码发生运行时错误时, Django 将会调用默认地 view 方法
django.views.defaults.server_error, 该方法加载渲染 500.html 模板文件。
这意味着我们必须在模板根目录定义 500.html 模板文件,该模板文件应用于所有的服务器错误。
defaults.server_error(request, template_name='500.html')
默认的 500 视图不会传递变量给 500.html 模板
如果在 settings 中 DEBUG 设置为 True,那么将永远不会调用 500 视图,而是显示URLconf 并带有一些调试信息

400(bad request)视图

from django.views import defaults
defaults.bad_request(request, template_name='400.html')
错误来自客户端的操作
例如当用户进行的操作在安全方面可疑的时候,例如篡改会话 cookie

403(Forbidden)视图

某些恶意网站上包含链接、表单按钮或者JS,利用登录过的用户在浏览器的认证信息试图在网站上完成某些操作,这就是跨站攻击。为了防止跨站攻击,django中在提交表单时有跨站请求保护,因此要在提交表单时要添加Cross Site Request Forgery (跨站请求伪造),如果没有添加,则会报403错误,如图所示:


403.png
  • 添加跨站请求方法:
    1.在 settings.py 中启用'django.middleware.csrf.CsrfViewMiddleware'中间件,此项在创建项目时,默认被启用
    2.在表单下添加
    {% csrf_token %}
  • 取消保护:
    可以使用装饰器 csrf_exempt,模板中也不需要写标签
  • 跨站请求原理
    加入标签后,可以查看源代码,发现多了如下代码
<input type='hidden' name='csrfmiddlewaretoken'
value='nGjAB3Md9ZSb4NmG1sXDolPmh3bR2g59' />

Request对象

HttpRequest对象

服务器接受到http协议请求后,会创建HttpRequest对象
视图函数的第一个参数是 HttpRequest对象,在django.http模块中定义了HttpRequest对象的API

属性

  • path:一个字符串,表示请求的页面的完整路径,不包含域名
  • method:一个字符串,表示请求使用的 HTTP 方法,常用值包括: 'GET'、 'POST'
  • encoding:一个字符串,表示提交的数据的编码方式
  • get:一个类似于字典的对象,包含 get 请求方式的所有参数
  • post:一个类似于字典的对象,包含 post 请求方式的所有参数
  • files:一个类似于字典的对象,包含所有的上传文件
  • cookies:一个标准的 Python 字典,包含所有的 cookie,键和值都为字符串
  • session:一个既可读又可写的类似于字典的对象,表示当前的会话,只有当 Django 启用会话的支持时才可用,详细内容见“状态保持”

方法

  • is_ajax():如果请求是通过 XMLHttpRequest 发起的,则返回 True

QueryDict 对象

定义在 django.http.QueryDict,request 对象的属性 GET、 POST 都是 QueryDict 类型的对象。与 python 字典不同, QueryDict 类型的对象用来处理同一个键带有多个值的情况。

get()

根据键获取值,只能获取一个值;如果一个键同时拥有多个值,获取最后一个值

getlist()

将键的值以列表返回,可以获取一个键的多个值

GET属性

包含 get 请求方式的所有参数,与 url 请求地址中的参数对应,位于?后面
参数的格式是键值对,如 key1=value1
多个参数之间,使用&连接,如 key1=value1&key2=value2
键是开发人员定下来的,值是可变的

POST属性

包含 post 请求方式的所有参数
与 form 表单中的控件对应,控件要有 name 属性,则 name 属性的值为键, value 属性的值为键,构成键值对提交
对于 checkbox 控件, name 属性一样为一组,当控件被选中后会被提交,存在一键多值的情况,键是开发人员定下来的,值是可变

Response对象

HttpResponse对象

在 django.http 模块中定义了 HttpResponse 对象的 API
HttpRequest 对象由 Django 自动创建, HttpResponse 对象由程序员创建
不调用模板,直接返回数据。

属性

  • content:表示返回的内容,字符串类型
  • charset:表示 response 采用的编码字符集,字符串类型
  • status_code: HTTP 响应状态码
  • content-type:指定输出的 MIME 类型

方法

  • init :使用页内容实例化 HttpResponse 对象
  • write(content):以文件的方式写
  • flush():以文件的方式输出缓存区

子类HttpResponseRedirect

重定向,服务器跳转
return HttpResponseRedirect('http://www.baidu.com')

子类JsonResponse

返回 json 数据,一般用于异步请求
帮助用户创建 JSON 编码的响应
参数 data 是字典对象
JsonResponse 的默认 Content-Type 为 application/json

from django.http import JsonResponse
def index2(requeset):
    return JsonResponse({'list': 'abc'})
def search(request):  
    kw = request.GET.get('kw')  
    word = Cnword.objects.filter(words__startswith=kw).values('words')[0:10]  
    # 返回django.db.models.query.ValuesQuerySet对象  
    # word = Cnword.objects.filter(words__startswith=kw)[0:10]  
    # 返回django.db.models.query.QuerySet对象  
    if word:  
        word = list(word) #ValuesQuerySet对象需要先转换成list  
        data = json.dumps(word) # 把list转成json  
        # data = serializers.serialize("json", word) #django.db.models.query.QuerySet对象可以序列化  
        return HttpResponse(data) #返回json  
    return HttpResponse('false')  

不需要全部字段时,可以用values('字段名','字段名2')来要求返回的是哪些列的数据.但是返回来的是ValuesQuerySet对象而不是QuerySet对象.
ValuesQuerySet对象 不能用 serializers.serialize() 方法序列化成json 需要先转换成list 再用 json.dumps()方法序列化成json
如果是直接models.objects.filter()查询出来的queryset对象,要用serializers.serialize() 方法序列化成json

状态保持

http 协议是无状态的:每次请求都是一次新的请求,不会记得之前通信的状态,因此实现状态保持的方式:在客户端或服务器端存储与会话有关的数据,存储方式包括 cookie、 session,会话一般指 session 对象。

  • 使用 cookie,所有数据存储在客户端,注意不要存储敏感信息
  • 使用 sesison ,所有数据存储在服务器端,在客户端 cookie 中存储 session_id,一般使用session来进行状态保持

使用session

  • get(key, default=None):根据键获取会话的值
  • clear():清除所有会话
  • flush():删除当前的会话数据并删除会话的 Cookie
  • del request.session['member_id']:删除会话

设置会话过期时间

set_expiry(value):设置会话的超时时间

  • 如果没有指定,则两个星期后过期
  • 如果 value 是一个整数,会话将在 values 秒没有活动后过期
  • 如果 value 是一个 timedelta 对象,会话将在当前时间加上这个指定的日期/时间过期
  • 如果 value 为 0,那么用户会话的 Cookie 将在用户的浏览器关闭时过期
  • 如果 value 为 None,那么会话永不过期

存储会话的方式

可以使用 settings.py 的 CACHES 中指定 SESSION_ENGINE 项

  • 基于数据库的会话
    SESSION_ENGINE='django.contrib.sessions.backends.db'
    session中的值默认是保存在django_session这张表里面且有效期是1209600秒
  • 基于缓存的会话
    SESSION_ENGINE='django.contrib.sessions.backends.cache'
    只存在本地缓存中,如果丢失则不能找回,比数据库的方式读写更快
  • 缓存和数据库同时使用
    SESSION_ENGINE='django.contrib.sessions.backends.cached_db'
    优先从本地缓存中获取,如果没有则从数据库中获取
  • 也可使用redis缓存session
    安装包 pip install django-redis-sessions==0.5.6
    修改 settings 中的配置,增加如下项
SESSION_ENGINE = 'redis_sessions.session'
SESSION_REDIS_HOST = 'localhost'
SESSION_REDIS_PORT = 6379
SESSION_REDIS_DB = 1
SESSION_REDIS_PASSWORD = '123'
SESSION_REDIS_PREFIX = 'session'

五、Template

  • Django框架提供了模板,可以很便利的动态生成HTML,模板的设计实现了逻辑和显示内容的分离,模板那包含:HTML的静态部分;动态插入内容部分
  • Django模板语言,简写DTL,定义在django.template包中,由startproject命令生成的settings.py定义关于模板的值:
    **DIRS定义了一个目录列表,模板引擎按照列表顺序搜索这些目录以查找模板源文件
    **APP_DIRS告诉模板引擎是否应该在每个已安装的应用中查找模板
    *常用用法:在项目的根目录下创建templates目录,设置DIRS的值
    DIRS=[os.path.join(BASE_DIR,"templates")]

模板处理步骤

Django处理模板分为两个阶段:

  • Step1 加载:根据给定的标识找到模板后预处理,将它编译好放在内存中
    loader.get_template(template_name)
  • Step2渲染:使用Content数据对模板插值并返回生成的字符串
    Template 对象的render(RequestContent)方法,使用context渲染模板
加载渲染模板的完整代码
from django.template import loader,RequestContext
from django.http import HttpResponse

def index(request):
  tem = loader.get_template('template/index.html')
  context = {}
  return HttpResponse(tem.render(context))
快捷函数

为了减少加载模板、渲染模板的重复代码,django提供了快捷函数

render_to_string("")
render(request,'模板',context)

模板语言

  • 模板语言包括
    • 变量{{ variable }}
    • 标签{%代码块%}
    • 过滤器
    • 注释

变量名

  • 变量名必须由字母、数字、下划线(不能以下划线开头)和点组成
  • 当模板引擎遇到点("."),会按照下列顺序查询:
    • 字典查询,例如:foo["bar"]
    • 属性或方法查询,例如:foo.bar
    • 数字索引查询,例如:foo[bar]
  • 如果变量不存在, 模板系统将插入空字符串

标签

语法:{% tag %}

for标签

  • Django 不支持退出循环操作。 如果想退出,可以让迭代变量仅包含需要迭代的项目。
  • Django 也不支持 continue 语句,我们无法让当前迭代操作跳回到循环头部。
  • 例如:
{% for item in item_list %}
  代码块
{% empty %}
  代码块
{% endfor %}

reversed标签:使得该列表被反向迭代

{% for item in item_list reversed%}

if标签

{% if ...... %}
代码块
{% elif ......%}
代码块
{% else %}
代码块
{% endif %}

逻辑运算符:and、or、not

注释标签

多行注释:{% comment %}

include标签:加载模板并以标签内的参数渲染

{%include "foo/bar.html" %}

url标签

  • 反向生成url
    {% url 'booktest.views.detail' book.id %}

csrf_token标签:这个标签用于跨站请求伪造

{% csrf_token%}

过滤器

  • {{ 变量|过滤器}}
    例如{ { name|lower }},表示将变量 name 的值变为小写输出
  • 过滤器链
    name|lower|upper
  • 过滤器参数传递
    list|join:","
    *设置默认值
    value|default:"什么也没有"

模板继承

语法:

  • 定义父模板base.html
    {%block block_name%}
    这里可以定义默认值
    如果不定义默认值,则表示空字符串
    { %endblock%}
  • 定义子模版 index.html
    {% extends "base.html" %}
  • 在子模版中使用block填充预留区域
    {% block block_name %}
    实际填充内容
    {% endblock %}

注意:django框架中最多只有三层模板继承结构

会被转义的字符

  • html转义,就是将包含的html标签输出,而不被执行
  • 原因是当显示用户提交字符串时,可能包含一些攻击性的代码,如js脚本
  • Django会将如下字串自动转义:
< 会转换为&lt
> 会转换为&gt
' (单引号) 会转换为&#39
" (双引号)会转换为 &quot
& 会转换为 &amp

关闭转义

  • 对于变量使用safe过滤器
    {{ data|safe }}
  • 对于代码块使用autoescape标签
{% autoescape off %}
{{ body }}
{% endautoescape %}

六、其他

验证码

详细文档参考: http://pillow.readthedocs.io/en/latest/

步骤:
  • 新建viewsUtil.py,定义verify
  • Image 表示画布对象
  • ImageDraw 表示画笔对象
  • ImageFont 表示字体对象
实例代码:
from django.http import HttpResponse
from PIL import Image,ImageDraw,ImageFont
import random
import io
# Create your views here.
def verify(request):
  # 定义变量,用于画面的背景色、宽、高
  bg_color = (random.randrange(20,100),random.randrange(20,100),255)
  width = 100
  height = 25
  # 创建画面对象
  im = Image.new('RGB',(width,height),bg_color)
  # 创建画笔对象
  draw = ImageDraw.Draw(im)
  # 调用画笔的 point()函数绘制噪点
  for i in range(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(4):
    rand_str = rand_str + str1[random.randrange(0,len(str1)-1)]
  print(rand_str)
  # 构造字体对象
  font = ImageFont.truetype('FZSTK.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
  print(request.session.get('verifycode'))
  # 将图片保存在内存中,文件类型为 png
  f = io.BytesIO()
  im.save(f,'png')
  # 将内存中的图片数据返回给客户端,MIME 类型为图片 png
  return HttpResponse(f.getvalue(), 'image/png')

View视图函数

def verify_page(request):
  verify(request)
  template = loader.get_template("verifycode/index.html")
  return HttpResponse(template.render())

显示验证码

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>
  <div>Hello world</div>
  <img id='verifycode' src="/verifycode/" alt="CheckCode"/>
</body>
</html>
扩展验证码

需求:点击“看不清,话一个”时,可以换一个新的验证码
View视图函数

from django.http import HttpResponse
from django.template import loader
from .viewsUtil import verify

def verify_page(request):
  verify(request)
  template = loader.get_template("verifycode/index.html")
  return HttpResponse(template.render())

def verifycodeValid(request):
  vc = request.POST['vc']
  if vc.upper() == request.session['verifycode']:
    return HttpResponse('ok')
  else:
    return HttpResponse('no')

Template模板
点击事件处理

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>title</title>
<script type="text/javascript" src="/static/jquery-1.12.4.min.js"></script>
<script type="text/javascript">
$(function () {
  $('#verifycodeChange').css('cursor', 'pointer').click(function () {
    $('#verifycode').attr('src', $('#verifycode').attr('src') + 1)
});
});
</script>
</head>
<body>
  <div>Hello world</div>
  <form method='post' action='/verifycodeValid/'>
    <input type="text" name="vc">
    <img id='verifycode' src="/verify/?1" alt="CheckCode"/>
    <span id='verifycodeChange'>看不清,换一个</span>
    <br>
    <input type="submit" value="提交">
  </form>
</body>
</html>

管理静态文件

  • 在settings文件中定义静态内容
STATIC_URL = '/static/'
STATICFILES_DIRS = [
  os.path.join(BASE_DIR,'static'),
]
  • 上传图片
    • 当django在处理文件上传的时候,文件数据会被保存到request.FILES中
    • FILES中的每个键为<input type="file" name="" />中的name
  • 注意:
    • FILES请求的方法为POST
    • 提交的<form>带有enctype="multipart/form-data"
  • 图片存储路径
    • 在项目根目录下static的目录下创建media文件夹
    • 图片上传后,会被保存到"/static/media/图片文件"
      settings.py文件中增加media_root项
      MEDIA_ROOT=os.path.join(BASE_DIR,"static/media")

分页

Paginator对象

Paginator(列表,int):返回分页对象,参数为列表数据,每面数据的条数

属性:
  • count:对象总数
  • num_pages:页面总数
  • page_range:页码列表,从1开始,例如[1,2,3,4]
方法:

page(num):下标从1开始,如果提供的页码不存在,则抛出InvalidPage异常

Page对象

Page对象由Paginator对象的page()方法色和归纳成返回Page对象

属性
  • object_list:当前页上所有对象的列表
  • number:当前页的序号,从1开始
  • paginator:当前page对象相关的Paginator对象
方法
  • has_next():如果有下一页返回True
  • has_previous():如果有上一页返回True
  • has_other_pages():如果有上一页或者有下一页返回True
  • next_page_number():返回下一页的页码,如果下一页不存在,则抛出InvalidPage异常
  • previous_page_number():返回上一页的页码,如果上一页页码不存在,则抛出InvalidPage异常
  • len():返回房前页对象的个数
  • 迭代页面对象:访问当前页面中的每个对象

富文本编辑器

  • 下载安装django_tinymce
    pip install django-tinymce
  • 将tinymce添加到APPS中
  • 在settings.py中添加编辑配置项
TINYMCE_DEFAULT_CONFIG = {
'theme': 'advanced',
'width': 600,
'height': 400,
}
  • 定义模型类是要加上HTMLField字段
  • 在模板中添加
<script type="text/javascript">
  tinyMCE.init({
    'mode':'textareas',
    'theme':'advanced',
    'width':400,
    'height':100
});
</script>

全文检索

Django中提供了一个Haystack包,可以提供模块化的搜索,提供了一个有好的API,支持不同的后端搜索引擎,例如whoosh、solr、Xapian、Elasticsearc等
1、在虚拟环境中以次安装包
pip install django-haystack
pip install whoosh
pip install jieba
2、添加应用:将haystack添加到应用中
3、添加搜索引擎

HAYSTACK_CONNECTIONS = {
'default': {
'ENGINE': 'booktest.whoosh_cn_backend.WhooshEngine',
'PATH': os.path.join(BASE_DIR, 'whoosh_index'),
}
}

4、分页设置

HAYSTACK_SEARCH_RESULTS_PER_PAGE = 10

设置对搜索结果的分页,每 10 项结果为一页。
5、索引生成设置

HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.RealtimeSignalProcessor'

这里设置实时更新索引
7、创建索引类
在应用目录下加你了search_indexes.py文件

from haystack import indexes
from booktest.models import HeroInfo
class HeroInfoIndex(indexes.SearchIndex,   indexes.Indexable):
  text = indexes.CharField(document=True, use_template=True)
  def get_model(self):
    return HeroInfo
  def index_queryset(self, using=None):
    return self.get_model().objects.all()

8、设置数据模板
在目录"templates/search/indexes/应用名称/"下创建"模型类名称_text.txt"文件

heroinfo_text.txt,这里列出了要对哪些列的内容进行检索
{{ object.hname }}
{{ object.hcontent }}
{{ object.hgender }}
这个数据模板的作用是对 HeroInfo. hname、HeroInfo. hcontent、HeroInfo. hgender
这三个字段建立索引,当检索的时候会对这三个字段做全文检索匹配,然后将匹配的结果排序后作为搜索结果返回

9、在项目的urls.py中添加url

urlpatterns = [
...
url(r'^search/', include('haystack.urls')),
]

10、创建搜索结果界面
在目录下'templates/search/'下建立search.html

<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
  {% if query %}
    <h3>搜索结果如下:</h3>
    {% for result in page.object_list %}
      <a href="/{{ result.object.id }}/">{{ result.object.hname }}</a> <br/>
      {% empty %}
      <p>啥也没找到</p>
    {% endfor %}
    {% if page.has_previous or page.has_next %}
      <div>
        {% if page.has_previous %}
          <a href="?q={{ query }}&amp;page={{ page.previous_page_number }}">
        {% endif %}&laquo; 上一页{% if page.has_previous %}</a>{% endif %}
          |
        {% if page.has_next %}
          <a href="?q={{ query }}&amp;page={{ page.next_page_number }}">{% endif %}下一页 &raquo;{% if page.has_next %}</a>
        {% endif %}
      </div>
    {% endif %}
  {% endif %}
</body>
</html>

11、修改搜索引擎为中文分词
复制 Lib\site-packages\haystack\backends\whoosh_backend.py 文件,粘贴到应用目录下(这里是 booktest)改名为whoosh_cn_backend.py

from jieba.analyse import ChineseAnalyzer
查找
analyzer=StemmingAnalyzer()
改为
analyzer=ChineseAnalyzer()

12、生成索引
python manage.py rebuild_index
13、在模板中创建搜索栏

<form method='get' action="/search/" target="_blank">
  <input type="text" name="q">
  <input type="submit" value="查询">
</form>

缓存

设置缓存

在setting文件中添加CACHES配置

CACHES={
  'default': {
    'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
    'TIMEOUT': 60,
  }
}
  • TIMEOUT:缓存的默认过期时间,以秒为单位,默认是300秒,如果为none,则是永远不会过期;如果为0,则是缓存立即失效;
  • BACKEND:设置缓存位置,如果为LocMemCache,则缓存在内存中;如果为RedisCache,则缓存在redis中
from django.core.cache import cache
设置:cache.set(键,值,有效时间)
获取:cache.get(键)
删除:cache.delete(键)
清空:cache.clear()

缓存View视图

示例代码:

from django.views.decorators.cache import cache_page
@cache_page(60 * 15)
def index(request):
  return HttpResponse('hello1')

缓存模板片段

示例代码:

{% load cache %}
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>
{% cache 500 hello %}
hello3
<!--hello2-->
{% endcache %}
</body>
</html>
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335

推荐阅读更多精彩内容