Python的web框架Django(1):HTTP、简介、静态文件配置、路由系统、视图函数、模板语言、ORM、Ajax、分页器、forms、Cookie、Session、中间件、ModelForm

1. HTTP协议

1)HTTP请求协议

请求格式

POST(方法) /form/entry(URI) HTTP/1.1(协议版本)

HOST:hackr.jp(服务端地址)

Connection:keep-alive

Content-Type:application/x-www-form-urlencoded

Content-Length:16

name=nero&age=25(内容实体)

 

请求方式:get与post请求

  • GET提交的数据会放在URL之后,以?分割URL和传输数据,参数之间以&相连,如EditBook?name=test1&id=123456。
  • POST方法是把提交的数据放在HTTP包的请求体中。
  • GET提交的数据大小有限制(因为浏览器对URL的长度有限制)。
  • GET与POST请求在服务端获取请求数据方式不同

 

2)响应协议

相应格式

HTTP/1.1(协议版本) 200(状态码) OK(状态码的原因短语)

Date:Tue, 10 Jul 2012 06:50:00 GMT(响应首部字段)

Content-Length:362

Content-Type:text/html

...(主体)

 

响应状态码

状态码是当客户端向服务器端发送请求时,返回的请求结果。借助状态吗,用户可以知道服务器端是正常处理了请求还是出现了异常。响应状态吗分别有以下5种。

  类别 原因短语
1XX Informational(信息行状态码) 接收的请求正在处理
2XX Success(成功状态码) 请求正常处理完毕
3XX Redirection(重定向状态码) 需要进行附加操作以完成请求
4XX Client Error(客户端错误状态码) 服务器无法处理请求
5XX Server Error(服务器错误状态码) 服务器处理请求出错

 

 

 

2. Django的简介:

1)Django的MTV模式

Model(模型):负责业务对象与数据库的对象(ORM)

Template(模板):负责如何把页面展示个用户

View(视图):负责业务逻辑,并在适当的时候调用Model和Template

此外,Django还有一个url分发器,它的作用是将一个个URL的页面请求分发给不同的view处理,view再调用相应的Model和Template

 

一般用户通过浏览器向我们的服务器发起一个请求(request),这个请求会去访问视图函数。试图函数调用模型,模型去数据库查找数据,然后逐级返回,视图函数把返回的数据填充到模板空格中,最后返回网页给用户。

 

2) Django工程

(1)创建一个django工程:djando-admin.py startproject mysite

manage.py Django项目里面的工具,通过它可以调用django.shell和数据库等

settings.oy 包含了项目的默认设置,包括数据库信息,调试标志以及其他一些工作的变量

urls.py 负责把URL模式映射到应用程序

(2)在mysite目录下创建blog应用:python manage.py startapp blog

(3)启动djando项目:python manage.py runserver 8080

 

3) settings配置文件

TEMPLATES下的

'DIRS': [os.path.join(BASE_DIR, 'templates')]

做了一个路径拼接

 

 

 

3. 静态文件配置

在根目录下生成一个“static”目录,用于存储静态文件,那么需要在settings.py文件中添加如下代码

STATIC_URL = 'static' # 别名

STATICFILES_DIRS=[
    os.path.join(BASE_DIR, "static"), # 真实的static文件夹目录路径
]

 

 

 

4.  Django URL路由系统

本质上是url模式与视图函数之间的对应

urlpatterns = [

    path(正则表达式, views视图函数, 参数, 别名),
]

 

1)路由系统的使用

正则表达式:一个正则表达式字符串

views视图函数:一个可调用对象,通常为一个视图函数或一个指定视图函数路径的字符串

参数:可选的要传递给视图函数的默认参数(字典形式)

别名:一个可选的name参数

from django.contrib import admin
from django.urls import path
from blog import views
from django.conf.urls import url,include

urlpatterns = [
    path('admin/', admin.site.urls),
    path("current_time", views.current_time),
    path("user_info", views.user_info),
    # 按照位置接收参数,参数接受顺序必须一致
    url(r"^articles/([0-9]{4})/$", views.year_archive),
    # 按照参数名接收参数,有名分组
    url(r"^articles/(?P[0-9]{4})/(?P[0-9]{2})/$", views.month_archive),
    # 参数三
    url(r"^articles/(?P[0-9]{4})/(?P[0-9]{2})/$", views.month_archive,
        {"year": "1990", "month": "8"}),
    # 参数四
    url(r"^articles/(?P[0-9]{4})/(?P[0-9]{2})/$", views.month_archive,
        {"year": "1990", "month": "8"}, name="articles"),

    # url映射分发
    url(r"^blog/", include('blog.urls'))

]

