Django

一、Django 简介

  Django 是一个由 Python 写成的开放源代码的 Web 应用框架。它最初是被开发来用于管理劳伦斯出版集团旗下的一些以新闻内容为主的网站的,即是 CMS(内容管理系统)软件。并于2005年7月在 BSD 许可证下发布。这套框架是以比利时的吉普赛爵士吉他手 Django Reinhardt 来命名的。由于 Django 的是在一个快节奏的新闻编辑室环境下开发的,它的目的是使常见的 Web 开发任务,快速和容易。

 

MTV 模式

Django 采用了 MTV 设计模式

上述图大概是说:

  1. URL ( urls.py )请求调度,当有缓存页面的时候直接返回内容。
  2. 视图函数( view.py )执行所请求的操作,通常包括读写数据库。
  3. 模型( models.py )定义了 Python 中的数据并与之交互。通常包含在一个关系数据库( MySQL、PostgreSQL SQLite 等),其他数据存储是可能的( XML、文本文件、LDAP、等)。
  4. 请求执行任务后,视图返回一个 HTTP 响应对象(通常是经过数据处理的一个模板)。可选的:视图可以保存一个版本的 HTTP 响应对象,返回携带一个时间戳,来告诉浏览器这个视图的更新时间。
  5. 模板通常返回 HTML 页面。Django 模板语言提供了 HTML 的语法及逻辑。

 

 

 安装

# pip 安装
pip install Django==1.10

# 克隆下载最新版本
git clone https://github.com/django/django.git

# 导入django模块
>>> import django
>>> print(django.get_version())
1.10

 

二、基本配置

1、常用命令

# 查看django版本
$ python -m django --version

# 创建项目,名为mysite
$ django-admin startproject mysite

# 启动django
$ python manage.py runserver
$ python manage.py runserver 8080
$ python manage.py runserver 0.0.0.0:8000

# 创建应用程序,确保和 manage.py 是同一目录
$ python manage.py startapp polls

# 运行创造模型变化迁移
$ python manage.py makemigrations

# 运行应用模型变化到数据库
$ python manage.py migrate

# admin创建管理员用户
$ python manage.py createsuperuser

注:自动重新加载 runserver,根据需要开发服务器自动重新加载Python代码为每个请求。您不需要重新启动服务器代码更改生效。然而,像添加文件某些操作不触发重新启动,所以你必须重新启动在这些情况下的服务器。

基本目录结构及作用:

mysite/              # 项目的容器,名字随便起
    manage.py        # 命令行实用工具,以各种方式与该Django项目进行交互
    mysite/          # 实际的Python项目
        __init__.py  # 空文件,导入不出错
        settings.py  # 这个Django项目配置
        urls.py      # 这个Django项目的URL声明; 一个Django驱动网站的“目录”
        wsgi.py      # 一个入口点为WSGI兼容的Web服务器,以满足您的项目

 

 2、配置文件

数据库

# 由于Django内部连接MySQL时使用的是MySQLdb模块,而python3中还无此模块,所以需要使用pymysql来代替
  
# 如下设置放置的与project同名的配置的 __init__.py文件中
  
import pymysql
pymysql.install_as_MySQLdb() 
# 在settings 中修改DATABASES 

DATABASES = {
    'default': {
    'ENGINE': 'django.db.backends.mysql',
    'NAME':'dbname',
    'USER': 'root',
    'PASSWORD': 'xxx',
    'HOST': '',
    'PORT': '',
    }
}

模板 

# 也在settings里修改,放html文件

TEMPLATE_DIRS = (
        os.path.join(BASE_DIR,'templates'),
    )

 静态文件

# 依然在settings里修改添加,放css,js等文件

STATICFILES_DIRS = (
        os.path.join(BASE_DIR,'static'),
    )

 

 三、路由系统

1、URL 调度

一个干净,优雅的 URL 方案是一个高质量的 Web 应用程序的一个重要的细节。

tornado 不同的是一个 url 对应一个函数,而并非一个类。

像是一个新华字典的目录,对应了 views 函数来进行处理,即这个 url 要用某个指定的 views 函数处理。

来看以下示例,如何动态构造:

from app1 import views

urlpatterns = [
    url(r'^manage1/(\d*)', views.manage1),
    url(r'^manage2/(?P<name>\w*)/(?P<id>\d*)', views.manage2),
    url(r'^manage3/(?P<name>\w*)', views.manage3,{'id':333}),
]

# 需要注意
# url多传了一个参数,那views函数得多接受一个参数 
# 对应接收值

def manage1(request, age):
    print(age)        # 18
    return HttpResponse('1')

def manage2(request, name, id):
    print(name, id)     # nick 18
    return HttpResponse('2')

def manage3(request, name, id):
    print(name, id)     # nick 666
    return HttpResponse('3')
对应 views 函数接收值

 

二级路由: 那如果映射 url 太多怎么办,全写一个在  urlpatterns 显得繁琐,so 二级路由应用而生

# 一级路由规定 app1 开头的都去 app1.urls 中找
# 二级在详细规定对应 views 函数

# 一级
urlpatterns = [
    url(r'^app1/', include('app1.urls')),
]

# 二级
urlpatterns = [
    url(r'^1$', views.manage1),
]

 

2、Django是如何处理一个请求

当用户请求从您的 Django 的网站页面,这是该系统遵循以确定哪些 Python 代码执行的算法:

  1. Django 请求是 URL 配置模块配置。通常通过值 ROOT_URLCONF 设置,但如果传入 HttpRequest 对象具有 urlconf 属性(由中间件设置),它的值将代替的可以使用  ROOT_URLCONF 的设置。
  2. Django 的负载是 Python 模块并寻找变量 urlpatterns。这是一个 django.conf.urls.url() 实例。
  3. Django 的贯穿每个 URL 模式,从而,在所请求的 URL 匹配的第一个停止。
  4. 一旦某个正则表达式相匹配,就运行相对应的视图函数(或基于类的视图)。该视图被传递以下参数:
    • HttpRequest 对象。
    • 如果匹配的正则表达式没有返回命名组,然后从正则表达式比赛是作为位置参数。
    • 关键词参数是由由正则表达式匹配的任何命名组,由指定的可选参数的任何覆盖的 kwargs参数 django.conf.urls.url()
  5. 如果没有正则表达式匹配,或者如果一个异常在这个过程中的任何一点时提出,Django的调用适当的错误处理视图。

 

3、官方示例

1> 以下代码是官方示例:

from django.conf.urls import url

from . import views

urlpatterns = [
    url(r'^articles/2003/$', views.special_case_2003),
    url(r'^articles/([0-9]{4})/$', views.year_archive),
    url(r'^articles/([0-9]{4})/([0-9]{2})/$', views.month_archive),
    url(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.article_detail),
]

 笔记注意事项:

  • 要捕获从URL中的值,用括号括起来,会当参数传入 views 视图。
  • 没有必要添加一个斜线,因为每个URL都有。例如,它^articles不是^/articles
  • 'r'前面的每个正则表达式字符串中是可选的,但建议。它告诉Python字符串是“原始” -没有什么字符串中应该进行转义。

 举例请求:

  • 请求 /articles/2005/03/ 将匹配列表中的第三项。Django的将调用该函数 。views.month_archive(request,'2005', '03')
  • /articles/2005/3/  不会匹配任何 URL 模式,因为在列表中的第三项中需要两位数字的月份。
  • /articles/2003/ 将匹配的列表,而不是第二个第一图案,因为该图案,以便测试,第一个是在第一测试通过。随意利用顺序插入特殊情况是这样的。在这里,Django的将调用该函数 views.special_case_2003(request)
  • /articles/2003 不匹配任何这些模式,因为每个模式要求 URL 以斜线结束。
  • /articles/2003/03/03/ 将匹配的最终格局。Django 的将调用该函数。views.article_detail(request,'2003', '03', '03')

 

 2> 命名组

上面的例子使用了简单的,非命名的正则表达式组(通过括号)来捕获 URL 的位,并通过他们的位置参数的视图。在更高级的用法,它可以使用命名 正则表达式组来捕获 URL 位,将它们作为关键字参数传递给视图。

 在 Python 正则表达式,命名正则表达式组的语法(?P<name>pattern),这里 name 是组的名称, pattern 就是某种模式相匹配。

 下面是上面的例子中的URLconf,改写使用命名组:

from django.conf.urls import url

from . import views

urlpatterns = [
    url(r'^articles/2003/$', views.special_case_2003),
    url(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive),
    url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.month_archive),
    url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<day>[0-9]{2})/$', views.article_detail),
]

