Django框架详解

一、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 }} {# .操作只能调用不带参数的方法 #} {{ person_list.0.dream }}

 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() 方法来获取重定向的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

 

posted @ 2018-09-06 22:32  aaronthon  阅读(692)  评论(0编辑  收藏  举报