一、WSGI接口

WSGI服务网关接口:Web Server Gateway Interface缩写。

WSGI是python定义的Web服务器和Web应用程序之间或框架之间的通用接口标准。

WSGI定义:Web开发者实现了一个函数,并响应HTTP请求。

WSGI将Web组件分成三类:Web服务器(WSGI Server),Web中间件(WSGI Middleware),Web用用程序(WSGI Application).

Web服务器接收HTTP请求,调用WSGI接口标准注册的WSGI Application,最后将响应返回给客户端。

Web应用的本质:1.浏览器发送HTTP请求。

                            2.服务器接收请求,生成HTML页面。

                            3.服务器将HTML页面当成HTTP响应的body发送给浏览器。

                            4.浏览器接收到HTTP响应,并从HTTP Body中HTML并渲染出来

二、中间件

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

中间件的官方说法是中间件是一个用来处理django的请求和相应的框架级别的钩子。在全局范围内改变django的输入和输出,每个中间件都有特定的功能。

中间件可以定义五个方法:1.process_request(self, request)

                                          2.process_response(self, request, response)

                                          3.process_view(self, request, view_func, view_args, view_kwargs)

                                          4.process_exception(self, request, exception)

                                          5.process_template_response(self, request, response)

以上方法返回的可以是None也可以是HttpResponse对象,如果是None,这继续按照django的规则继续执行下面的中间件,如果是HttpResponse对象,则直接把对象返回给用户。

process_request

process_request有一个参数,就是request,这个request和视图函数中的request是一样的。它的返回值可以是None也可以是HttpResponse对象。返回值是None的话,按正常流程继续走,交给下一个中间件处理,如果是HttpResponse对象,Django将不执行视图函数,而是直接走本中间件的process_response方法,倒序返回,将相应对象返回给浏览器。

  1. 中间件的process_request方法是在执行视图函数之前执行的。
  2. 当配置多个中间件时,会按照MIDDLEWARE中的注册顺序,也就是列表的索引值,从前到后依次执行的。
  3. 不同中间件之间传递的request都是同一个对象

process_response

process_response有两个参数,一个是request,一个是response。这里面的request和process_request里面的参数request是一样的对象,response是视图函数返给回给用户的是Httpresponse对象,并且该方法返回值必须是HttpResponse对象。

  1. 中间件的process_response方法是在执行视图函数之后执行的。
  2. 当配置多个中间件时,会按照MIddleware注册顺序的倒序执行,从后往前执行。

process_view

process_view有四个参数:1.request是HttpResponse对象

             2.view_func是django即将用到的视图函数,它是实际的视图函数

                                           3.view_args是传递给视图函数的位置参数的列表

                                           4.view_kwargs是传递给视图函数的关键之参数的字典

                                           5.args和kwargs都不包含第一个参数request

  1. 中间件的process_view方法是在执行视图函数之前执行的。
  2. process_view方法是在所有的process_request方法执行完之后执行的
  3. 当配置多个中间件时,会按照Middleware的注册顺序从前往后执行

process_view它应该返回一个None或HttpResponse对象,如果返回None,则继续执行剩下的中间件的process_view方法,然后再执行相应的视图。如果返回HttpResponse对象,则不再执行剩下的process_view和后面的视图函数,它将执行中间件的process_response方法并将应用到HttpResponse并返回结果。

process_exception

process_exception有两个参数:request是一个HttpResponse对象,exception是视图产生的Exception对象。这个方法是只有视图函数执行异常时才执行的,它返回的对象可以是一个None也可以是一个HttpResponse对象。如果是HttpResponse对象,django将调用模板和process_response方法并返回给浏览器。,否则默认处理异常。

  1. 如果视图函数中无异常,process_exception方法则不执行。
  2. 当配置多个中间件时,会按照Middleware的注册顺序从后往前执行
  3. 当一个中间的process_exception方法执行了,则直接调用process_response方法,不再执行其他中间件的process_exception方法

process_template_response

它有两个参数,request参数是HttpResponse对象,response参数是TemplateResponse对象(由视图函数或中间件产生)。

  1. process_template_response方法是在视图函数之后立即执行
  2. 但是它由一个前提条件,就是视图函数返回的对象有一个render()(或则表明表明该对象是一个TemplateResponse对象或等价方法)
  3. 当配置多个中间件时,会按照Middleware的注册顺序从后往前执行
  4. 然后执行视图函数返回的HttpResponse对戏那个的render()方法,并返回一个新的HttpResponse对象
  5. 然后执行process_response方法

 三、URL路由系统(URLconf)

URL配置(URLconf)就像django所支撑网站的目录,它的本质就是该URL和要为该URL调用的视图函数之间的映射表。

# 基本配置
from djago.conf.urls import url

urlpattrens = [
url(正则表达式,views视图函数名,参数,别名),
]
# 注意事项
1.从上到下一次匹配,一旦匹配成功就不再匹配
2.不需要添加一个前导的斜杠,因为每个URL都有
3.每个正则表达式前的r是可选的,但建议加上
# 补充说明
APPEEND_SLASH = True # django默认为True,作用就是自动在网址末尾加/
  1. URLconf不检验请求方法,同一个URL不论什么请求方式,都走同一个视图函数。
  2. 捕捉到的参数永远都是字符串