这正好完成同样的事情,前面的例子,一个细微的差别:捕获的值传递给查看功能作为关键字参数,而不是位置参数。例如:

  • 请求/articles/2005/03/会调用函数来代替,views.month_archive(request, year='2005',month='03')views.month_archive(request, '2005', '03')
  • 请求/articles/2003/03/03/会调用该函数,views.article_detail(request, year='2003',month='03', day='03')

在实践中,这意味着你的 URLconf 稍微更明确,不容易参数顺序错误 - 你可以在你的意见'函数定义重新排序的参数。当然,这些优点来在简短的费用; 一些开发任务命名组的语法丑陋,太冗长。

匹配/分组算法

这里的URL配置解析器遵循算法,相对于正则表达式命名组与非命名组:

  1. 如果有任何命名参数,它会使用这些,而忽略非命名参数。
  2. 否则,它会通过所有非命名参数作为位置参数。

在这两种情况下,被赋予按任何额外的关键字参数传递额外的选项来查看功能也将被传递给视图

 

3> What the URLconf searches against

The URLconf searches against the requested URL, as a normal Python string. This does not include GET or POST parameters, or the domain name.

For example, in a request to https://www.example.com/myapp/, the URLconf will look for myapp/.

In a request to https://www.example.com/myapp/?page=3, the URLconf will look for myapp/.

该URL配置不看请求方法。换言之,所有的请求的方法,GET,POST 等将被路由到为相同的URL,相同的功能。

 

4> 捕获的参数总是字符串

每个捕获的参数发送到视图作为普通的 Python 字符串,无论什么样的匹配正则表达式匹配。

例如,在该URL配置行:

url(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive),

...的 year参数传递给 views.year_archive()将是一个字符串,

不是一个整数,即使 [0-9]{4} 将只匹配整数字符串。

 

5> 指定view的默认设置

 一个方便的技巧是你的观点的论据指定默认参数。下面是一个例子的 RLconf 和看法:

# URLconf
from django.conf.urls import url

from . import views

urlpatterns = [
    url(r'^blog/$', views.page),
    url(r'^blog/page(?P<num>[0-9]+)/$', views.page),
]

# View (in blog/views.py)
def page(request, num="1"):
    # Output the appropriate page of blog entries, according to num.
    ...

在上述的例子中,两个 URL 模式指向同一个视图 views.page 但第一图案不捕获从 URL 任何东西。如果第一个模式匹配,该 page() 函数将使用它的默认参数 num"1"。如果第二图案相匹配时, page()将使用任何 num 值由正则表达式捕获。

 

 6> 包括其他的URLconf 

在任何时候,你urlpatterns可以“include”其他的URLconf模块。这实质上是“roots”的一套低于其他的网址。

例如,这里的URL配置为节选的Django网站 本身。它包括许多其他的URLconf的:

from django.conf.urls import include, url

urlpatterns = [
    # ... snip ...
    url(r'^community/', include('django_website.aggregator.urls')),
    url(r'^contact/', include('django_website.contact.urls')),
    # ... snip ...
]

请注意,在这个例子中,正则表达式没有一个$ (结束字符串匹配字符),但包括尾随斜线。每当 Django 的遇到 include()django.conf.urls.include()),它扒关闭任何匹配到该点的URL的一部分,并将剩余的字符串所包含的URL配置用于进一步的处理。

另一种可能性是通过使用的列表,以包括另外的网址格式  url()实例。例如,考虑这个 URL 配置:

from django.conf.urls import include, url

from apps.main import views as main_views
from credit import views as credit_views

extra_patterns = [
    url(r'^reports/$', credit_views.report),
    url(r'^reports/(?P<id>[0-9]+)/$', credit_views.report),
    url(r'^charge/$', credit_views.charge),
]

urlpatterns = [
    url(r'^$', main_views.homepage),
    url(r'^help/', include('apps.help.urls')),
    url(r'^credit/', include(extra_patterns)),
]

在这个例子中,/credit/reports/URL将被处理 credit_views.report()的Django图。

从其中单个图案前缀被重复使用的URLconf去除冗余。

我们可以通过声明的共同路径前缀只有一次,分组,例如这个URL配置:

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

urlpatterns = [
    url(r'^(?P<page_slug>[\w-]+)-(?P<page_id>\w+)/', include([
        url(r'^history/$', views.history),
        url(r'^edit/$', views.edit),
        url(r'^discuss/$', views.discuss),
        url(r'^permissions/$', views.permissions),
    ])),
]

 

7> 传递额外的选项来查看功能

URLconf 有一个挂钩,可以传递额外的参数给您的视图功能,作为一个 Python 字典。

django.conf.urls.url()功能可以采取这应该是额外的参数的字典传递给视图功能可选的第三个参数。

例如:

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

urlpatterns = [
    url(r'^blog/(?P<year>[0-9]{4})/$', views.year_archive, {'foo': 'bar'}),
]

在这个例子中,用于向请求/blog/2005/,Django会调用 。views.year_archive(request, year='2005',foo='bar')

# 处理冲突

这可能有它可以捕获一个名为关键字参数的URL模式,并且还传递参数,在其额外的参数字典相同的名称。发生这种情况时,在字典中的参数将被用来代替在URL捕获的参数。

传递额外的选项来 include()

同样,您可以通过额外的选项include()。当你通过额外的选项include()每个中所包含的URL配置线将通过额外的选项。

例如,这两个URL配置集在功能上是相同的:

# 设置一个:

# main.py
from django.conf.urls import include, url

urlpatterns = [
    url(r'^blog/', include('inner'), {'blogid': 3}),
]

# inner.py
from django.conf.urls import url
from mysite import views

urlpatterns = [
    url(r'^archive/$', views.archive),
    url(r'^about/$', views.about),
]

# 设置两个

# main.py
from django.conf.urls import include, url
from mysite import views

urlpatterns = [
    url(r'^blog/', include('inner')),
]

# inner.py
from django.conf.urls import url

urlpatterns = [
    url(r'^archive/$', views.archive, {'blogid': 3}),
    url(r'^about/$', views.about, {'blogid': 3}),
]

 

 

四、视图层

对逻辑负责处理用户的请求并返回响应。反回可以是HTML内容的网页,或重定向,或404错误,或一个XML文件,或一个形象......此代码可以住在任何你想去的地方,只要它在你的Python路径。

在一个文件中称将视图views.py,放在你的项目或应用程序目录。

 1、返回快捷功能

render()

render(requesttemplate_namecontext=Nonecontent_type=Nonestatus=Noneusing=None)[source]
结合给定的模板与一个给定的上下文,返回一个字典HttpResponse在渲染文本对象

所需的参数

 template_name 一个模板的使用或模板序列名称全称。如果序列是给定的,存在于第一个模板将被使用。

可选参数

context    一组字典的值添加到模板中。默认情况下,这是一个空的字典。

content_type    MIME类型用于生成文档。

status    为响应状态代码。默认值为200

using    这个名字一个模板引擎的使用将模板。

例子

from django.shortcuts import render

def my_view(request):
    # View code here...
    return render(request, 'myapp/index.html', {
        'foo': 'bar',
    }, content_type='application/xhtml+xml')

等价于

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

def my_view(request):
    # View code here...
    t = loader.get_template('myapp/index.html')
    c = {'foo': 'bar'}
    return HttpResponse(t.render(c, request), content_type='application/xhtml+xml')

 

 

render_to_response()

 render_to_response(template_namecontext=Nonecontent_type=Nonestatus=Noneusing=None)[source]

 这个和  render() 差不多,不推荐,在未来可能废弃掉

 

redirect()

 redirect(topermanent=False*args**kwargs)[source]

 默认情况下,为临时重定向;通过 permanent=True 设置永久重定向

def my_view(request):
    ...
    return redirect('/some/url/')


def my_view(request):
    ...
    object = MyModel.objects.get(...)
    return redirect(object, permanent=True)

 

 2、求和响应对象

Django 使用请求和响应对象在系统间传递状态。

当请求一个页面时,Django 创建一个 HttpRequest对象包含原数据的请求。然后 Django 加载适当的视图,通过 HttpRequest作为视图函数的第一个参数。每个视图负责返回一个HttpResponse目标。

HttpRequest对象

HttpRequest.scheme 
一个字符串表示请求的方案(HTTP或HTTPS)通常

HttpRequest.path

一个字符串的完整路径的请求

HttpRequest.method

请求的HTTP方法。这是保证要大写

if request.method == 'GET':
    do_something()
elif request.method == 'POST':
    do_something_else()

HttpRequest.GET

字典像包含所有给定的HTTP GET参数对象。

HttpRequest.POST

字典像包含所有给定的HTTP POST参数对象,提供请求包含表单数据。

HttpRequest.COOKIES

一个标准的Python字典,包含了所有的COOKIES,key和values都是字符串

HttpRequest.FILES

字典像对象包含所有上传的文件。
html 标签 <input type="file" name="" />