注意:

  • 若要从URL中捕获一个值,只需要在它周围放置一对圆括号
  • 不需要添加一个前导的反斜杠,因为每个URL都有。例如,应该是^articles而非^/articles
  • 每个正则表达式前面的“r”是可选的但建议加上。它告诉Python这个字符串是“原始的”--字符串中任何字符都不应该转义

 

2)反向解析

在urls.py文件中设置别名

urlpatterns = [
    path("login/", views.login, name="Login"),
]

在html文件中填写别名

通过reverse方法可以反向解析出url

from django.urls import reverse
url = reverse('Login')
print(url)

 

3)名称空间

名称空间是表示标识符的可见范围。一个标识符可在多个命名空间中定义,它在不同名称空间中的含义是互不相干的。这样,在一个新的名称空间中可定义任何标识符,它们不会与任何已有的标识符发生冲突,因为已有的定义都处于其他名称空间中。

由于name没有作用域,Django在反解URL时,会在项目全局顺序搜索,当查找到第一个name指定URL时,立即返回我们在开发项目时,会经常使用name属性反解出URL,当不小心在不同的app的urls中定义相同的name时,可能会导致URL反解错误,为了避免这种事情的发生,引入了名称空间。

projects的urls.py:

urlpatterns = [
    re_path(r'^admin/', admin.site.urls),
    re_path(r'^app01/', include("app01.urls", namespace="app01"))
    re_path(r'^app02/', include("app02.urls", namespace="app02"))
]

app01.urls:

urlpatterns = [
    re_path(r"^index/", index, name="index")
]

app02.urls:

urlpatterns = [
    re_path(r"^index/", index, name="index")
]

app01.views

from django.core.urlresolvers import reverse

def index(request):
    return HttpResponse(reverse("app01:index"))

app02.views

from django.core.urlresolvers import reverse

def index(request):
    return HttpResponse(reverse("app02:index"))

 

4)path方法

from django.urls import path
from . import views

ulrpatterns = [
    path('articles/2003', views.special_case_2003),
    path('articles//', views.year_archive),
    path('articles///', views.month_archive),
    path('articles///', views.article_detail),
]

(1)基本规则:

  • 使用尖括号(<>)从url中捕获值
  • 捕获值中可以包含一个转化器类型(converter type),比如使用捕获一个整数变量。如果没有转化器,将匹配任何字符串,当然也包括了/字符。
  • 无需添加前导斜杠

 

(2)path转化器:

  • Django默认支持以下5个转化器
  • str,匹配除了路径分隔符(/)之外的非空字符串,这是默认的形式
  • int,匹配正整数,包含0
  • slug,匹配字母、数字以及斜杠、下划线组成的字符串
  • uuid,匹配格式化的uuid,如0145881rp-5615-1415-aef1-nvaogr425
  • path,匹配任何非空字符串,包含了路径分隔符

 

(3)path的自定义转换器

对于一些复杂或复用的需要,可以定义自己的转化器。转化器是一个类或接口,它有3个要求:

  • regex类属性,字符串类型
  • to_python(self, value)方法,value是由类属性regex所匹配到的字符串,返回具体的Python变量值,以供Django传递到对应的视图函数中
  • to_url(self, value)方法,和to_python相反,value是一个具体的Python变量值,返回其字符串,通常用于url反向引用

创建一个类

class MonConvert:
    regex = "[0-9]{2}"
    
    def to_python(self, value):
        return int(value)
    
    def to_url(self, value): # 反向解析
        return '%04d' % value

在url路径控制中注册定义的url转换器

register_converter(MonConvert, "mm")

在path方法中使用

path("articles/", views.mon_path)

 

 

 

5. Django视图函数

一个视图函数,简称视图,是一个简单的Python函数,它接受Web请求并且返回Web响应。响应可以是一张网页的HTML内容,一个重定向,一个404错误,一个XML文档,或者一张图片。为了将代码放在某处,约定是将视图放置在项目或应用程序目录中的名为views.py的文件中。

 

