Django开发入门——视图和URL配置

第一份视图“hello world”
在使用命令django-admin.py startproject DjangoPro创建的项目DjangoPro的文件夹中创建一个叫view.py的空文件,这个模块包含视图。文件名与服务无关。

from django.http import HttpResponse

def hello(request):
    return HttpResponse('Hello World')

每个视图函数至少要有一个参数,通常为request,这是一个触发这个视图函数、包含当前Web请求的信息的对象,是类django.http.HttpRequest的一个实例虽然不用它做任何事情,然而它必须是这个视图函数的第一个参数。

总结:一个视图函数就是Python的一个函数。这个函数的第一个参数类型是HttpRequest;它返回一个HttpRequest实例,响应可以是一张网页内容,一个重定向,一个404错误等。
第一个URL
如果现在运行你的服务还将看到的是欢迎界面,那是因为这个项目对hello视图海一无所知。我们需要通过一个详细描述的URL来显示的告诉项目并激活这个视图函数。为了绑定视图函数和URL,使用
URLconf

URLconf就像是Django所制成的网站的目录。它的本质是URL模式以及要为该URL模式调用的视图函数之间的映射表。就是用这种方式告诉每个URL该调用哪段代码。
URL的配置文件就是urls.py这个文件当中有许多注释,如果想使用注释的功能只需要曲调注释即可。

from django.contrib import admin
from django.conf.urls import url
urlpatterns = [
    url(r'^admin/', admin.site.urls),
]

url函数将返回匹配到的结果并保存到urlpatterns变量中。该变量定义了URL以及用处理这些URL的代码之间的映射关系,Django期望能从ROOT_URLCONF模块中找到它;一个url()对象包括正则表达式,视图函数,名称name。默认情况下URLconf所有内容都被注释起来了,如果URLconf为空,Django会认定你才创建好新项目,因此会显示欢迎界面。

在URLconf中加入URL和view如下:

from django.contrib import admin
from django.conf.urls import url

from django.views import hello

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

从views模块中倒入事先定义的hello视图,接下来,加上url(r’^hello/ ′ , h e l l o ) , , 这 行 被 称 为 U R L p a t t e r n , 他 是 一 个 P y t h o n 的 元 组 , 元 组 中 的 第 一 个 元 素 是 模 式 匹 配 字 符 串 ; 第 二 个 元 素 是 那 个 模 式 将 使 用 的 视 图 函 数 ; 其 实 就 是 告 诉 D j a n g o 所 有 指 向 / h e l l o / 的 请 求 都 应 由 h e l l o 这 个 视 图 函 数 来 处 理 。 ∗ ∗ 关 于 u r l p a t t e r n s 的 语 法 ∗ ∗ D j a n g o 在 检 查 U R L 模 式 之 前 , 移 除 每 一 个 申 请 的 U R L 开 头 的 斜 杠 / 。 所 以 为 / h e l l o / 写 模 式 开 头 不 用 包 含 / 。 如 果 申 请 访 问 的 / h e l l o / 没 有 尾 部 的 / , 那 么 默 认 的 任 何 不 匹 配 或 尾 部 无 / 的 U R L 都 会 被 重 定 向 至 尾 部 包 含 / 的 相 同 字 眼 的 U R L 这 是 受 配 置 文 件 中 的 A P P E N D S L A S H 控 制 的 , 大 多 数 U R L 模 式 会 以 开 始 , 以 ', hello),,这行被称为URLpattern,他是一个Python的元组,元组中的第一个元素是模式匹配字符串;第二个元素是那个模式将使用的视图函数;其实就是告诉Django所有指向/hello/的请求都应由hello这个视图函数来处理。 **关于urlpatterns的语法** Django在检查URL模式之前,移除每一个申请的URL开头的斜杠/。所以为/hello/写模式开头不用包含/。如果 申请访问的/hello/没有尾部的/,那么默认的任何不匹配或尾部无/的URL都会被重定向至尾部包含/的相同字眼的URL这是受配置文件中的APPEND_SLASH控制的,大多数URL模式会以^开始,以 ,hello),URLpatternPython使Django/hello/hellourlpatternsDjangoURLURL//hello//访/hello///URL/URLAPPENDSLASHURL结尾
运行结果
这里写图片描述
Django是怎么处理请求的?
1.进来的请求转入/hello/
2.Django通过setting.py文件里的ROOT_URLCONF配置来决定根URLCONF,文件里ROOT_URLCONF = 'DjangoPro.urls’说明需要找到DjangoPro.urls文件。
3.Django在URLCONF中的所有URL模式中,查找第一个匹配/hello/的条目。
4.如果找到匹配,将调用相应的视图函数
5.视图函数返回一个HttpResponse
6.Django转换HttpRespnse为一个合适的HTTP response,以Web page显示出来。
第二个视图——显示动态内容
不像第一个视图,每次进入页面都显示的是hello World,这个视图将会显示时间,即你每次运行服务的时间将会显示在页面。
和上一个视图一样,先来定义视图函数:views.py