# 起别名
url(r'^home', views.home, name='home'), # 给我的url匹配模式起名为 home
url(r'^index/(\d*)', views.index, name='index'), # 给我的url匹配模式起名为index

这样:

在模板里面可以这样引用:

{% url 'home' %}

在views函数中可以这样引用:

from django.urls import reverse

reverse("index", args=("2018", ))

命名空间模式

即使不同的APP使用相同的URL名称,URL的命名空间模式也可以让你唯一反转命名的URL。

举个例子:

project中的urls.py

from django.conf.urls import url, include

urlpatterns = [
url(r'^app01/', include('app01.urls', namespace='app01')),
url(r'^app02/', include('app02.urls', namespace='app02')),
]

app01中的urls.py

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

app_name = 'app01'
urlpatterns = [
url(r'^(?P<pk>\d+)/$', views.detail, name='detail')
]

app02中的urls.py

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

app_name = 'app02'
urlpatterns = [
url(r'^(?P<pk>\d+)/$', views.detail, name='detail')
]

现在,我的两个app中 url名称重复了,我反转URL的时候就可以通过命名空间的名称得到我当前的URL。

语法:

'命名空间名称:URL名称'

模板中使用:

{% url 'app01:detail' pk=12 pp=99 %}

views中的函数中使用

v = reverse('app01:detail', kwargs={'pk':11})

 这样即使app中URL的命名相同,我也可以反转得到正确的URL了。

 有名分组

# 这种形式是无名分组
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中的值并以位置参数传递给视图。在更高级的用法中,可以使用命名的正则表达式组来捕获URL 中的值并以关键字 参数传递给视图。

在Python 正则表达式中,命名正则表达式组的语法是​​(?P<name>pattern)​​​,其中​​name​​​ 是组的名称,​​pattern​​ 是要匹配的模式。

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')函数
/articles/2003/03/03/
请求将调用函数views.article_detail(request, year='2003', month='03', day='03')。

四、Template模板

 python的模板:HTML代码+逻辑控制代码