filename      # 上传的文件名
content_type  # 上传文件的类型
content       # 上传文件的内容

HttpRequest.META

一个标准的Python字典包含所有可用的HTTP头。可用标题取决于客户端和服务器,但这里是一些例子:

CONTENT_LENGTH       – 请求体的长度(一个字符串)。
CONTENT_TYPE         – 请求体的类型。
HTTP_ACCEPT          - 为响应–可以接受的内容类型。
HTTP_ACCEPT_ENCODING – 接受编码的响应
HTTP_ACCEPT_LANGUAGE – 接受语言的反应
HTTP_HOST            – 客户端发送的HTTP主机头。
HTTP_REFERER         – 参考页面
HTTP_USER_AGENT      – 客户端的用户代理字符串。
QUERY_STRING         – 查询字符串,作为一个单一的(分析的)字符串。
REMOTE_ADDR          – 客户端的IP地址
REMOTE_HOST          – 客户端的主机名
REMOTE_USER          – 用户通过Web服务器的身份验证。
REQUEST_METHOD       – 字符串,如"GET"或"POST"
SERVER_NAME          – 服务器的主机名
SERVER_PORT          – 服务器的端口(一个字符串)。

 

HttpResponse对象

 对于HttpRequest 对象来说,是由django自动创建的,但是,HttpResponse 对象就必须我们自己创建。每个 view 请求处理方法必须返回一个 HttpResponse 对象。

HttpResponse 类在 django.http.HttpResponse

 字符串使用:

典型的用法是通过页面的内容,为一个字符串

>>> from django.http import HttpResponse
>>> response = HttpResponse("Here's the text of the Web page.")
>>> response = HttpResponse("Text only, please.", content_type="text/plain")

# 如果你想添加内容的增量
>>> response = HttpResponse()
>>> response.write("<p>Here's the text of the Web page.</p>")
>>> response.write("<p>Here's another paragraph.</p>")

特性与方法:

HttpResponse.content
一个bytestring代表内容

 HttpResponse.charset

一个字符串的字符集表示的响应将编码

HttpResponse.status_code

HTTP状态代码为响应码

HttpResponse.streaming

这个属性永远为假,一般用于中间件

HttpResponse.closed

关闭

 

方法:

HttpResponse.__init__(content='', content_type=None, status=200, reason=None, charset=None)[source]

实例化类自动执行的方法

HttpResponse.__setitem__(header, value)

为给定值给定的标题名称。都是字符串

HttpResponse.__delitem__(header)

删除标题的名称。不区分大小写。

HttpResponse.__getitem__(header)

获取给定标题名称。不区分大小写。

HttpResponse.has_header(header)

检查是否具有给定名称的一个标题

HttpResponse.setdefault(header, value)

设置一个标题,除非它已经设置。

HttpResponse.set_cookie(key, value='', max_age=None, expires=None, path='/', domain=None, secure=None, httponly=False)

设置一个cookie。参数跟标准库的Cookie对象差不多

HttpResponse.set_signed_cookie(key, value, salt='', max_age=None, expires=None, path='/', domain=None, secure=None, httponly=True)

加密cookice,可以用 HttpRequest.get_signed_cookie() 获取,当然你也可以加盐

HttpResponse.delete_cookie(key, path='/', domain=None)

删除Cookie与给定键。

 

HttpResponse子类:

class HttpResponseRedirect[source]