http请求中产生两个核心对象:

http请求:HttpRequest对象

Http响应:HttpResponse对象

所在位置:django.http

 

1) HttpRequest对象

(1)属性:

1. HttpRequest.path
一个字符串,表示请求页面的全路径,不包括域名

2. HttpRequest.GET
一个类似于字典的对象,包含所有HTTP GET参数的类字典对象

3. HttpRequest.POST
一个类似于字典的对象,包含所有HTTP POST参数的类字典对象。POST请求可以带有空的POST字典 -- 如果通过HTTP POST方法发送一个表单,但是表单中没有任何的数据,QueryDict对象依然会被创建。因此,不应该使用 if request.POST来检查使用的是否是POST方法;应该使用 if request.method == "POST"
另外:如果使用POST上传文件的话,文件信息将包含在FILES属性中。

4. HttpRequest.body
一个字符串,代表请求报文的主体。在处理非HTTP形式的报文时非常有用,例如:二进制图片、XML、JSON等。但是如果要处理表单数据的时候,推荐使用HttpResponse.POST

5. HttpRequest.method
一个字符串,表示请求使用的HTTP方法。必须使用大写。例如:“GET”、“POST”
method:请求中使用的http方法的字符串表示。全大写表示
if request.method == "GET":
    pass
elseif request.method == "POST":
    pass

6. HttpRequest.encoding
一个字符串,表示提交的数据的编码方式(如果为None则表示使用DEFAULT_CHARSET的设置,默认为'utf-8')。这个属性是可写的,可以修改来修改访问表单数据使用的编码。
接下来对属性的任何访问(例如从GET或POST中读取数据)将使用新的encoding值。
如果知道表单数据的编码不是DEFAULT_CHARSET,则使用它。

7. HttpRequest.META
一个标准的Python,包含所有的HTTP首部。具体的头部信息取决于客户端和服务器

8. HttpRequest.FILES
包含所有上传文件的类字典对象;FILES中的每个key都是标签中name属性的值,FILES中的每一个value同时也是一个标准的python字典对象,包含下面三个Keys:
    filename:上传文件名,用字符串表示
    content_type:上传文件的Content Type
    content:上传文件的原始内容
注意:FILES只有请求的方法为POST且提交的
带有enctype="multipart/form-data"的情况下才会包含数据。否则,FILES将为一个空的类似于字典的对象。 9. HttpRequest.COOKIES 包含所有cookies的标准Python字典对象;keys和values都是字符串 10. HttpRequest.session 一个即可读又可写的类似于字典的对象,表示当前的会话。只有当Django启动会话的支持时才可用。      11. HttpRequest.user 一个django.contrib.auth.models.User对象,代表当前登录的用户。如果访问用户当前没有登录,user将被初始化为django.contrib.auth.models.AnonymousUser的实例。你可以通过user的is_authenticated()方法来辨别用户是否登录:     if request.user.is_authenticated(): 只有激活Django中的AuthenticationMiddleware时该属性才可用

 

(2)request常用方法

1. HttpRequest.get_full_path()
返回path,如果可以将加上查询的字符串
例如:“/index”

2. HttpRequest.is_ajax()
如果请求是通过XMLHttpRequest发起的,则返回true,方法是检查HTTP_X_REQUESTED_WIDTH相应的首部是否是字符串“XMLHttpRequest”。
大部分现代的JavaScript库都会发送这个头部。如果编写自己的XMLHttpRequest调用(在浏览器端),必须手工设置这个值来让is_ajax()可以工作。
如果一个响应需要根据请求是否是通过AJAX发起的,并且正在使用某种形式的缓存例如Django的cache middleware,应该使用vary_on_headers('HTTP_X_REQUESTED_WITH')装饰你的视图以让响应能够正确的缓存。

 

2)HttpResponse对象:

每个view请求处理方法必须返回一个HttpResponse对象。HttpResponse类在django.http.HttpResponse

在HttpResponse对象上扩展的常用方法:

    页面渲染:render(), render_to_response(),

    页面跳转:redirect()

    locals():可以直接将函数中所有的变量传给模板

 

相应对象主要有三种形式:

  • HttpResponse()
  • render()
  • redirect

 