from django.http import HttpResponse
from datetime import datetime

def now_time(request):
    time=datetime.now()
    html='<h1>It is now %s</h1>' %(time)
    return HttpResponse(html)

在来制定URL和视图函数utls.py

from django.contrib import admin
from django.conf.urls import url

from DjangoPro.views import hello,now_time

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^hello/', hello),
    url(r'^time/', now_time),
]

运行结果:

#It is now 2018-08-06 08:17:42.367614
**Django时区:**显示时间与日期可能和实际相差几个小时。这是因为Django是有时区意识的,并且默认时区为America/Chicago,如果在别的时区,需要在settings.py文件中更改这个值。
URL配置和松耦合
Django和URL配置背后的原则:松耦合原则,松耦合是一个重要的保证互换性的软件开发方法。在Django中URL和视图函数之间就是松耦合的。即决定URL返回哪个视图函数和实现这个视图函数的功能是在两个不同的地方,所以两个模块互不影响。


第三个视图——动态URL
一家在线书店会为每一本书提供一个URL,如/book/23、/book/432/。
创建第三个视图来显示当前时间加上时间偏差量的时间如:/time/plus/2、/time/plus/6.我们可以使用通配符来处理任意的时差。

  • 正则表达式非命名组,通过位置参数传递给视图
url(r'^time/plus/(\d{1,2})', hours_ahead),

视图views.py

from django.http import HttpResponse, Http404
import datetime

#offset是从URL里面体悟出来的参数,提取的是(\d{1,2})中匹配到的字符串
def hours_ahead(request,offset):
    #捕捉错误,报错404,offset只匹配一个或两个数字
    try:
        #将它转换成整形,因为后面的datetime.timedelta()
        #函数要求hours必须为整形,
        offset=int(offset)
    except ValueError:
        raise Http404()

    dt=datetime.datetime.now() + datetime.timedelta(hours=offset)
    html="<h1>In %s hours,it will be %s.</h1>" %(offset,dt)
    return HttpResponse(html)

若要从url中捕获一个值,须要在他周围设置一对圆括号。

  • 正则表达式命名组,通过关键字参数传递给视图,本例关键字参数为plus
    url(r’^time/(?p/(\d{1,2})),hours_ahead)’

URL的反向解析

  • 如果在视图,模版中使用硬编码的链接,在urlconf发生改变时,维护是一件非常麻烦的。
  • 解决:在做链接时,通过指向urlconf的名称,动态生成链接地址
  • 视图:使用django.cure,utlresolvers,reserver()函数
  • 模版:使用url标签

高级视图和URL配置

使用命名组
可以使用命名正则表达式来捕获URL,并且将其作为关键字传给视图。

url(r'^article/(?P<year>\d{4})/(?P<month>\d{2})/$',date_article),
def date_article(request,year,month):

    html='<h1>it is %s %s</h1>' %(month,year)
    return HttpResponse(html)

如果不带命名组,请求/article/2018/12/将会等同于

date_article(request,'2018','12')

戴上命名组

date_article(request,year='2018',month='12')

使用命名组可以让你的URLconfs更清晰,减少搞混参数次序的潜在DUG,可读性增强,但是会显得冗余。
理解匹配/分组算法
URLconf解释器有关正则表达式中命名组和非命名组所遵循的算法。

  • 如果有命名组,Django会忽略非命名组而直接使用命名组;
  • 否则,Django会把所有非命名组以位置参数的形式传递;
  • 在以上两种情况,Django同时会以关键字参数的方式传递一些额外参数。
    包含其他URLconf