构造函数的第一个参数是必需的–路径redirectto。这是一个完全合格的URL(例如“https://www.yahoo.com /搜索/),没有一个绝对的路径(例如域搜索/ /),甚至是相对路径(如“/”)。在最后的情况下,客户端浏览器将重建完整的URL本身的电流路径。看到HttpResponse其他optionalconstructor参数。请注意,这将返回一个HTTP状态代码302。

class HttpResponsePermanentRedirect[source]

像httpresponseredirect,但它返回一个永久重定向(HTTP状态代码301)而不是“发现”的重定向(状态代码302)

class HttpResponseNotModified[source]

构造函数不带任何参数和NO含量应该被添加到这一反应。使用指定一个页面没有被modifiedsince用户的最后一个请求(状态代码304)。

class HttpResponseBadRequest[source]

就像HttpResponse但使用400状态码

class HttpResponseNotFound[source]

就像HttpResponse但使用404状态码

class HttpResponseForbidden[source]

就像HttpResponse但使用403状态码

class HttpResponseNotAllowed[source]

像HttpResponse,但使用405状态码。第一argumentto构造函数要求准许清单的方法(如(get,后])

class HttpResponseGone[source]

就像HttpResponse但使用410状态码

class HttpResponseServerError[source]

就像HttpResponse但使用500状态码

 

 

五、模板层

  作为一个Web框架,Django 需要模板。模板包含所需的 HTML 输出静态部分以及动态内容插入。

1、模版的执行

def current_datetime(request):
    now = datetime.datetime.now()
    html = "<html><body>It is now %s.</body></html>" % now
    return HttpResponse(html)

from django import template
t = template.Template('My name is {{ name }}.')
c = template.Context({'name': 'Adrian'})
print t.render(c)

import datetime
from django import template
import DjangoDemo.settings
 
now = datetime.datetime.now()
fp = open(settings.BASE_DIR+'/templates/Home/Index.html')
t = template.Template(fp.read())
fp.close()
html = t.render(template.Context({'current_date': now}))
return HttpResponse(html

from django.template.loader import get_template
from django.template import Context
from django.http import HttpResponse
import datetime
 
def current_datetime(request):
    now = datetime.datetime.now()
    t = get_template('current_datetime.html')
    html = t.render(Context({'current_date': now}))
    return HttpResponse(html)

return render_to_response('Account/Login.html',data,context_instance=RequestContext(request))
示例

 

2、模版语言

 模板中也有自己的语言,该语言可以实现数据展示

    • {{ item }}
    • {% for item in item_list %}  <a>{{ item }}</a>  {% endfor %}
        forloop.counter
        forloop.first
        forloop.last 
    • {% if ordered_warranty %}  {% else %} {% endif %}
    • 母板:{% block title %}{% endblock %}
      子板:{% extends "base.html" %}
         {% block title %}{% endblock %}
    • 帮助方法:
      {{ item.event_start|date:"Y-m-d H:i:s"}}
      {{ bio|truncatewords:"30" }}
      {{ my_list|first|upper }}
      {{ name|lower }}

 

3、自定义simple_tag

a、在app中创建templatetags模块

b、创建任意 .py 文件,如:xx.py

#!/usr/bin/env python
#coding:utf-8
from django import template
from django.utils.safestring import mark_safe
from django.template.base import resolve_variable, Node, TemplateSyntaxError
  
register = template.Library()
  
@register.simple_tag
def my_simple_time(v1,v2,v3):
    return  v1 + v2 + v3
  
@register.simple_tag
def my_input(id,arg):
    result = "<input type='text' id='%s' class='%s' />" %(id,arg,)
    return mark_safe(result)

c、在使用自定义simple_tag的html文件中导入之前创建的 xx.py 文件名

{% load xx %}

d、使用simple_tag

{% my_simple_time 1 2 3%}
{% my_input 'id_username' 'hide'%}

e、在settings中配置当前app,不然django无法找到自定义的simple_tag

INSTALLED_APPS = (
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'app01',
)
View Code

 

 

六、Model 层

Django提供了一个抽象层(“Model”)的构建和管理Web应用程序的数据。

  • 每个模型是一个Python类,子类d jango.db.models.model
  • 模型中的每个属性代表一个数据库字段。

 

简单的例子

from django.db import models

class Person(models.Model):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)

 

参数与字段

1、models.AutoField  自增列 = int(11)
  如果没有的话,默认会生成一个名称为 id 的列,如果要显示的自定义一个自增列,必须将给列设置为主键 primary_key=True。
2、models.CharField  字符串字段
  必须 max_length 参数
3、models.BooleanField  布尔类型=tinyint(1)
  不能为空,Blank=True
4、models.ComaSeparatedIntegerField  用逗号分割的数字=varchar
  继承CharField,所以必须 max_lenght 参数
5、models.DateField  日期类型 date
  对于参数,auto_now = True 则每次更新都会更新这个时间;auto_now_add 则只是第一次创建添加,之后的更新不再改变。
6、models.DateTimeField  日期类型 datetime
  同DateField的参数
7、models.Decimal  十进制小数类型 = decimal
  必须指定整数位max_digits和小数位decimal_places
8、models.EmailField  字符串类型(正则表达式邮箱) =varchar
  对字符串进行正则表达式
9、models.FloatField  浮点类型 = double
10、models.IntegerField  整形
11、models.BigIntegerField  长整形
  integer_field_ranges = {
    'SmallIntegerField': (-32768, 32767),
    'IntegerField': (-2147483648, 2147483647),
    'BigIntegerField': (-9223372036854775808, 9223372036854775807),
    'PositiveSmallIntegerField': (0, 32767),
    'PositiveIntegerField': (0, 2147483647),
  }
12、models.IPAddressField  字符串类型(ip4正则表达式)
13、models.GenericIPAddressField  字符串类型(ip4和ip6是可选的)
  参数protocol可以是:both、ipv4、ipv6
  验证时,会根据设置报错
14、models.NullBooleanField  允许为空的布尔类型
15、models.PositiveIntegerFiel  正Integer
16、models.PositiveSmallIntegerField  正smallInteger
17、models.SlugField  减号、下划线、字母、数字
18、models.SmallIntegerField  数字
  数据库中的字段有:tinyint、smallint、int、bigint
19、models.TextField  字符串=longtext
20、models.TimeField  时间 HH:MM[:ss[.uuuuuu]]
21、models.URLField  字符串,地址正则表达式
22、models.BinaryField  二进制
23、models.ImageField   图片
24、models.FilePathField 文件
更多字段
1、null=True
  数据库中字段是否可以为空
2、blank=True
  django的 Admin 中添加数据时是否可允许空值
3、primary_key = False
  主键,对AutoField设置主键后,就会代替原来的自增 id 列
4、auto_now 和 auto_now_add
  auto_now   自动创建---无论添加或修改,都是当前操作的时间
  auto_now_add  自动创建---永远是创建时的时间
5、choices
GENDER_CHOICE = (
        (u'M', u'Male'),
        (u'F', u'Female'),
    )
gender = models.CharField(max_length=2,choices = GENDER_CHOICE)
6、max_length
7、default  默认值
8、verbose_name  Admin中字段的显示名称
9、name|db_column  数据库中的字段名称
10、unique=True  不允许重复
11、db_index = True  数据库索引
12、editable=True  在Admin里是否可编辑
13、error_messages=None  错误提示
14、auto_created=False  自动创建
15、help_text  在Admin中提示帮助信息
16、validators=[]
17、upload-to
更多参数

 

连表结构

  • 一对多:models.ForeignKey(其他表)
  • 多对多:models.ManyToManyField(其他表)
  • 一对一:models.OneToOneField(其他表)

 

操作表

1、基本操作

#
models.Tb1.objects.create(c1='xx', c2='oo')  # 增加一条数据,可以接受字典类型数据 **kwargs

obj = models.Tb1(c1='xx', c2='oo')
obj.save()

#
models.Tb1.objects.get(id=123)          # 获取单条数据,不存在则报错(不建议)
models.Tb1.objects.all()                # 获取全部
models.Tb1.objects.filter(name='seven') # 获取指定条件的数据

#
models.Tb1.objects.filter(name='nick').delete() # 删除指定条件的数据

# 改models.Tb1.objects.filter(name='nick').update(gender='0')  # 将指定条件的数据更新,均支持 **kwargs
obj = models.Tb1.objects.get(id=1)
obj.c1 = '111'
obj.save()                                                      # 修改单条数据

 

2、进阶操作(了不起的双下划线)

利用双下划线将字段和对应的操作连接起来

# 获取个数
models.Tb1.objects.filter(name='nick').count()

# 大于,小于
models.Tb1.objects.filter(id__gt=1)              # 获取id大于1的值
models.Tb1.objects.filter(id__lt=10)             # 获取id小于10的值
models.Tb1.objects.filter(id__lt=10, id__gt=1)   # 获取id大于1 且 小于10的值

# in
models.Tb1.objects.filter(id__in=[11, 22, 33])   # 获取id等于11、22、33的数据
models.Tb1.objects.exclude(id__in=[11, 22, 33])  # not in

# contains
models.Tb1.objects.filter(name__contains="ven")
models.Tb1.objects.filter(name__icontains="ven") # icontains大小写不敏感
models.Tb1.objects.exclude(name__icontains="ven")

# range
models.Tb1.objects.filter(id__range=[1, 2])      # 范围bettwen and

# 其他类似
# startswith,istartswith, endswith, iendswith,

# order by
models.Tb1.objects.filter(name='nick').order_by('id')    # asc
models.Tb1.objects.filter(name='nick').order_by('-id')   # desc

# limit 、offset
models.Tb1.objects.all()[10:20]

# group by
from django.db.models import Count, Min, Max, Sum

models.Tb1.objects.filter(c1=1).values('id').annotate(c=Count('num'))
# SELECT "app01_tb1"."id", COUNT("app01_tb1"."num") AS "c" FROM "app01_tb1" WHERE "app01_tb1"."c1" = 1 GROUP BY "app01_tb1"."id"

 

3、连表操作(了不起的双下划线)

利用双下划线和 _set 将表之间的操作连接起来

class UserProfile(models.Model):
    user_info = models.OneToOneField('UserInfo')
    username = models.CharField(max_length=64)
    password = models.CharField(max_length=64)

    def __unicode__(self):
        return self.username


class UserInfo(models.Model):
    user_type_choice = (
        (0, u'普通用户'),
        (1, u'高级用户'),
    )
    user_type = models.IntegerField(choices=user_type_choice)
    name = models.CharField(max_length=32)
    email = models.CharField(max_length=32)
    address = models.CharField(max_length=128)

    def __unicode__(self):
        return self.name


class UserGroup(models.Model):

    caption = models.CharField(max_length=64)

    user_info = models.ManyToManyField('UserInfo')

    def __unicode__(self):
        return self.caption


class Host(models.Model):
    hostname = models.CharField(max_length=64)
    ip = models.GenericIPAddressField()
    user_group = models.ForeignKey('UserGroup')

    def __unicode__(self):
        return self.hostname
表结构实例
user_info_obj = models.UserInfo.objects.filter(id=1).first()
print user_info_obj.user_type
print user_info_obj.get_user_type_display()
print user_info_obj.userprofile.password
 
user_info_obj = models.UserInfo.objects.filter(id=1).values('email', 'userprofile__username').first()
print user_info_obj.keys()
print user_info_obj.values()
一对一操作
    # 添加一对多
    dic = {
        "hostname": "名字1",
        "ip": "192.168.1.1",
        "user_group_id": 1,   # 加对象则为"user_group"
    }
    models.Host.objects.create(**dic)

    # 正向查一对多
    host_obj = models.Host.objects.all()
    print(type(host_obj),     # <class 'django.db.models.query.QuerySet'>
          host_obj)           # <QuerySet [<Host: 名字1>]>
    for item in host_obj:
        print(item.hostname)
        print(item.user_group.caption)
        print(item.user_group.user_info.values())
        # <QuerySet [{'name': 'nick', 'user_type': 1, 'id': 1, 'email': '630571017@qq.com', 'address': '128号'}]>
    
    usergroup_obj = models.Host.objects.filter(user_group__caption='标题1')
    print(usergroup_obj)


    # 反向查一对多
    usergroup_obj = models.UserGroup.objects.get(id=1)
    print(usergroup_obj.caption)
    ret = usergroup_obj.host_set.all()  # 所有关于id=1的host
    print(ret)
    
    obj = models.UserGroup.objects.filter(host__ip='192.168.1.1').\
        values('host__id', 'host__hostname')
    print(obj)      # <QuerySet [{'host__id': 1, 'host__hostname': '名字1'}]>
一对多
user_info_obj = models.UserInfo.objects.get(name='nick')
user_info_objs = models.UserInfo.objects.all()
 
group_obj = models.UserGroup.objects.get(caption='CTO')
group_objs = models.UserGroup.objects.all()
 
# 添加数据
#group_obj.user_info.add(user_info_obj)
#group_obj.user_info.add(*user_info_objs)
 
# 删除数据
#group_obj.user_info.remove(user_info_obj)
#group_obj.user_info.remove(*user_info_objs)
 
# 添加数据
#user_info_obj.usergroup_set.add(group_obj)
#user_info_obj.usergroup_set.add(*group_objs)
 
# 删除数据
#user_info_obj.usergroup_set.remove(group_obj)
#user_info_obj.usergroup_set.remove(*group_objs)
 
# 获取数据
#print group_obj.user_info.all()
#print group_obj.user_info.all().filter(id=1)
 
# 获取数据
#print user_info_obj.usergroup_set.all()
#print user_info_obj.usergroup_set.all().filter(caption='CTO')
#print user_info_obj.usergroup_set.all().filter(caption='DBA')

    # 添加多对多
    # userinfo_id_1 = models.UserInfo.objects.filter(id=1)
    # usergroup_id_1 = models.UserGroup.objects.filter(id=1).first()
    # usergroup_id_1.user_info.add(*userinfo_id_1)
多对多操作
    # F 使用查询条件的值(用原来的值操作)
    #
    # from django.db.models import F
    # models.Tb1.objects.update(num=F('num')+1)


    # Q 构建搜索条件
    from django.db.models import Q
    # con = Q()
    #
    # q1 = Q()
    # q1.connector = 'OR'
    # q1.children.append(('id', 1))
    # q1.children.append(('id', 10))
    # q1.children.append(('id', 9))
    #
    # q2 = Q()
    # q2.connector = 'OR'
    # q2.children.append(('c1', 1))
    # q2.children.append(('c1', 10))
    # q2.children.append(('c1', 9))
    #
    # con.add(q1, 'AND')
    # con.add(q2, 'AND')
    #
    # models.Tb1.objects.filter(con)
F & Q
    from django.db import connection
    cursor = connection.cursor()
    cursor.execute("""SELECT * from app1_userinfo where name = %s""", ['nick'])
    row = cursor.fetchone()
    print(row)
Django 执行原生SQL

注意:xx_set中的【_set】是多对多中的固定搭配

 

扩展:

a、自定义上传

def upload_file(request):
    if request.method == "POST":
        obj = request.FILES.get('fafafa')
        f = open(obj.name, 'wb')
        for chunk in obj.chunks():
            f.write(chunk)
        f.close()
    return render(request, 'file.html')
View Code

b、Form上传文件实例

       <form method="post" action="/view1/" enctype="multipart/form-data">
           <input type="file" name="ExcelFile" id="id_ExcelFile" />
           <input type="submit" value="提交" />
       </form>
HTML
class FileForm(forms.Form):
    ExcelFile = forms.FileField()
Form
from django.db import models

class UploadFile(models.Model):
    userid = models.CharField(max_length = 30)
    file = models.FileField(upload_to = './upload/')
    date = models.DateTimeField(auto_now_add=True)
models
def UploadFile(request):
    uf = AssetForm.FileForm(request.POST,request.FILES)
    if uf.is_valid():
            upload = models.UploadFile()
            upload.userid = 1
            upload.file = uf.cleaned_data['ExcelFile']
            upload.save()
            
            print upload.file
View

c、ajax上传文件实例

   <div>
       {{ up.ExcelFile }}
       <input type="button" id="submitj" value="提交" />
   </div>


<script src="/static/js/jquery-2.1.4.min.js"></script>
<script>
    $('#submitj').bind("click",function () {
        var file = $('#id_ExcelFile')[0].files[0];
        var form = new FormData();
        form.append('ExcelFile', file);
         $.ajax({
                type:'POST',
                url: '/view1/',
                data: form,
                processData: false,  // tell jQuery not to process the data
                contentType: false,  // tell jQuery not to set contentType
                success: function(arg){
                    console.log(arg);
                }
            })
    })
</script>
HTML
class FileForm(forms.Form):
    ExcelFile = forms.FileField()
Form
from django.db import models

class UploadFile(models.Model):
    userid = models.CharField(max_length = 30)
    file = models.FileField(upload_to = './upload/')
    date = models.DateTimeField(auto_now_add=True)
models
from study1 import forms

def UploadFile(request):
    uf = AssetForm.FileForm(request.POST,request.FILES)
    if uf.is_valid():
            upload = models.UploadFile()
            upload.userid = 1
            upload.file = uf.cleaned_data['ExcelFile']
            upload.save()
            
            print upload.file

return render(request, 'file.html', locals())
View

 

 

七、Form

django中的Form一般有两种功能:

  • 输入html
  • 验证用户输入
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import re
from django import forms
from django.core.exceptions import ValidationError


def mobile_validate(value):
    mobile_re = re.compile(r'^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$')
    if not mobile_re.match(value):
        raise ValidationError('手机号码格式错误')


class PublishForm(forms.Form):

    user_type_choice = (
        (0, u'普通用户'),
        (1, u'高级用户'),
    )

    user_type = forms.IntegerField(widget=forms.widgets.Select(choices=user_type_choice,
                                                                  attrs={'class': "form-control"}))

    title = forms.CharField(max_length=20,
                            min_length=5,
                            error_messages={'required': u'标题不能为空',
                                            'min_length': u'标题最少为5个字符',
                                            'max_length': u'标题最多为20个字符'},
                            widget=forms.TextInput(attrs={'class': "form-control",
                                                          'placeholder': u'标题5-20个字符'}))

    memo = forms.CharField(required=False,
                           max_length=256,
                           widget=forms.widgets.Textarea(attrs={'class': "form-control no-radius", 'placeholder': u'详细描述', 'rows': 3}))

    phone = forms.CharField(validators=[mobile_validate, ],
                            error_messages={'required': u'手机不能为空'},
                            widget=forms.TextInput(attrs={'class': "form-control",
                                                          'placeholder': u'手机号码'}))

    email = forms.EmailField(required=False,
                            error_messages={'required': u'邮箱不能为空','invalid': u'邮箱格式错误'},
                            widget=forms.TextInput(attrs={'class': "form-control", 'placeholder': u'邮箱'}))
Form
def publish(request):
    ret = {'status': False, 'data': '', 'error': '', 'summary': ''}
    if request.method == 'POST':
        request_form = PublishForm(request.POST)
        if request_form.is_valid():
            request_dict = request_form.clean()
            print request_dict
            ret['status'] = True
        else:
            error_msg = request_form.errors.as_json()
            ret['error'] = json.loads(error_msg)
    return HttpResponse(json.dumps(ret))
View Code

扩展:ModelForm

在使用Model和Form时,都需要对字段进行定义并指定类型,通过ModelForm则可以省去From中字段的定义

class AdminModelForm(forms.ModelForm):
      
    class Meta:
        model = models.Admin
        #fields = '__all__'
        fields = ('username', 'email')
          
        widgets = {
            'email' : forms.PasswordInput(attrs={'class':"alex"}),
        }
View Code

 

 

八、认证系统auth 

auth模块是Django提供的标准权限管理系统,可以提供用户身份认证, 用户组管理,并且可以和admin模块配合使用.

在INSTALLED_APPS中添加'django.contrib.auth'使用该APP, auth模块默认启用.

model

from django.contrib.auth.models import User

# 数据库中该表名为auth_user.
CREATE TABLE "auth_user" (
    "id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, 
    "password" varchar(128) NOT NULL, "last_login" datetime NULL, 
    "is_superuser" bool NOT NULL, 
    "first_name" varchar(30) NOT NULL, 
    "last_name" varchar(30) NOT NULL,
    "email" varchar(254) NOT NULL, 
    "is_staff" bool NOT NULL, 
    "is_active" bool NOT NULL,
    "date_joined" datetime NOT NULL,
    "username" varchar(30) NOT NULL UNIQUE
)

新建用户

user = User.objects.create_user(username, email, password)
user.save()

# 不存储用户密码明文而是存储一个Hash值

认证用户

from django.contrib.auth import authenticate

user = authenticate(username=username, password=password)

# 认证用户的密码是否有效, 若有效则返回代表该用户的user对象, 若无效则返回None.
# 该方法不检查is_active标志位.

修改密码

user.set_password(new_password)

# 以下实例为先认证通过后才可以修改密码
user = auth.authenticate(username=username, password=old_password)
if user is not None:
    user.set_password(new_password)
    user.save()

登录

from django.contrib.auth import login

# login向session中添加SESSION_KEY, 便于对用户进行跟踪:
'login(request, user)'

# login不进行认证,也不检查is_active标志位
# 实例
user = authenticate(username=username, password=password)
if user is not None:
    if user.is_active:
        login(request, user)

退出登录

# logout会移除request中的user信息, 并刷新session

from django.contrib.auth import logout

def logout_view(request):
    logout(request)

只允许登录的用户访问

@login_required修饰器修饰的view函数会先通过session key检查是否登录, 已登录用户可以正常的执行操作, 未登录用户将被重定向到login_url指定的位置.

若未指定login_url参数, 则重定向到settings.LOGIN_URL

from django.contrib.auth.decorators import login_required

@login_required(login_url='/accounts/login/')
def userinfo(request):
    ...

# settings 配置
LOGIN_URL = '/index/'
# views
@login_required
def userinfo(request):
    ...

 

九、跨站请求伪造

简介

django为用户实现防止跨站请求伪造的功能,通过中间件 django.middleware.csrf.CsrfViewMiddleware 来完成。而对于django中设置防跨站请求伪造功能有分为全局和局部。

全局:

  中间件 django.middleware.csrf.CsrfViewMiddleware

局部:

  • @csrf_protect,为当前函数强制设置防跨站请求伪造功能,即便settings中没有设置全局中间件。
  • @csrf_exempt,取消当前函数防跨站请求伪造功能,即便settings中设置了全局中间件。

注:from django.views.decorators.csrf import csrf_exempt,csrf_protect

 

应用

1、普通表单

veiw中设置返回值:
  return render_to_response('Account/Login.html',data,context_instance=RequestContext(request))  
     或者
     return render(request, 'xxx.html', data)
  
html中设置Token:
  {% csrf_token %}

2、Ajax

对于传统的form,可以通过表单的方式将token再次发送到服务端,而对于ajax的话,使用如下方式。

# view.py

from django.template.context import RequestContext
# Create your views here.
  
  
def test(request):
  
    if request.method == 'POST':
        print request.POST
        return HttpResponse('ok')
    return  render_to_response('app01/test.html',context_instance=RequestContext(request))
view.py
# text.html

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    {% csrf_token %}
  
    <input type="button" onclick="Do();"  value="Do it"/>
  
    <script src="/static/plugin/jquery/jquery-1.8.0.js"></script>
    <script src="/static/plugin/jquery/jquery.cookie.js"></script>
    <script type="text/javascript">
        var csrftoken = $.cookie('csrftoken');
  
        function csrfSafeMethod(method) {
            // these HTTP methods do not require CSRF protection
            return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
        }
        $.ajaxSetup({
            beforeSend: function(xhr, settings) {
                if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
                    xhr.setRequestHeader("X-CSRFToken", csrftoken);
                }
            }
        });
        function Do(){
  
            $.ajax({
                url:"/app01/test/",
                data:{id:1},
                type:'POST',
                success:function(data){
                    console.log(data);
                }
            });
  
        }
    </script>
