zoukankan      html  css  js  c++  java
  • Django控制器URL详解

    配置路由

    通过对urls.py的配置将用户请求映射到处理函数。

    Django的URL字符串匹配实际上基于正则表达式,这允许单条URL可以匹配一类请求。参见Django Book中的示例:

    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),
    ]

    实例解析:

    • /articles/2005/03/请求将匹配列表中的第三个模式。Django 将调用函数views.month_archive(request, '2005', '03');无论如何匹配,匹配的内容均将作为Python字符串传递给视图函数。

    • /articles/2005/3/ 不匹配任何URL 模式,因为列表中的第三个模式要求月份应该是两个数字。

    • /articles/2003/ 将匹配列表中的第一个模式不是第二个,因为模式按顺序匹配,第一个会首先测试是否匹配。请像这样自由插入一些特殊的情况来探测匹配的次序。

    • /articles/2003 不匹配任何一个模式,因为每个模式要求URL以一个反斜线结尾。

    在Python 正则表达式中,命名正则表达式组的语法是(?Ppattern),其中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),
    ]

    以命名组的语法重写上述代码,两者区别在于捕获的值作为关键字参数而不是位置参数传递给视图函数

    /articles/2005/03/ 请求将调用views.month_archive(request, year='2005', month='03')函数,而不是views.month_archive(request, '2005', '03')。

    针对正则表达式中的命名组和非命名组,如果有命名参数url解析器将使用命名参数,否则将以位置参数传递所有匹配的字符串。

    进行匹配时将不包括GET或POST请求方式的参数以及域名:

    • http://www.example.com/myapp/

    • http://www.example.com/myapp/?page=3

    对同一个URL的无论是POST请求、GET请求、或HEAD请求方法都将映射到相同的函数。

    urlpatterns 中的每个正则表达式在第一次访问它们时被编译。这使得系统相当快。

    使用include

    urlpatterns可以包含另一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 遇到django.conf.urls.include()时,它会去掉URL 中匹配的部分并将剩下的字符串发送给包含的URLconf 做进一步处理。

    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/(?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)),
    ]

    在这个例子中,URL/credit/reports/将被credit.views.report()这个函数处理。

    编写views函数

    views函数接受封装了HTTP请求的request对象作为参数, 返回response对象作为HTTP响应.

    若返回str对象, django会将其封装为response对象, 也可以返回模板渲染结果或者redirect对象.

    django.http.JsonResponse将一个dict对象构造为JSON格式的响应:

    `return JsonResponse({'result': 'ok'})`

    使用模板

    编写hello.py并保存在templates下:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Hello</title>
    </head>
    <body>
        <p>{{ hello }}</p>
    </body>
    </html>

    修改HelloWorld/settings.py,修改 TEMPLATES 中的 DIRS:'DIRS': [os.path.join(BASE_DIR, 'templates')]

    修改 view.py,增加一个新的对象,用于向模板提交数据:

    from django.shortcuts import render
    
    def hello(request):
        context = {}
        context['hello'] = 'Hello World'
        return render(request, 'hello.html',context)

    render函数原形:

    render(request, template_name[, context][, content_type][, status][, using])[source]

    render(渲染)通常使用3个位置参数:

    render(request, template_name, context = None)

    分别为HttpRequest对象,模板文件名和上下文词典并返回一个渲染后的 HttpResponse 对象。模板引擎可以在上下文context中搜索对象并进行渲染。

    可选参数:

    • content_type:生成的文档要使用的MIME 类型。默认为DEFAULT_CONTENT_TYPE 设置的值。

    • status: 响应的状态码,默认为200.

    • using用于加载模板使用的模板引擎的名称.如:

      • 'django.template.backends.django.DjangoTemplates'

      • 'django.template.backends.jinja2.Jinja2'

    render方法返回响应字符串,render_to_response则返回HttpResponse对象。

    def hello(request):
        context = dict()
        response = render_to_response('test-cookies.html', context)
        return response

    重定向

    重定向将对某一URL的请求,转到另外的URL。

    Django中常用3中方法实现页面重定向。

    在模板视图函数中使用redirect()

    一般情况下redirect()接受一个绝对或相对URL的字符串,并返回一个临时重定向。

    关键字参数permanent的默认值为False,传入permanent=True则可以返回一个永久重定向。

    from django.shortcuts import redirect
    
    def hello(request):
        return redirect(r'^admin/')

    在URL配置中使用redirect_to

    配置ulrs.py

    from django.conf.urls import url
    from django.contrib import admin
    from FirstDjango.view import hello
    from django.views.generic.base import RedirectView
    
    
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^hello/', hello),
        url(r'^world/', RedirectView.as_view(url='/hello/'))
    ]

    访问127.0.0.1/world/的效果等同于访问127.0.0.1/hello/

    使用redirects app进行重定向

    1. 在settings.py 中 增加 'django.contrib.redirects' 到你的 INSTALLED_APPS 设置。

    2. 增加 'django.contrib.redirects.middleware.RedirectFallbackMiddleware' 到的MIDDLEWARE_CLASSES 设置中。

    3. 运行 manage.py syncdb. 创建 django_redirect 表,包含 site_id, old_path and new_path 字段。

    获得请求参数

    HTTP方法用于表示用户提交请求的动作类型, 常用的有GETPOST方法.

    Django将HTTP请求封装为request, 我们可以从中获得请求参数等信息.

    Django的URL匹配不区分请求方法,不对请求参数进行匹配,对同一个URL的不同方法的请求将会映射到同样的处理函数.但是我们可以通过request对象获得HTTP方法的信息.

    请求与响应对象

    HttpRequest

    HttpRequest存储了客户请求的相关参数和一些查询方法。

    • path

    请求页面的全路径,不包括域名—例如, "/hello/"。

    • method

    Http请求方法,包括'GET','POST'。

    • GET

    QueryDict类实例,包含所有HTTP GET参数的字典对象。

    • POST

    QueryDict类实例,包含所有HTTP POST参数的字典对象。

    • REQUEST

    为了方便,该属性是POST和GET属性的集合。

    • COOKIES

    包含所有Cookies的标准Python字典对象,Keys和Values都是字符串。

    HttpRequest.get_signed_cookie(key, default=RAISE_ERROR, salt='', max_age=None)

    返回签名过的Cookie 对应的值,如果签名不再合法则返回django.core.signing.BadSignature。如果提供default 参数,将不会引发异常并返回default 的值。

    可选参数salt可以用来对安全密钥强力攻击提供额外的保护。
    max_age参数用于检查Cookie 对应的时间戳以确保Cookie 的时间不会超过max_age秒。

    HttpRequest.session.set_test_cookie() 设置测试cookie,检验客户端是否支持cookie
    HttpRequest.session.test_cookie_worked() 检测测试cookie,客户端支持时返回True。

    set_test_cookie的同一次请求-响应中test_cookie_worked的结果是不可靠的。

    • FILES

    包含所有上传文件的类字典对象。

    FILES中的每个Key都是<input type="file" name="" />标签中name属性的值,FILES中的每个value 同时也是一个标准Python字典对象,包含3个Key:

    "filename"

    "content-type"

    "content"

    • META

    包含所有可用HTTP头信息的字典,其中的Key包括:

    HTTP_ACCEPT_ENCODING

    HTTP_ACCEPT_LANGUAGE

    HTTP_HOST: 客户发送的HTTP主机头信息

    HTTP_REFERER: referring页

    HTTP_USER_AGENT: 客户端的user-agent字符串

    HTTP_X_BENDER: X-Bender头信息

    • session

    可读写的session对象

    • raw_post_data

    原始的POST数据

    • 其它

    HttpRequest.is_secure()请求是否由Https协议发起

    HttpRequest.is_ajax() 请求是否由Ajax协议发起

    QueryDict

    HttpRequest中的GET和POST属性都是django.http.QueryDict类的实例,它是dict派生类。提供了对一键多值的支持和相关操作方法。

    HttpResponse

    • content

    HttpResponsee.content是存储响应内容的字符串,

    • item

    HttpResponse.__setitem__(header, value) 设置响应头属性

    HttpResponse.__delitem__(header) 删除响应头属性

    HttpResponse.__getitem__(header) 访问响应头属性

    HttpResponse.has_header(header) 检查是否存在响应头属性

    • cookie

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

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

    HttpResponse.set_signed_cookie(key, value, salt='', max_age=None, expires=None, path='/', domain=None, secure=None, httponly=True) 使用带有密钥签名的数据


    GET方法

    GET方法会将请求参数包含在URL中,一般用于发送获取而不改变服务器数据的请求。

    GET方法适合发送搜索查询等请求,因为数据被保存在URL中可以方便地作为书签,分享或重新提交。

    HttpRequest.GET属性是一个封装了GET请求参数的dict,只需要在词典中访问响应的参数即可。

    form-get.html:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <form action="/search-post/" method="get">
            <input type="text" name="search_content">
            <input type="submit" value="submit">
        </form>
    
        <p>{{  result }}</p>
    
    </body>
    </html>

    search.py:

    def search_get(request):
        context = dict()
        if 'search_content' in request.GET:
            context['result'] = request.GET['search_content']
        return render(request, 'form-post.html', context)

    urls.py:

    from django.conf.urls import url
    from django.contrib import admin
    from SecondDjango.views import *
    
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
    
        url(r'form-get/', search),
        url(r'^search-get', search_get),
    ]

    POST方法

    POST方法是更常用的提交数据的方法,它常用来提交要求改变服务器状态的请求如登录请求.

    Django为POST方法提供了CSRF保护,这只需要在模板中添加csrf_token即可。

    HttpRequest.POST属性是一个封装了除file_upload相关参数外POST请求参数的dict,只需要在词典中访问响应的参数即可。因为可能存在空参数的情况,所以要先进行相关校验。

    form-post.html:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <form action="/search-post/" method="post">
            {% csrf_token %}
            <input type="text" name="search_content">
            <input type="submit" value="submit">
        </form>
    
        <p>{{  result }}</p>
    
    </body>
    </html>

    与form-get.html相比,多了{% csrf_token %}用来提供和csrf保护。

    search.py:

    from django.shortcuts import render
    from django.core.context_processors import csrf
    
    # Create your views here.
    
    def search(request):
        return render(request, 'form-post.html', None)
    
    def search_get(request):
        context = dict()
        if 'search_content' in request.GET:
            context['result'] = request.GET['search_content']
        return render(request, 'form-post.html', context)

    urls.py:

    from django.conf.urls import url
    from django.contrib import admin
    from SecondDjango.views import *
    
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
    
        url(r'^form-post/', search),
        url(r'^search-post/', search_post),
    ]

    文件上传

    Django上传文件的内容包含在HttpResponse.FILE中。

    编写file-upload.html:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>File Upload</title>
    </head>
    <body>
        <form action="/handle-upload/" method="post" enctype="multipart/form-data">
            {% csrf_token %}
            <input type="file" name="file">
            <br><br>
            <input type="submit" value="upload">
        </form>
    </body>
    </html>

    编写file-upload-success.html:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>File Upload Success</title>
    </head>
    <body>
        <p>{{ filename }} uploaded successfully</p>
    </body>
    </html>

    编写views.py:

    def handle_upload(request):
        print('handling upload')
        file = request.FILES['file']
        filename = str(request.FILES['file'])
        print(filename)
        if not os.path.exists('upload/'):
            os.mkdir('upload/')
        out = open('upload/' + filename, 'wb+')
        for chunk in file.chunks():
            out.write(chunk)
        print('write finished')
        # render response
        context = dict()
        context['filename'] = filename
        return render(request, 'file-upload-success.html', context)
    
    def upload(request):
        return render(request, 'file-upload.html')

    配置urls.py:

    from django.conf.urls import url
    from django.contrib import admin
    from SecondDjango.views import *
    
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
    
        url(r'^handle-upload/', handle_upload),
        url(r'^upload/', upload),
    ]

    session 与 cookie

    Http协议是无状态协议,以请求-响应的模式工作用户不保持在线状态。session和cookie是用来保持对用户跟踪的常用方法。

    cookies

    cookies是保存在客户端硬盘上的小文件,浏览器在发送请求时会将cookies包含在HttpRequest中一同发送。

    服务端可以在HttpResponse中重新设置cookies, 浏览器收到cookies之后会自动更新保存在客户端硬盘上的cookie文件。

    编写test-cookies.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Test Cookies</title>
    </head>
    <body>
        尹大人被打了{{ num }}次了!
        {{ beat }}
    </body>
    </html>

    编写views.py

    def test_cookies(request):
        context = dict()
        if 'num' in request.COOKIES:
            num = int(request.COOKIES['num']) + 1
        else:
            num = 1
        beat = ''
        for i in range(num+1):
            beat += '啊!'
        context['num'] = str(num)
        context['beat'] = beat
        response = render_to_response('test-cookies.html', context)
        response.set_cookie('num', str(num))
        return response

    因为要使用response.set_cookie所以采用render_to_response渲染。

    配置urls.py

    from django.conf.urls import url
    from django.contrib import admin
    from SecondDjango.views import *
    
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
    
        url(r'^test-cookies/', test_cookies),
    ]

    session

    session(会话)对象是保存了追踪用户信息的词典,一般情况下若浏览器未关闭或未超时session将会有效.

    session使用cookie在客户端保存用于识别用户的token, 数据保留在服务端.

    Django提供了基于缓存、文件和数据库的session引擎, 若要启动session首先在settings.py中进行配置.

    • 修改 MIDDLEWARE_CLASSES 设置,并确定其中包含了 'django.contrib.sessions.middleware.SessionMiddleware'

    • 修改INSTALLED_APPS设置,确定其中包含了
      django.contrib.sessions

    默认情况下以上两个设置为支持session的状态。此外还需设置session引擎SESSION_ENGINE

    • 默认为基于数据库的引擎django.contrib.sessions.backends.db

    • 基于文件的引擎django.contrib.sessions.backends.file

    • 这里采用最简单的基于缓存的引擎django.contrib.sessions.backends.cache

    编写login-session.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Login Session</title>
    </head>
    <body>
         <form action="/login-validate/" method="post">
            {% csrf_token %}
            <input type="text" name="username">
            <input type="password" name="password">
            <input type="submit" value="submit">
        </form>
    
    </body>
    </html>

    编写login-success.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Login Success</title>
    </head>
    <body>
        <p>Welcome, {{ current_user }}!</p>
    </body>
    </html>

    编写keep-online.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Keep Online</title>
    </head>
    <body>
        <p>{{ username }}, you are still online.</p>
    </body>
    </html>

    编写views.py

    def login(request):
        return render(request, 'login-session.html')
    
    def login_validate(request):
        context = dict()
        if request.POST['password'] == 'exciting':
            request.session['current_user'] = 'NaiveUser'
            context['current_user'] = request.session['current_user']
        return render(request, 'login-success.html', context)
    
    def keep_online(request):
        context = dict();
        context['username'] = request.session['current_user']
        return render(request, 'keep-online.html', context)

    可以方便的对HttpRequest.session进行操作,然后使用render将其渲染到HttpResponse中返回客户端。

    配置urls.py

    from django.conf.urls import url
    from django.contrib import admin
    from SecondDjango.views import *
    
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
    
        url(r'^login-session/', login),
        url(r'^login-validate/', login_validate),
        url(r'^keep-online/', keep_online),
    ]

    访问127.0.0.1:8000/login-session/输入"NaiveUser","exciting"登录。在关闭浏览器之前访问127.0.0.1:8000/keep-online/,可以看到:

    访问127.0.0.1:8000/test-cookies/,然后再次发送请求(刷新)。可以发现服务器跟踪了访问的次数。

  • 相关阅读:
    操作系统01_进程和线程管理
    数据库02_字段类型
    鲁滨逊漂流记游戏
    查找数N二进制中1的个数(JS版 和 Java版)
    js中的call、apply
    jQuery对象与Dom对象的相互转换
    jndi配置数据源
    关于JS中变量的作用域-实例
    重写equals()方法时,需要同时重写hashCode()方法
    String与StringBuilder
  • 原文地址:https://www.cnblogs.com/fungitive/p/9136162.html
Copyright © 2011-2022 走看看