url(r'^weblog/', include('mysite.blog.urls')),
    url(r'^photos/', include('mysite.photos.urls')),

捕获的参数如何和include()协同工作

from django.conf.urls.defaults import *
urlpatterns = patterns('',
(r'^(?P<username>\w+)/blog/', include('foo.urls.blog')),
)
# foo/urls/blog.py
from django.conf.urls.defaults import *
urlpatterns = patterns('',
(r'^$', 'foo.views.blog_index'),
(r'^archive/$', 'foo.views.blog_archive'),
)

被捕获的username变量将传递给被包含的URLconf,进而传递给哪个URLconf中的每一个视图函数。不管那些行对是的视图函数是否需要这个参数,所以只有你需要的时候哪个被传递的参数才有用。
额外的URLconf如何和include()协同工作

# urls.py
from django.conf.urls.defaults import *
urlpatterns = patterns('',
(r'^blog/', include('inner'), {'blogid': 3}),
)
# inner.py
from django.conf.urls.defaults import *
urlpatterns = patterns('',
(r'^archive/$', 'mysite.views.archive'),
(r'^about/$', 'mysite.views.about'),
(r'^rss/$', 'mysite.views.rss'),


捕获的参数一样,全部传递,用时有效

通用视图

最初Django的视图都是用函数实现的,后来开发出一些通用的视图函数,以取代某些重复使用的代码。通用视图就像是一些封装好的处理器,使用他们的时候只需要给出特定参数即可。
通用视图运行原理
因为URLConf仍然使用“给一个可调用对象HttpRequest,并期待返回一个HttpResponse“这样的逻辑,所类视图必须设计一个可调用窗口。这就是as_view()方法。它接受request并实例化类视图,接着调用dispatch()方法。这个方法会依据request的请求类型再去调用实例的对应同名当法,并把request传过去,如果没有对应的方法就引发一个异常,值得注意的是这个方法的返回值和普通的视图函数的返回值没有什么不同。
Django提供了一系列县城的类视图,他们都继承一个View基类django.views.generic.base,在这个基类里实现了与URLS的接口as_view、请求方法匹配dispatch和一些其他基本的功能。
Dajngo内建通用视图可以实现的功能:

  • 完成常用的简单任务:重定向到另一个页面以及渲染另一个模板;
  • 显示列表和某个特定对象的详细内容页面;
  • 呈现基于日期的数据的年/月/日归当页面,关联的详情页面,最新页面。
    使用通用视图
    使用通用视图的方法时在URLconf文件中创建配置字典,惹阿比后把这些字典作为URLconf元组的第三个成员。
from django.views.generic.base import TemplateView
urlpatterns = [
		url(r'^about/$',TemplateView.as_view(template_name='about.html')),
    ]

about.html

<h1>Hello,World</h1>

这里写图片描述
根本没用视图函数,是不是很神奇!
子类化通用视图
子类化通用视图并重写必要属性;

from django.views.generic import TemplateView

class AboutView(TemplateView):
    template_name = 'about.html'
    #get_context_data方法只接受关键字参数,这个参数来自于
    #URLconf的第三个参数
    def get_context_data(self, **kwargs):
        context=super(AboutView, self).get_context_data(**kwargs)

        return context
#urls.py
from DjangoPro.views import AboutView
urlpatterns = [
    url(r'^about/$',AboutView.as_view()),
    ]

对象的通用视图
通用视图的优势通常体现在对数据库访问上。比如这个显示对象列表的视图,完全省去了对数据库的操作:

from django.views.generic import ListView
from books.models import Publisher

class PublisherList(ListView):
    template_name = 'ListView.html'
    model = Publisher
#urls.py
from DjangoPro.views import PublisherList
urlpatterns = [

    url(r'^publishers/$',PublisherList.as_view()),
#ListView.html
<ul>
    {% for publisher in object_list %}

        <li>{{ publisher.name }}</li>
    {% endfor %}
</ul>

这里写图片描述
编写友好的模板上下文
上例中ListView.html模版中时用的context变量名为‘object_list’。这是一个通用名,即ListView视图总会使用的一个名字;当你访问一个视图模型的时候,视图还会自动用小写的模型名+_list的格式命名一个相同的context取渲染模板,建议指定模版名字。
在通用视图上的context_object_name

class PublisherList(ListView):
    template_name = 'publisher_list.html' #指定模板
    model = Publisher #指定数据来源
    context_object_name = 'Mypublisher_list' #指定模板变量名,默认objects_list

添加额外上下文
多数时候,你值时需要展示一些额外的信息而不是提供一些通用视图。比如考虑到每个publisher页面上的图书列表的展示。

from django.views.generic import DetailView
from books.models import Publisher,Book

class PublisherDetail(DetailView):
    model = Publisher

    template_name = 'publisher_list.html'
    context_object_name = 'Mypublisher_list'

    def get_context_data(self, **kwargs):

        context=super(PublisherDetail, self).get_context_data(**kwargs)
        context['book_list']=Book.objects.all()
        return context

查看对象的子集
model参数指定了视图在哪个数据库模型之上进行操作,这适用于所有的需要操作一个单独的对象或者一个对象集合的通用视图。同样也可以用queryset参数来指定一个对象列表,

queryset = Book.objects.all()等于model = Publisher

然而通过queryset来定义一个过滤的对象列表。可以更加详细的了解哪些对象将会被显示。
显示某个出版商的所有图书列表:

#views.py

from django.views.generic import ListView
from books.models import Book

class AcmeBookList(ListView):

    queryset = Book.objects.filter(publisher__name='Apress')
    context_object_name = 'book_list'
    template_name = 'acme_list.html'
#acme_list.html

<ul>
{% for book in book_list %}
    <li>{{ book.title }}</li>
{% endfor %}
</ul>

动态过滤
在给定的列表页面中根据URL种的关键字来过滤对象。将之前的出版社显示书籍重写,使它能够对应不同的出版社进行显示。
ListView有一个get_queryset()方法,在之前它值是返回一个queryset属性值,现在可以添加逻辑。
这种方式工作的关键点,在于当类视图内调用的时候,各种有用的对象被储存在self上;同request()一样,其中包含从URLconf中获取到的位置参数和基于名字的参数。

#urls.py
from DjangoPro.views import PublisherBookList
urlpatterns = [
    url(r'^books/(\w+)/$',PublisherBookList.as_view()),
    ]
#DjangoPro.views.py

from django.shortcuts import get_object_or_404
from django.views.generic import ListView
from books.models import Book,Publisher


class PublisherBookList(ListView):

    template_name = 'books_by_publisher.html'
    context_object_name = 'Mypublisher_book_list'
    def get_queryset(self):
        # get_object_or_404默认的调用django的get方法,如果查询的对象不存在,则抛出一个404异常
        self.publisher=get_object_or_404(Publisher,name=self.args[0])
        return Book.objects.filter(publisher=self.publisher)

执行额外的工作
需要考虑最后的共同模式在通用视图之前或者之后会引起的额外开销。
在Author对象上有一个last_accessed字段,这个字段用来u跟踪某人最后一次查看了这个作者的时间:

#books.models.py

class Author(models.Model):
    """关于作者的类"""

    first_name=models.CharField(max_length=30)
    last_name=models.CharField(max_length=40)
    #数据类型为规定的邮箱的类型
    email=models.EmailField('e-mail', blank=True)
    last_accessed=models.DateTimeField()
    
    
    def __str__(self):
        return u'%s %s' %(self.first_name,self.last_name)
from django.views.generic import DetailView
from django.utils import timezone
from books.models import Author


class AuthorDetailView(DetailView):
    queryset = Author.objects.all()

    def get_object(self, queryset=None):
        object=super(AuthorDetailView, self).get_object()


        object.last_accessed=timezone.now()
        object.save()

        return object
#urls.py
from DjangoPro.views import AuthorDetailView

urlpatterns = [
    url(r'^author/(?P<pk>[0-9]+)/$',AuthorDetailView.as_view(),name='author_detail'),]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值