</body>
</html>
text.html

更多:https://docs.djangoproject.com/en/dev/ref/csrf/#ajax

 

 

十、分页

Django内置分页 

Paginator

 

自定义分页

#!/usr/bin/env python
# _*_coding:utf-8_*_
from django.utils.safestring import mark_safe
 
class PageInfo(object):
    def __init__(self,current,totalItem,peritems=5):
        self.__current=current
        self.__peritems=peritems
        self.__totalItem=totalItem
    def From(self):
        return (self.__current-1)*self.__peritems
    def To(self):
        return self.__current*self.__peritems
    def TotalPage(self):  #总页数
        result=divmod(self.__totalItem,self.__peritems)
        if result[1]==0:
            return result[0]
        else:
            return result[0]+1
 
def Custompager(baseurl,currentPage,totalpage):  #基础页,当前页,总页数
    perPager=11
    #总页数<11
    #0 -- totalpage
    #总页数>11
        #当前页大于5 currentPage-5 -- currentPage+5
            #currentPage+5是否超过总页数,超过总页数,end就是总页数
        #当前页小于5 0 -- 11
    begin=0
    end=0
    if totalpage <= 11:
        begin=0
        end=totalpage
    else:
        if currentPage>5:
            begin=currentPage-5
            end=currentPage+5
            if end > totalpage:
                end=totalpage
        else:
            begin=0
            end=11
    pager_list=[]
    if currentPage<=1:
        first="<a href=''>首页</a>"
    else:
        first="<a href='%s%d'>首页</a>" % (baseurl,1)
    pager_list.append(first)
 
    if currentPage<=1:
        prev="<a href=''>上一页</a>"
    else:
        prev="<a href='%s%d'>上一页</a>" % (baseurl,currentPage-1)
    pager_list.append(prev)
 
    for i in range(begin+1,end+1):
        if i == currentPage:
            temp="<a href='%s%d' class='selected'>%d</a>" % (baseurl,i,i)
        else:
            temp="<a href='%s%d'>%d</a>" % (baseurl,i,i)
        pager_list.append(temp)
    if currentPage>=totalpage:
        next="<a href='#'>下一页</a>"
    else:
        next="<a href='%s%d'>下一页</a>" % (baseurl,currentPage+1)
    pager_list.append(next)
    if currentPage>=totalpage:
        last="<a href=''>末页</a>"
    else:
        last="<a href='%s%d'>末页</a>" % (baseurl,totalpage)
    pager_list.append(last)
    result=''.join(pager_list)
    return mark_safe(result)   #把字符串转成html语言
