Haste makes waste

自强学堂-Django基础教程(1)-视图与URL

Posted on By lijun

无意中在网上发现了这个网站自强学堂(作者还是校友),上面整理的教程都很不错,正好适合刚学完DjangoBasic篇之后的扩展。本系列作为该自强学堂教程的笔记,为节省时间,与DjangoBasic部分重叠的话,会省略。


1. Django全貌

  • urls.py,网址入口,关联到对应的views.py中的一个函数,访问网址就对应一个函数。

  • views.py,处理用户发出的请求,从urls.py中对应过来, 通过渲染templates中的网页可以将显示内容,比如登陆后的用户名,用户请求的数据,输出到网页。

  • models.py,与数据库操作相关,存入或读取数据时用到这个,当然用不到数据库的时候 你可以不使用。

  • forms.py,表单,用户在浏览器上输入数据提交,对数据的验证工作以及输入框的生成等工作,当然你也可以不使用。

  • templates文件夹,views.py 中的函数渲染templates中的Html模板,得到动态内容的网页,当然可以用缓存来提高速度。

  • admin.py,后台,可以用很少量的代码就拥有一个强大的后台。

  • settings.py,Django 的设置,配置文件,比如 DEBUG 的开关,静态文件的位置等。

2. 常用Django相关命令

功能 命令 备注
新建一个 django project django-admin startproject project_name -
新建 app python manage.py startapp app_name -
创建数据库类SQL文件(.py) python manage.py makemigrations  
将类SQL文件应用到数据库 python manage.py migrate  
使用开发服务器 python manage.py runserver  
清空数据库 python manage.py flush 保留空表
创建超级管理员 python manage.py createsuperuser  
修改 用户密码 python manage.py changepassword username  
★导出数据 python manage.py dumpdata appname > appname.json  
★导入数据 python manage.py loaddata appname.json  
Django 项目环境终端 python manage.py shell  
★数据库命令行 python manage.py dbshell 能执行sql
更多命令 终端上输入 python manage.py 可以看到详细的列表  

3. Django 视图与网址

3.1 基础

  • 创建app
(myvenv) C:\Users\utane\OneDrive\pythonCode>django-admin startproject zqxtTest
(myvenv) C:\Users\utane\OneDrive\pythonCode>cd zqxtTest
(myvenv) C:\Users\utane\OneDrive\pythonCode\zqxtTest>python manage.py startapp learn
  • 将’learn’添加到setting.py的INSTALLED_APPS中

    新建的 app 如果不加到 INSTALL_APPS 中的话, django 就不能自动找到app中的模板文件(app-name/templates/下的文件)和静态文件(app-name/static/中的文件)

  • 定义视图函数 打开上述新建的app的views.py文件,添加新的视图:
from django.shortcuts import render
from django.http import HttpResponse

def index(request):
    return HttpResponse(u"欢迎光临")

现在还剩下一步,如何上讲述view与url关联。

  • view与url的关联-方法1 这种方法是之前DjangoBasic中使用的,也是通用性最好的方法-遇到特定的网址,就把解析的任务交给特定的app的url解析器。 urls.py文件中
from django.conf.urls import url,include  # 方法1
from django.contrib import admin

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^$', include('learn.urls'))
]

同时在learn中也需要添加urls.py文件

# 方法1
from django.conf.urls import url
from . import views

urlpatterns = [
   url(r'^$', views.index, name='index'),
]
  • view与url的关联-方法2和方法3 将其他app的views引入当前app中,然后指向该app的对应view,两类方法类似。
from django.conf.urls import url
from django.contrib import admin
# from learn import views  # 方法2
# from learn.views import index # 方法3

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    # url(r'^$',index,name="index") # 方法3
    # url(r'^$',views.index, name="index") # 方法2
]

3.2 进阶(获取get型request中的参数)

本示例,通过url传递参数过来,在view中进行计算,并将结果生成html相应结果,再返回给用户。

1. 采用 /add/?a=4&b=5&c=6 这样GET方法进行

  • views.py中添加对应的处理view
def add(request):
    a = request.GET.get('a',0)
    b = request.GET.get('b',0)
    x = request.GET.get('x',0)
    c = int(a) + int(b) + int(x)
    return HttpResponse(str(c))

request.GET.get('x',0),当无法取到x的时候,会有默认值0。

  • project的urls.py中,添加对应的url处理:如果遇到add开头的url,则将处理丢给learn这个app处理。
url(r'^add/*', include('learn.urls'),name='add')
  • learn的urls.py中,添加对应的url处理:
urlpatterns = [
   url(r'^$', views.add, name='add'),
]

上面的url是经过project的url处理过后的url,故已经没有了add

  • 访问http://127.0.0.1:8000/add/?a=4&b=5&x=50,html上显示59。如果访问http://127.0.0.1:8000/add/?a=4&b=5,也可以得到正确的结果。因为add view在处理的时候使用request.GET.get('x',0),当无法取到x的时候,会有默认值0。