(1)render()

render(request, template_name[, context])
结合一个给定的模板和一个给定的上下文字典,并返回一个渲染后的HttpResponse对象。

参数:

  • request:用于生成相应的请求对象
  • template_name:要使用的模板的完整名称,可选的参数
  • context:添加到模板上下文的一个字典。默认是一个空字典。如果字典中的某个值是可调用的,视图将在渲染模板之前调用它。

render方法就是将一个模板页面中的模板,最终渲染成一个html页面作为响应体。

 

(2)redirect()

传递要重定向的一个硬编码的URL

def my_view(request):
    ...
    return redirect("/index")

 

 

 

6. 模板语言

1)模板语法之变量

在Django模板中遍历复杂数据结构的关键是句点字符。万能的句点号,列表、字典、属性、类都可以用.来取到。 语法:

{{ var_name }}

def index(request):
    import datetime
    s = "hello"
    l = [11, 22, 33]
    dic = {"name": "adam", "age": 24}
    date = datetime.date(1993, 5, 2)

    class Person(object):
        def __init__(self, name):
            self.name = name

    p1 = Person("Bruce" ,25)
    p2 = Person("Chris", 28)
    p3 = Person("David", 33)

    person_list = [p1, p2, p3]

    return render(request, "index.html". {"l": l, "data": data, "person_list": person_list})

template:

{{ l }}

{{ l.2 }}

{{ dic.name }}

{{ person_list.0.name }}

注意:句点符也可以用来应用对象的方法(无参数方法):

字典:{{ dic.name.upper }}

 

2)模板之过滤器

语法:{{ obj | filter_name: param }}

使用案例:

  • {{ ship_date|date:"FJ,Y"}},ship_date变量传给date过滤器,date过滤器通过使用“FJ,Y”这几个参数来格式化日期数据。
  • {{ obj|upper }}
  • {{ obj|lower }}
1. default
如果一个变量是false或者为空,使用给定的默认值。否则,使用变量的值。例如:
{{ value|default:"nothing"}}

2. length
返回值得长度。它对字符串和列表都起作用。例如:
{{ value|length }}
如果value是['a', 'b', 'c', 'd'],name输出为4

3. filesizeformat
将值格式化为一个“人类可读的”文件尺寸(例如“13KB”,“4.1MB”,“1.2GB”)
{{ value|filesizeformat }}

4. date
如果value = datetime.datetime.now()
{{ value|date:"Y-m-d" }}

5. slice
如果value = "hello world"
{{ value|slice:"2:-1"}}

6. truncatechars
如果字符串字符多于指定的字符数量,那么会被截断。截断的字符串将以可翻译的省略号序列(“...”)结尾。
参数:要截断的字符数
{{ value|truncatechars:9 }}

7. safe
Django的模板中会对HTML标签和JS等语法标签进行自动转义,为了安全。但有时我们不希望这些HTML元素被转义。
value = "点击"
{{ value|safe }}

其它常用过滤器:

add:给变量加上相应的值

addslashes:给变量中的引号前加上斜线

capfirst:首字母大写

cut:从字符串中移除指定的字符

default_if_none:如果值是None就替换成设置的默认值,否则就使用本来的值

 

3)模板之标签

一些在输出中创建文本,一些通过循环或逻辑来控制流程,一些加在其后的变量将使用到的额外信息到模板中。一些标签需要开始和结束标签

 

(1)for标签,遍历每一个元素

{% for person in person_list %}
    

{{ person }}

{% endfor %}

可以利用{% for obj in list reversed %}反向完成循环

遍历一个字典:

{% for key, val in dic.items %}
    

{{ key }}:{{ val }}

{% endfor %}

注:循环序号可以通过{{ forloop }}显示

  • forloop.counter 从1开始
  • forloop.counter0 从0开始
  • forloop.revcounter
  • forloop.revcounter0 
  • forloop.first
  • forloop.last

 

(2)for ... empty

for标签带有一个可选的{% empty %}从句,以便在给出的组是空的或者没有被找到时,可以有所操作

{% for person in person_list %}

    

{{ person.name }} {% empty %}

sorry, no person here

{% endfor %}

 

(3)if标签

{% if %}会对一个变量求值,如果它的值是“True”(存在、不为空、且不是boolean类型的false值),对应的内容块会输出。