分页实例

 

 

十一、Cookice

获取Cookie:

request.COOKIES['key']
request.get_signed_cookie(key, default=RAISE_ERROR, salt='', max_age=None)
    参数:
        default: 默认值
           salt: 加密盐
        max_age: 后台控制过期时间

 

设置Cookie:

rep = HttpResponse(...) 或 rep = render(request, ...)
 
rep.set_cookie(key,value,...)
rep.set_signed_cookie(key,value,salt='加密盐',...)
    参数:
        key,              键
        value='',         值
        max_age=None,     超时时间
        expires=None,     超时时间(IE requires expires, so set it if hasn't been already.)
        path='/',         Cookie生效的路径,/ 表示根路径,特殊的:跟路径的cookie可以被任何url的页面访问
        domain=None,      Cookie生效的域名
        secure=False,     https传输
        httponly=False    只能http协议传输,无法被JavaScript获取(不是绝对,底层抓包可以获取到也可以被覆盖)

由于cookie保存在客户端的电脑上,所以,JavaScript和jquery也可以操作cookie。

<script src='/static/js/jquery.cookie.js'></script>
$.cookie("list_pager_num", 30,{ path: '/' });

 

 

十二、Session

Django中默认支持Session,其内部提供了5种类型的Session供开发者使用:

  • 数据库(默认)
  • 缓存
  • 文件
  • 缓存+数据库
  • 加密cookie

1、数据库Session

Django默认支持Session,并且默认是将Session数据存储在数据库中,即:django_session 表中。
 
a. 配置 settings.py
 
    SESSION_ENGINE = 'django.contrib.sessions.backends.db'   # 引擎(默认)
     
    SESSION_COOKIE_NAME = "sessionid"                       # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串(默认)
    SESSION_COOKIE_PATH = "/"                               # Session的cookie保存的路径(默认)
    SESSION_COOKIE_DOMAIN = None                             # Session的cookie保存的域名(默认)
    SESSION_COOKIE_SECURE = False                            # 是否Https传输cookie(默认)
    SESSION_COOKIE_HTTPONLY = True                           # 是否Session的cookie只支持http传输(默认)
    SESSION_COOKIE_AGE = 1209600                             # Session的cookie失效日期(2周)(默认)
    SESSION_EXPIRE_AT_BROWSER_CLOSE = False                  # 是否关闭浏览器使得Session过期(默认)
    SESSION_SAVE_EVERY_REQUEST = False                       # 是否每次请求都保存Session,默认修改之后才保存(默认)
 
 
 
b. 使用
 
    def index(request):
        # 获取、设置、删除Session中数据
        request.session['k1']
        request.session.get('k1',None)
        request.session['k1'] = 123
        request.session.setdefault('k1',123) # 存在则不设置
        del request.session['k1']
 
        # 所有 键、值、键值对
        request.session.keys()
        request.session.values()
        request.session.items()
        request.session.iterkeys()
        request.session.itervalues()
        request.session.iteritems()
 
 
        # 用户session的随机字符串
        request.session.session_key
 
        # 将所有Session失效日期小于当前日期的数据删除
        request.session.clear_expired()
 
        # 检查 用户session的随机字符串 在数据库中是否
        request.session.exists("session_key")
 
        # 删除当前用户的所有Session数据
        request.session.delete("session_key")
 
        ...
View Code

2、缓存Session

a. 配置 settings.py
 
    SESSION_ENGINE = 'django.contrib.sessions.backends.cache'  # 引擎
    SESSION_CACHE_ALIAS = 'default'                            # 使用的缓存别名(默认内存缓存,也可以是memcache),此处别名依赖缓存的设置
 
 
    SESSION_COOKIE_NAME = "sessionid"                        # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串
    SESSION_COOKIE_PATH = "/"                                # Session的cookie保存的路径
    SESSION_COOKIE_DOMAIN = None                              # Session的cookie保存的域名
    SESSION_COOKIE_SECURE = False                             # 是否Https传输cookie
    SESSION_COOKIE_HTTPONLY = True                            # 是否Session的cookie只支持http传输
    SESSION_COOKIE_AGE = 1209600                              # Session的cookie失效日期(2周)
    SESSION_EXPIRE_AT_BROWSER_CLOSE = False                   # 是否关闭浏览器使得Session过期
    SESSION_SAVE_EVERY_REQUEST = False                        # 是否每次请求都保存Session,默认修改之后才保存
 
 
 
b. 使用
 
    同上
View Code

3、文件Session

a. 配置 settings.py
 
    SESSION_ENGINE = 'django.contrib.sessions.backends.file'    # 引擎
    SESSION_FILE_PATH = None                                    # 缓存文件路径,如果为None,则使用tempfile模块获取一个临时地址tempfile.gettempdir()                                                            # 如:/var/folders/d3/j9tj0gz93dg06bmwxmhh6_xm0000gn/T
 
 
    SESSION_COOKIE_NAME = "sessionid"                          # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串
    SESSION_COOKIE_PATH = "/"                                  # Session的cookie保存的路径
    SESSION_COOKIE_DOMAIN = None                                # Session的cookie保存的域名
    SESSION_COOKIE_SECURE = False                               # 是否Https传输cookie
    SESSION_COOKIE_HTTPONLY = True                              # 是否Session的cookie只支持http传输
    SESSION_COOKIE_AGE = 1209600                                # Session的cookie失效日期(2周)
    SESSION_EXPIRE_AT_BROWSER_CLOSE = False                     # 是否关闭浏览器使得Session过期
    SESSION_SAVE_EVERY_REQUEST = False                          # 是否每次请求都保存Session,默认修改之后才保存
 
b. 使用
 
    同上
View Code

4、缓存+数据库Session

数据库用于做持久化,缓存用于提高效率
 
a. 配置 settings.py
 
    SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db'        # 引擎
 
b. 使用
 
    同上
View Code

5、加密cookie Session

a. 配置 settings.py
     
    SESSION_ENGINE = 'django.contrib.sessions.backends.signed_cookies'   # 引擎
 
b. 使用
 
    同上
View Code

更多参考:猛击这里 和 猛击这里

扩展:Session用户验证

def login(func):
    def wrap(request, *args, **kwargs):
        # 如果未登陆,跳转到指定页面
        if request.path == '/test/':
            return redirect('http://www.baidu.com')
        return func(request, *args, **kwargs)
    return wrap

 

6、Redis 实现 

环境安装

pip install django-redis
pip install django-redis-cache
pip install django-redis-sessions
1> 配置django-redis-sessions

在settings.py中配置

SESSION_ENGINE = 'django.contrib.sessions.backends.signed_cookies'
# SESSION_ENGINE = 'redis_sessions.session'
SESSION_REDIS_HOST = 'localhost'
SESSION_REDIS_PORT = 6379
SESSION_REDIS_DB = 0
SESSION_REDIS_PASSWORD = 'password'
SESSION_REDIS_PREFIX = 'session'
SESSION_COOKIE_NAME = 'session_name'
SESSION_COOKIE_AGE = '60*20'  # 超时时间


# If you prefer domain socket connection, you can just add this line instead of SESSION_REDIS_HOST and SESSION_REDIS_PORT.
SESSION_REDIS_UNIX_DOMAIN_SOCKET_PATH = '/var/run/redis/redis.sock'

配置完成后可测试如下:

$ pip install django nose redis
# Make sure you have redis running on localhost:6379
(poem)[beginman@beginman poem]$ nosetests

----------------------------------------------------------------------
Ran 0 tests in 0.001s

OK
2> 配置django-redis-sessions

在settings.py中配置

CACHES = {
        "default": {
            "BACKEND": "django_redis.cache.RedisCache",
            "LOCATION": [
                "redis://:password@IP0.0.0.0:6379",
            ],
            "OPTIONS": {
                # "CLIENT_CLASS": "django_redis.client.DefaultClient",
                "CONNECTION_POOL_KWARGS": {"max_connections": 100},     # 连接池
            }
        }
    }
CACHES = {
    'default': {
        'BACKEND': 'redis_cache.RedisCache',
        'LOCATION': '<host>:<port>',
        'OPTIONS': {
            'DB': 1,
            'PASSWORD': '',
            'PARSER_CLASS': 'redis.connection.HiredisParser',
            'CONNECTION_POOL_CLASS': 'redis.BlockingConnectionPool',
            'CONNECTION_POOL_CLASS_KWARGS': {
                'max_connections': 50,
                'timeout': 20,
            }
        },
    },
}
View Code
3>django实现redis的存取
# Start by importing your default cache:
from django.core.cache import cache

# Store data under a-unique-key:
cache.set('a-unique-key', 'this is a string which will be cached')

# Later on you can retrieve it in another function:
cache.get('a-unique-key') # Will return None if key is not found in cache

# You can specify a default value:
cache.get('another-unique-key', 'default value')

# You can store multiple values at once:
cache.set_many({'a': 1, 'b': 2, 'c': 3})

# And fetch multiple values:
cache.get_many(['a', 'b', 'c']) # returns {'a': 1, 'b': 2, 'c': 3}

# You can store complex types in the cache:
cache.set('a-unique-key', {
    'string'    : 'this is a string',
    'int'       : 42,
    'list'      : [1, 2, 3],
    'tuple'     : (1, 2, 3),
    'dict'      : {'A': 1, 'B' : 2},
})

更多:http://niwinz.github.io/django-redis/latest/#_installation 

 

十三、缓存

由于Django是动态网站,所有每次请求均会去数据进行相应的操作,当程序访问量大时,耗时必然会更加明显,最简单解决方式是使用:缓存,缓存将一个某个views的返回值保存至内存或者memcache中,5分钟内再有人来访问时,则不再去执行view中的操作,而是直接从内存或者Redis中之前缓存的内容拿到,并返回。

Django中提供了6种缓存方式:

  • 开发调试
  • 内存
  • 文件
  • 数据库
  • Memcache缓存(python-memcached模块)
  • Memcache缓存(pylibmc模块)

1、配置

a、开发调试

# 此为开始调试用,实际内部不做任何操作
    # 配置:
        CACHES = {
            'default': {
                'BACKEND': 'django.core.cache.backends.dummy.DummyCache',     # 引擎
                'TIMEOUT': 300,                                               # 缓存超时时间(默认300,None表示永不过期,0表示立即过期)
                'OPTIONS':{
                    'MAX_ENTRIES': 300,                                       # 最大缓存个数(默认300)
                    'CULL_FREQUENCY': 3,                                      # 缓存到达最大个数之后,剔除缓存个数的比例,即:1/CULL_FREQUENCY(默认3)
                },
                'KEY_PREFIX': '',                                             # 缓存key的前缀(默认空)
                'VERSION': 1,                                                 # 缓存key的版本(默认1)
                'KEY_FUNCTION' 函数名                                          # 生成key的函数(默认函数会生成为:【前缀:版本:key】)
            }
        }


    # 自定义key
    def default_key_func(key, key_prefix, version):
        """
        Default function to generate keys.

        Constructs the key used by all other methods. By default it prepends
        the `key_prefix'. KEY_FUNCTION can be used to specify an alternate
        function with custom key making behavior.
        """
        return '%s:%s:%s' % (key_prefix, version, key)

    def get_key_func(key_func):
        """
        Function to decide which key function to use.

        Defaults to ``default_key_func``.
        """
        if key_func is not None:
            if callable(key_func):
                return key_func
            else:
                return import_string(key_func)
        return default_key_func
View Code

b、内存

# 此缓存将内容保存至内存的变量中
    # 配置:
        CACHES = {
            'default': {
                'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
                'LOCATION': 'unique-snowflake',
            }
        }

    # 注:其他配置同开发调试版本
View Code

c、文件

# 此缓存将内容保存至文件
    # 配置:

        CACHES = {
            'default': {
                'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
                'LOCATION': '/var/tmp/django_cache',
            }
        }
    # 注:其他配置同开发调试版本
View Code

d、数据库

# 此缓存将内容保存至数据库

    # 配置:
        CACHES = {
            'default': {
                'BACKEND': 'django.core.cache.backends.db.DatabaseCache',
                'LOCATION': 'my_cache_table', # 数据库表
            }
        }

    # 注:执行创建表命令 python manage.py createcachetable
View Code

e、Memcache缓存(python-memcached模块)

# 此缓存使用python-memcached模块连接memcache

    CACHES = {
        'default': {
            'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
            'LOCATION': '127.0.0.1:11211',
        }
    }

    CACHES = {
        'default': {
            'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
            'LOCATION': 'unix:/tmp/memcached.sock',
        }
    }   

    CACHES = {
        'default': {
            'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
            'LOCATION': [
                '172.19.26.240:11211',
                '172.19.26.242:11211',
            ]
        }
    }
View Code

f、Memcache缓存(pylibmc模块)

# 此缓存使用pylibmc模块连接memcache
    
    CACHES = {
        'default': {
            'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache',
            'LOCATION': '127.0.0.1:11211',
        }
    }

    CACHES = {
        'default': {
            'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache',
            'LOCATION': '/tmp/memcached.sock',
        }
    }   

    CACHES = {
        'default': {
            'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache',
            'LOCATION': [
                '172.19.26.240:11211',
                '172.19.26.242:11211',
            ]
        }
    }
View Code

 

2、应用

a、 全站使用

使用中间件,经过一系列的认证等操作,如果内容在缓存中存在,则使用FetchFromCacheMiddleware获取内容并返回给用户,当返回给用户之前,判断缓存中是否已经存在,如果不存在则UpdateCacheMiddleware会将缓存保存至缓存,从而实现全站缓存

    MIDDLEWARE = [
        'django.middleware.cache.UpdateCacheMiddleware',
        # 其他中间件...
        'django.middleware.cache.FetchFromCacheMiddleware',
    ]

    CACHE_MIDDLEWARE_ALIAS = ""
    CACHE_MIDDLEWARE_SECONDS = ""
    CACHE_MIDDLEWARE_KEY_PREFIX = ""
View Code

b、单独视图缓存

方式一:
        from django.views.decorators.cache import cache_page

        @cache_page(60 * 15)
        def my_view(request):
            ...

    方式二:
        from django.views.decorators.cache import cache_page

        urlpatterns = [
            url(r'^foo/([0-9]{1,2})/$', cache_page(60 * 15)(my_view)),
        ]
View Code

c、局部视图使用

a. 引入TemplateTag

        {% load cache %}

    b. 使用缓存

        {% cache 5000 缓存key %}
            缓存内容
        {% endcache %}
View Code

更多:猛击这里

 

 

十四、序列化

关于Django中的序列化主要应用在将数据库中检索的数据返回给客户端用户,特别的Ajax请求一般返回的为Json格式。

1、serializers

from django.core import serializers
 
ret = models.BookType.objects.all()
 
data = serializers.serialize("json", ret)

2、json.dumps

import json
 
#ret = models.BookType.objects.all().values('caption')
ret = models.BookType.objects.all().values_list('caption')
 
ret=list(ret)
 
result = json.dumps(ret)

由于json.dumps时无法处理datetime日期,所以可以通过自定义处理器来做扩展,如:

import json 
from datetime import date 
from datetime import datetime 
   
class JsonCustomEncoder(json.JSONEncoder): 
    
    def default(self, field): 
     
        if isinstance(field, datetime): 
            return o.strftime('%Y-%m-%d %H:%M:%S') 
        elif isinstance(field, date): 
            return o.strftime('%Y-%m-%d') 
        else: 
            return json.JSONEncoder.default(self, field) 
   
   
# ds = json.dumps(d, cls=JsonCustomEncoder) 
View Code

 

 

十五、中间件

django 中的中间件(middleware),在django中,中间件其实就是一个类,在请求到来和结束后,django会根据自己的规则在合适的时机执行中间件中相应的方法。

在django项目的settings模块中,有一个 MIDDLEWARE_CLASSES 变量,其中每一个元素就是一个中间件,如下图。

与mange.py在同一目录下的文件夹 wupeiqi/middleware下的auth.py文件中的Authentication类

中间件中可以定义四个方法,分别是:

  • process_request(self,request)
  • process_view(self, request, callback, callback_args, callback_kwargs)
  • process_template_response(self,request,response)
  • process_exception(self, request, exception)
  • process_response(self, request, response)

以上方法的返回值可以是None和HttpResonse对象,如果是None,则继续按照django定义的规则向下执行,如果是HttpResonse对象,则直接将该对象返回给用户。

自定义中间件

1、创建中间件类

class RequestExeute(object):
      
    def process_request(self,request):
        pass
    def process_view(self, request, callback, callback_args, callback_kwargs):
        i =1
        pass
    def process_exception(self, request, exception):
        pass
      
    def process_response(self, request, response):
        return response

2、注册中间件

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',
    'wupeiqi.middleware.auth.RequestExeute',
)

 

 