# 变量  用双大括号来引用变量  用法:{{ title }}
# 逻辑  用大括号和百分号组合  用法:{% for user in user_list %}  {% endfor %}
# 点 .  在模板里面有特殊的含义,就是获取对象的相应属性值  {{ user.name }}
# 模板中支持的写法
{# 取l中的第一个参数 #}
{{ l.0 }}
{# 取字典中key的值 #}
{{ d.name }}
{# 取对象的name属性 #}
{{ person_list.0.name }}
{# .操作只能调用不带参数的方法 #}

 Filters过滤器的使用

语法: {{ value|filter_name:参数 }}  
{{ value|default:"nothing" }}
{{ value|length }} # 返回value的长度
{{ value|filesizeformat }} # 将十进制数转为为KB,MB,GB等
{{ value|slice:"2:-1" }} # 切片
{{ value|data:"Y-m-d H:i:s" }} # 格式化时间
{{ value|safa }} # 告诉django这段代码是安全的,不必转译
{{ value|truncatechars:9 }} # 截断,如果value的字符数大于9,则只显示前9个字符,后面的用...表示。
{{ value|upper }} # 将value的字母全变成大写
{{ value|add:2 }} # value值+2并显示
{{ value|cut:"a" }} # 移除指定字符

自定义filter过滤器

from django import template
register = template.Library()

@register.filter(name="cut")
def cut(value, args):
return value.replace(args, "")

@register.filter(name="add")
def add(value):
return "{}很可爱!".format(value)
{# 先导入我们自定义filter那个文件 #}
{% load app01_filters %}

{# 使用我们自定义的filter #}
{{ somevariable|cut:"0" }}
{{ value|add }}

注意:以上代码要在django项目中使用

前端未完待续......

五、Views视图

 django的两种处理请求的方式:FBV和CBV

FBV:function base views  在视图里面基于函数处理请求

CBV:class base views  在视图里面基于类处理请求

# urls.py中
url(r'^add_class/$', views.AddClass.as_view()),

Response对象

HttpResponse类位于django.http模块中。

使用

传递字符串

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['Content-Type'] = 'text/html; charset=UTF-8'
del response['Content-Type']

属性

HttpResponse.content:响应内容

HttpResponse.charset:响应内容的编码

HttpResponse.status_code:响应的状态码

JsonResponse对象

JsonResponse是HttpResponse的子类,专门用来生成JSON编码的响应。

from django.http import JsonResponse

response = JsonResponse({'foo': 'bar'})
print(response.content)

b'{"foo": "bar"}'

默认只能传递字典类型,如果要传递非字典类型需要设置一下safe关键字参数。

response = JsonResponse([1, 2, 3], safe=False)

render()

结合一个给定的模板和一个给定的上下文字典,并返回一个渲染后的 HttpResponse 对象。

from django.shortcuts import render

def my_view(request):
# 视图的代码写在这里
return render(request, 'myapp/index.html', {'foo': 'bar'})

redirect()

参数可以是:

  • 一个模型:将调用模型的get_absolute_url()
  • 一个视图,可以带有参数:将使用urlresolvers.reverse
  • 一个绝对的或相对的URL,将原封不动的作为重定向的位置。

默认返回一个临时的重定向;传递permanent=True

示例:​

你可以用多种方式使用redirect()

传递一个具体的ORM对象(了解即可)

将调用具体ORM对象的get_absolute_url()

from django.shortcuts import redirect

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

传递一个视图的名称

def my_view(request):
...
return redirect('some-view-name', foo='bar')

传递要重定向到的一个具体的网址

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

当然也可以是一个完整的网址

def my_view(request):
...
return redirect('http://example.com/')

默认情况下,redirect() 返回一个临时重定向。以上所有的形式都接收一个permanent 参数;如果设置为True,将返回一个永久的重定向:

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

扩展阅读: 

临时重定向(响应状态码:302)和永久重定向(响应状态码:301)对普通用户来说是没什么区别的,它主要面向的是搜索引擎的机器人。

A页面临时重定向到B页面,那搜索引擎收录的就是A页面。

A页面永久重定向到B页面,那搜索引擎收录的就是B页面。

6.2、操作表

基本操作

# 增
#
# 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='seven').delete() # 删除指定条件的数据

# 改
# models.Tb1.objects.filter(name='seven').update(gender='0') # 将指定条件的数据更新,均支持 **kwargs
# obj = models.Tb1.objects.get(id=1)
# obj.c1 = '111'
# obj.save() # 修改单条数据
# save是更改所有字段,即使更改一个字段,也会将所有字段重新赋值, 不推荐
# update更改,只更改修改的字段,推荐使用

# update方式修改不能用get的原因是:update是QuerySet对象的方法,get返回的是一个model对象,它没有update方法,而filter返回的是一个QuerySet对象(filter里面的条件可能有多个条件符合,比如name='alvin',可能有两个name='alvin'的行数据)

基本操作

基本操作

查询相关API

# 查询相关API:

# <1>filter(**kwargs): 它包含了与所给筛选条件相匹配的对象

# <2>all(): 查询所有结果

# <3>get(**kwargs): 返回与所给筛选条件相匹配的对象,返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有都会抛出错误。

#-----------下面的方法都是对查询的结果再进行处理:比如 objects.filter.values()--------

# <4>values(*field): 返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一系列 model的实例化对象,而是一个可迭代的字典序列

# <5>exclude(**kwargs): 它包含了与所给筛选条件不匹配的对象

# <6>order_by(*field): 对查询结果排序

# <7>reverse(): 对查询结果反向排序

# <8>distinct(): 从返回结果中剔除重复纪录

# <9>values_list(*field): 它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列

# <10>count(): 返回数据库中匹配查询(QuerySet)的对象数量。

# <11>first(): 返回第一条记录

# <12>last(): 返回最后一条记录

# <13>exists(): 如果QuerySet包含数据,就返回True,否则返回False

查询相关API

查询API

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

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

# 大于,小于
#
# models.Tb1.objects.filter(id__gt=1) # 获取id大于1的值
# models.Tb1.objects.filter(id__gte=1) # 获取id大于等于1的值
# models.Tb1.objects.filter(id__lt=10) # 获取id小于10的值
# models.Tb1.objects.filter(id__lte=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

# isnull
# Entry.objects.filter(pub_date__isnull=True)

# 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='seven').order_by('id') # asc
# models.Tb1.objects.filter(name='seven').order_by('-id') # desc

# 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"

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

# regex正则匹配,iregex 不区分大小写
#
# Entry.objects.get(title__regex=r'^(An?|The) +')
# Entry.objects.get(title__iregex=r'^(an?|the) +')

# date
#
# Entry.objects.filter(pub_date__date=datetime.date(2005, 1, 1))
# Entry.objects.filter(pub_date__date__gt=datetime.date(2005, 1, 1))

# year
#
# Entry.objects.filter(pub_date__year=2005)
# Entry.objects.filter(pub_date__year__gte=2005)

# month
#
# Entry.objects.filter(pub_date__month=12)
# Entry.objects.filter(pub_date__month__gte=6)

# day
#
# Entry.objects.filter(pub_date__day=3)
# Entry.objects.filter(pub_date__day__gte=3)

# week_day
#
# Entry.objects.filter(pub_date__week_day=2)
# Entry.objects.filter(pub_date__week_day__gte=2)

# hour
#
# Event.objects.filter(timestamp__hour=23)
# Event.objects.filter(time__hour=5)
# Event.objects.filter(timestamp__hour__gte=12)

# minute
#
# Event.objects.filter(timestamp__minute=29)
# Event.objects.filter(time__minute=46)
# Event.objects.filter(timestamp__minute__gte=29)

# second
#
# Event.objects.filter(timestamp__second=31)
# Event.objects.filter(time__second=2)
# Event.objects.filter(timestamp__second__gte=31)

进阶操作

双下方法

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

利用双下划线和 _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())

OneToOne