总结:上面的处理方式,限定了url中的参数名称,如果将x修改为y的话,就无法取到值,得到错误结果了。

2. 采用 /add/4/5/50 这样的网址的方式

  • 将learn app的urls.py修改为如下:
urlpatterns = [
   url(r'^$', views.add, name='add'),
   url(r'^(\d+)/(\d+)/(\d+)/$', views.add2, name='add2'),
]

即网址中多了 (\d+), 正则表达式中 \d 代表一个数字,+ 代表一个或多个前面的字符,写在一起 \d+ 就是一个或多个数字,用括号括起来的意思是保存为一个子组,每一个子组将作为一个参数,被 views.py 中的对应视图函数接收。

  • views中添加对应的处理视图
def add2(request, a, b,x):
    c = int(a) + int(b) + int(x)
    return HttpResponse(str(c))
  • project中的urls.py不需要修改,因为已经定义了url(r'^add/*', include('learn.urls'),name='add'),只要url中出现add,就会将url的解析任务交给learn app的url解析器。

  • 访问http://127.0.0.1:8000/add/4/5/50/,可以得到正确的结果59.

3. (参考)URL中参数的传递和提取

参考:在 DjangoBasic-03-模板扩展-blog详情页面中也涉及到了参数的传递和提取,参考如下的代码:

  • 产生url的链接入口,在这里生成了一个pk参数,传递给了url生成器,url生成器用name为post_detail去标识。
<a href="[% url 'post_detail' pk=post.pk %}">[{ post.title }}</a>
  • url解析器,接收到name为post_detail的url请求,会生成一个url,按照格式r'^post/(?P<pk>[0-9]+)/$',另外这个也可以用来匹配,即用户直接输入url时匹配用。
urlpatterns = [
    url(r'^$', views.post_list, name='post_list'),
    url(r'^post/(?P<pk>[0-9]+)/$', views.post_detail, name='post_detail'),
]
  • 视图处理,接收上面子组(每一个子组将作为一个参数),与request一起传递给对应的视图post_detail。
def post_detail(request, pk):
    post = get_object_or_404(Post, pk=pk)
    return render(request, 'blog/post_detail.html', {'post': post})

4. Django URL name详解

4.1 通过html页面上的link进行计算

  • 修改project的urls.py,为进入index视图添加url解析,注意这里修改了url的解析方式,这样直接从project的url解析跳到app的视图。
from django.conf.urls import url
from django.contrib import admin
from learn.views import index,add2 # new!

urlpatterns = [
    url(r'^$', index, name='home'), # new!
    url(r'^admin/', admin.site.urls),

    url(r'^add/(\d+)/(\d+)/(\d+)/$', add2, name='add2'),
]

  • views中添加对应视图
def index(request):
    return render(request, 'home.html')
  • 添加html模板文件,在learn下新建templates文件夹,添加home.html
<!DOCTYPE html>
<html>
<head>
    <title>自强学堂</title>
</head>
<body>

<a href="/add/4/5/80">计算 4+5+80</a>

</body>
</html>
  • 这时运行http://localhost:8000,可以看到上述页面,点击链接可以得到正确的结果。

    通过点击链接,跳转到对应的url,在project的urls中进行解析,进入learn的解析器,进入对应的视图add2,进行计算,并返回response。

4.2 问题:url的显示需求有变更

如果我不想用add表示在url中,要改成jiafa呢,这样要修改对应的html模板和project的url解析器。 如果有大量的html文件,使用了上面的/add/4/5/80链接进行计算呢,那么所有的都需要修改。 有没有一种更加优雅有效的方式呢,让呈现出来的url与link无关呢。

  • 修改html中的link方式:<a href="[% url 'add2' 4 5 20 %}">link</a>

  • 将project中的url解析修改为 url(r'^jiafa/(\d+)/(\d+)/(\d+)/$', add2, name='add2'),

  • 再次点击上面的link,除了能正确计算结果外,还能呈现修改后的网址http://127.0.0.1:8000/jiafa/4/5/20/

可以看到,上面通过name匹配,生成了正确的url。

4.3 问题:如何让http://127.0.0.1:8000/add/4/5/20/继续可用呢?

如果某个用户收藏了旧的网址,那么将不能进行计算了?如果让旧的网址仍然可用呢?

  • 在 views.py 写一个跳转的函数,from django.http import HttpResponseRedirect
def old_add2_redirect(request,a,b,x):
    return HttpResponseRedirect(
        reverse('add2',args=(a,b,x))
    )

  • urls.py中,添加url(r'^add/(\d+)/(\d+)/(\d+)/$', old_add2_redirect),,即碰到这个url后,就进行redirect。

  • 再次输入http://127.0.0.1:8000/add/4/5/20/,将url跳转到http://127.0.0.1:8000/jiafa/4/5/20/,并能计算出结果。