十六、信号

Django中提供了“信号调度”,用于在框架执行操作时解耦。通俗来讲,就是一些动作发生的时候,信号允许特定的发送者去提醒一些接受者。

1、Django内置信号

Model signals
    pre_init                    # django的modal执行其构造方法前,自动触发
    post_init                   # django的modal执行其构造方法后,自动触发
    pre_save                    # django的modal对象保存前,自动触发
    post_save                   # django的modal对象保存后,自动触发
    pre_delete                  # django的modal对象删除前,自动触发
    post_delete                 # django的modal对象删除后,自动触发
    m2m_changed                 # django的modal中使用m2m字段操作第三张表(add,remove,clear)前后,自动触发
    class_prepared              # 程序启动时,检测已注册的app中modal类,对于每一个类,自动触发
Management signals
    pre_migrate                 # 执行migrate命令前,自动触发
    post_migrate                # 执行migrate命令后,自动触发
Request/response signals
    request_started             # 请求到来前,自动触发
    request_finished            # 请求结束后,自动触发
    got_request_exception       # 请求异常后,自动触发
Test signals
    setting_changed             # 使用test测试修改配置文件时,自动触发
    template_rendered           # 使用test测试渲染模板时,自动触发
Database Wrappers
    connection_created          # 创建数据库连接时,自动触发

