首页 > 技术文章 > django路由层

LearningOnline 2018-06-23 15:15 原文

0.上节关键命令

  创建项目   django-admin startproject 项目名称
  创建应用   python manage.py startapp app名称
  启动项目   python manage.py runserver IP PORT

1.url配置(URLconf)

  功能:URLconf就像是django所支撑网站的目录,它其实建立起了url与视图函数的映射关系。通过这种方式告诉django,客户端发来的某个url调用哪一段逻辑代码对应执行

  例如当用户访问/views/时,去调用相关的视图函数,这个视图函数存在于views.Py中  

  django和URL配置背后的哲学遵循松耦合原则,松耦合是一个重要的保证互换性的软件开发方法

  url下的path是django2.0的语法,re_path属于1.0的语法,目前2.0也兼容这种语法,导入即可

url部分(记住了,一个url模式就是一个正则表达式)

urlpatterns = [
    # 用户在url中输入127.0.0.1:8000/articles/2003/,可以直接调用函数
    url(r'^articles/2003/$', views.special_case_2003),
    # 利用优先匹配,获取用户输入年月
    url("^articles/(\d{4})/(\d{2})/$", views.article_month),
    # 什么都不写也会默认访问这一个index视图,这个也很重要
    url(r'^$', views.index),
]

#  正则表达式字符串的开头字母“r”。 它告诉Python这是个原始字符串,不需要处理里面的反斜杠(转义字符)

# 当为网站根目录实现一个视图,你需要使用URL模式`` ‘^$’`` , 它代表一个空字符串

views部分

from django.shortcuts import render,HttpResponse,redirect
from django.urls import reverse

# Create your views here.

def special_case_2003(request):
    return HttpResponse('get it')

def article_month(request,year,month):
    print(year, type(year))
    print(month, type(month))
    return HttpResponse(year + ":" + month)

def index(request):
    return HttpResponse('首页默认显示')

注:

  若要在url中捕获一个值,只需要在他周围加上一对圆括号,如上例

  不需要添加一个前导的反斜杠,因为每个URL 都有。例如,应该是^articles 而不是 ^/articles

  每个正则表达式前面的'r' 是可选的但是建议加上。它告诉Python 这个字符串是“原始的” —— 字符串中任何字符都不应该转义

1.2有名分组

  上面简单配置只是通过简单配置来捕获URL中的值,并通过位置参数传给视图,可以使用命名的正则表达式组来捕获URL 中的值并以关键字参数传递给视图

  就是给分组起个名字,通过使用关键字传参

url部分

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

# 有名分组
urlpatterns = [
    url("^articles/(?P<year>\d{4})/(?P<month>\d{2})/(?P<day>\d+)/$",views.article_day) 
# article_year(request,year=2000,month=12,day=12)
]

views部分

from django.shortcuts import render,HttpResponse,redirect
from django.urls import reverse

# 这里形参无论怎么放置都无所谓了
def article_day(request,month,day,year):
    return HttpResponse(year + "-" + month + "-" + day)

1.3 分发

   首先需要引入一个函数include(看urls.py下的注释),当你存在多个app的时候,彼此互不影响,各自从各自的app中去查找,好处是用于解耦

  include的背后是一种即插即用的思想

from django.urls import path,include

urlpatterns = [ 
        path('app01/',include("app01.urls")),
        path('app02/',include("app02.urls")),
]

1.4 反向解析,别名,命名空间

  url下的名字由于业务需求领导要求变更,这意味用到该路径的地方都需要更改,模板中用到这个名字的地方都需要改,一个项目中可能包含几十个模板文件,此时意味着维护起来代价相当高,此时则引入了反向解析这种语法,通过使用别名name来提高代码的灵活性。

案例一(不带参数的url):

url部分(不管怎么变动,我们只需更改这里的url部分即可,大大减少了工作量)

from django.urls import path
from app import views

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

视图部分

from django.shortcuts import render,HttpResponse,redirect
from django.urls import reverse   # 导入反向解析的一个函数

def login(request):
    if request.method == 'POST':
        user = request.POST.get('user')
        pwd = request.POST.get('pwd')
        if user=='bob' and pwd=='123':
            # 登录成功后直接跳转到首页index,即重定向,
            # 不过下面这样写就又被写死了,如果url中一改这里也需要改动
            # 现在也需要通过在url下使用别名
            # return redirect("index")   # 硬编码
            url = reverse("index")    # 反向解析
            print("url", url)    # url /index/
            return redirect(url)     # 这步就是重定向
    return render(request,"login.html")


def index(request):
    return HttpResponse('跳转成功')

模板部分(login.html)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
{#注意这里内容必须要放在form表单里,否则无法实现跳转#}
<form {% url 'log_in' %} method="post">
    姓名:<input type="text" name="user">
    密码:<input type="password" name="pwd">
    <input type="submit">
</form>
</body>
</html>

案例二(携带参数的url):

对于携带参数的url,这时候我们别名的语法如下:

urls.py

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

urlpatterns = [
    #...
    url(r'^articles/([0-9]{4})/$', views.year_archive, name='news-year-archive'),
    #...
]    

# 某一年nnnn对应的归档的URL是/articles/nnnn/

我们在模板中获取:

<a href="{% url 'news-year-archive' 2012 %}">2012 Archive</a>   # 注意模版语言的用法,注意参数的传递方法
<ul>
{% for yearvar in year_list %}
    <li><a href="{% url 'news-year-archive' yearvar %}">{{ yearvar }} Archive</a></li>
{% endfor %}
</ul>    
    

在试图函数中:

from django.urls import reverse
from django.http import HttpResponseRedirect

def redirect_to_year(request):
    # ...
    year = 2006
    return HttpResponseRedirect(reverse('news-year-archive', args=(year,)))

注:

  思路其实通过以不变(别名name)应万变

  在模板文件中:

    {% url ‘别名’ %}

  在视图函数中:    

    from django.urls import reverse
    url=reverse(别名)

名称空间(namespace)

  url别名name我们可以随意起名,但是如果在两个不同的app,在各自的urlconf中为某一条url取了相同的name,这就会带来麻烦。因此才引入了我们的名称空间

  URL命名空间可以保证反查到唯一的URL,即使不同的app使用相同的URL名称也不受影响

urls.py

from django.conf.urls import include, url

urlpatterns = [
    url(r'^author-polls/', include('polls.urls', namespace='author-polls')),   
    url(r'^publisher-polls/', include('polls.urls', namespace='publisher-polls')),   
] 

 2.静态文件配置问题

  这里提出这个静态文件配置,主要是由于我们url解析一些HTML标签的时候,当中存在jQuery或者bootstrap事件,这些都需要我们提前导入特定的功能包才能使用。当然使用网络提供的路径也可以使用,但是如果网络环境发生变化,极有可能导致我们的HTML某些事件无法加载,因此才提出了静态文件配制问题

  首先我们需要在manage.py同级目录下创建一个文件夹(一般就以static命名),然后将下载好的jQuery或者bootstrap配置文件放到该文件夹内

  接着我们需要在setting文件下进行相关路径配置:

STATIC_URL = '/static/'   #这个配置就相当于配置的别名,如果这里的名字修改了就按照这里的名字去导入
STATICFILES_DIRS = [
    os.path.join(BASE_DIR,"static")  # 找到static绝对路径
]

现在基本配置就完成了,如果在标签中使用,直接导入该相对路径即可

<link rel = "stysheet",href= "/static/index.css/"> 

<link rel="stylesheet" href="/static/bootstrap-3.3.7-dist/css/bootstrap.min.css">

 

推荐阅读