{% if num > 100 or num < 0 %}
    

Hello World

{% elif num > 60 and num <= 100 %}     

Buy

{% else %}

Bye

{% endif %}

 

(4)with

使用一个简单的名字缓存一个复杂的变量

{% with total = business.employees.count %}
    {{ total }} employee {{ total|pluralize }}
{% endwith %}

 

(5)csrf_token

{% csrf_token %}(加在form标签最后一行)

用于生成csrf_token的标签,用于防止跨站攻击验证

 

(6){% url %}

引用路由配置的地址

 

4)模板语言之自定义标签与过滤器

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

b. 在app中创建templatetags模块(模块名只能是templatetags)

c. 创建任意.py文件,如my_tags.py

from django import template
from django.utils.safestring import mark_safe

register = template.Library() # register的是固定变量名,不能改变


@register.filter
def filter_multi(v1, v2):
    return v1 * v2


@register.simple_tag
def simple_tag_multi(v1, v2):
    return v1 * v2

@register.simple_tag
def my_input(id, arg):
    result = "" % (id, arg, )
    return mark_safe(result)

d. 在使用自定义的html文件中导入之前创建的my_tags.py文件名

{% load my_tags %}

e. 使用simple_tag和filter

{% load my_tags %}

{{ num|filter_multi: 2}}

{% simple_tag_multi 2 5 %} # 参数不限,但不能放在if for语句中
{% simple_tag_multi num 5 %}

注意:filter可以用在if等语句后,simple_tag不可以

 

5)模板语言之继承

Django模板引擎中最强大也是最复杂的就是模板继承。模板继承可以创建以基本的“骨架”模板,它包含站点中的全部元素,并且可以定义能够被子模板覆盖的blocks。



    
    {% block title %}My Amazing Site(% endblock %)



    

上面这个模板叫作base.html。在这个例子中,block标签定义了3个可以被子模板内容填充的block。block告诉模板引擎:子模板可能会覆盖掉模板中的这些位置。

子模板可能如下:

{% extends "base.html" %}

{% block title%}
    My Amazing Blog
{% endblock %}

{% block content %}
    {% for blog in blogs %}
        

{{ blog.title }}

{{ blog.body }}

{% endfor %} {% endblock %}

extends标签是这里的关键。它告诉模板引擎这个模板“继承”了另一个模板。

请注意,子模板并没有定义sidebar block,所以系统使用了父模板中的值。

这种方式使代码得到最大程度的复用,并且使得添加内容到共享的内容区域更加简单

使用继承的一些提示:

  • 如果在模板中使用{% extends %}标签,它必须是模板中的第一个标签。其他的任何情况下,模板继承都将无法工作
  • 在base模板中设置越多的{% block %}标签越好。子模板不必定义全部父模板中的blocks,所以,可以在大多数blocks中填充合理的默认内容。
  • 如果发现在大量的模板中复制内容,那可能意味着应该把内容移动到父模板中的一个{% block %}中。
  • 如需父模板中的内容没,加入{{ block.super }}标签
  • 为了更好的可读性,也可以给{% endblock %}标签一个名字。
{% block content%}
...
{% endblock content%}
  • 不能在一个模板中定义多个相同名字的block标签

 

 

 

7. djando ORM

ORM实现了数据模型与数据库的解耦,即数据模型的设计不需要依赖于特定的数据库,通过简单的配置就可以轻松更换数据库,这极大地减轻了开发人员的工作量,不需要面对因数据库变更而导致的无效劳动。

ORM是“对象-关系-映射”的简称。

 

1)常用字段

1. CharField
字符串字段,用于较短的字符串
CharField要求必须有一个参数maxlength,用于从数据层和Django校验层限制该字段所允许的最大字符数。

2. IntegerField
用于保存一个整数

3. FloatField
一个浮点数,必须提供一个整数
max_digits 总位数
decimal_places 小数位数

4. AutoField
一个IntegerField,添加记录时它会自动增长,通常不需要直接使用这个字段;
自定义一个主键:my_id=models.AutoField(primary_key=True)
如果不指定主键的话,系统会自动添加一个关键字段到model

5. BooleanField
A true/false field. admin用checkbox来表示此类字段

6. TextField
一个容量很大的文本字段
admin用一个