对于Django内置的信号,仅需注册指定信号,当程序执行相应操作时,自动触发注册函数:

from django.core.signals import request_finished
    from django.core.signals import request_started
    from django.core.signals import got_request_exception

    from django.db.models.signals import class_prepared
    from django.db.models.signals import pre_init, post_init
    from django.db.models.signals import pre_save, post_save
    from django.db.models.signals import pre_delete, post_delete
    from django.db.models.signals import m2m_changed
    from django.db.models.signals import pre_migrate, post_migrate

    from django.test.signals import setting_changed
    from django.test.signals import template_rendered

    from django.db.backends.signals import connection_created


    def callback(sender, **kwargs):
        print("xxoo_callback")
        print(sender,kwargs)

    xxoo.connect(callback)
    # xxoo指上述导入的内容
View Code
from django.core.signals import request_finished
from django.dispatch import receiver

@receiver(request_finished)
def my_callback(sender, **kwargs):
    print("Request finished!")
View Code

2、自定义信号

a. 定义信号

import django.dispatch
pizza_done = django.dispatch.Signal(providing_args=["toppings", "size"])

b. 注册信号

def callback(sender, **kwargs):
    print("callback")
    print(sender,kwargs)
 
pizza_done.connect(callback)

c. 触发信号

from 路径 import pizza_done
 
pizza_done.send(sender='seven',toppings=123, size=456)

由于内置信号的触发者已经集成到Django中,所以其会自动调用,而对于自定义信号则需要开发者在任意位置触发。

更多:猛击这里

 

 

十七、admin

django amdin是django提供的一个后台管理页面,改管理页面提供完善的html和css,使得你在通过Model创建完数据库表之后,就可以对数据进行增删改查,而使用django admin 则需要以下步骤:

  • 创建后台管理员
  • 配置url
  • 注册和配置django admin后台管理页面

1、创建后台管理员

python manage.py createsuperuser

2、配置后台管理url

url(r'^admin/', include(admin.site.urls))

3、注册和配置django admin 后台管理页面

a、在admin中执行如下配置
from django.contrib import admin
  
from app01 import  models
  
admin.site.register(models.UserType)
admin.site.register(models.UserInfo)
admin.site.register(models.UserGroup)
admin.site.register(models.Asset)
View Code
b、设置数据表名称
class UserType(models.Model):
    name = models.CharField(max_length=50)
  
    class Meta:
        verbose_name = '用户类型'
        verbose_name_plural = '用户类型'
View Code
c、打开表之后,设定默认显示,需要在model中作如下配置
class UserType(models.Model):
    name = models.CharField(max_length=50)
  
    def __unicode__(self):
        return self.name
View Code
from django.contrib import admin
  
from app01 import  models
  
class UserInfoAdmin(admin.ModelAdmin):
    list_display = ('username', 'password', 'email')
  
  
admin.site.register(models.UserType)
admin.site.register(models.UserInfo,UserInfoAdmin)
admin.site.register(models.UserGroup)
admin.site.register(models.Asset)
View Code
d、为数据表添加搜索功能
from django.contrib import admin
  
from app01 import  models
  
class UserInfoAdmin(admin.ModelAdmin):
    list_display = ('username', 'password', 'email')
    search_fields = ('username', 'email')
  
admin.site.register(models.UserType)
admin.site.register(models.UserInfo,UserInfoAdmin)
admin.site.register(models.UserGroup)
admin.site.register(models.Asset)
View Code
e、添加快速过滤
from django.contrib import admin
  
from app01 import  models
  
class UserInfoAdmin(admin.ModelAdmin):
    list_display = ('username', 'password', 'email')
    search_fields = ('username', 'email')
    list_filter = ('username', 'email')
      
  
  
admin.site.register(models.UserType)
admin.site.register(models.UserInfo,UserInfoAdmin)
admin.site.register(models.UserGroup)
admin.site.register(models.Asset)
View Code

更多:http://docs.30c.org/djangobook2/chapter06/

 

 

 

posted @ 2016-10-09 11:56  suoning  阅读(7715)  评论(6编辑  收藏  举报