Django Universal View Tutorial

Source: Internet
Author: User
In the worst case,
Web development is a tedious and monotonous task. So far, we've covered how Django can reduce the monotony of development at the level of models and templates, but web development is also experiencing this tiresome aspect of view.


Django's generic views can reduce these pains. It abstracts out some of the code and patterns that are commonly used in view development, so you can quickly write a common view of your data without having to write a lot of code. In fact, examples of almost all views in the previous chapters can be overridden with the help of a common view.


In the eighth chapter, we briefly introduce how to make the View more "universal". Looking back, we'll find some of the more common tasks, such as displaying a series of objects and writing a piece of code to display any object's content. The solution is to pass an extra parameter to the urlconf.


The Django built-in common view enables the following functions:


§ Complete Common simple tasks: Redirect to another page and render a specified template.


§ Displays the detailed content page for the list and for a specific object. The Event_list and Entry_list views mentioned in the 8th chapter are an example of a list view. A single
The event page is what we call the detailed content page.


§ Renders the date-based data of the year/month/day archive page, the associated details page, the latest page. Django
Weblogs (http://www.djangoproject.com/weblog/) is an archive of the year, month, and day that uses a common view architecture, like a typical newspaper archive.


§ Allows users to create, modify, and delete objects without authorization or authorization.


In summary, these views provide an easy-to-use interface for the tasks common to developers in their daily development.


Using a common view

The common view method is to create a configuration dictionary in the urlconf file and then use those dictionaries as the third member of the urlconf tuple.


For example, here is a urlconf that renders a static "about" page:

From django.conf.urls.defaults import *from django.views.generic.simple Import direct_to_templateurlpatterns = Patterns (', (' ^about/$ ', direct_to_template, {' template ': ' about.html '})

One look seems a bit weird, don't need to write code view! It is exactly the same as the example in the eighth chapter: the Direct_to_template view gets the relevant information needed to render the view from the parameters.


Because the universal view is a standard view function, we can reuse it in our own view. For example, we extend the about example to map a URL from/about/<whatever>/to a static render about/<whatever>.html. We first modify the URL configuration to the new view function:

From django.conf.urls.defaults import *from django.views.generic.simple import Direct_to_template**from Mysite.books.views Import about_pages**urlpatterns = Patterns (', ' ^about/$ ', direct_to_template, {' Template ': ' About.html '}), * * (' ^about/(w+)/$ ', about_pages), * *)

Next, we write the code for the About_pages view:

From django.http import http404from django.template import templatedoesnotexistfrom django.views.generic.simple Import Direct_to_templatedef about_pages (Request, page): Try:return direct_to_template (Request, template= "about/%s.html"% page) except Templatedoesnotexist:raise Http404 ()

Here we use direct_to_template like other functions. Because it returns a HttpResponse object, we just need to simply return it. There is a slightly more complicated place to deal with situations where templates are not found. We don't want a non-existent template to throw a server error, so we catch the tempaltedoesnotexist exception and return a 404 error.


Is there a security issue here?


Sharp-eyed readers may have noticed a possible security vulnerability: we use data from the client browser directly to construct the template name (template= "about/%s.html"%page). At first glance, this is like a classic directory traversal (directory
Traversal) attack (see Chapter 19th for details). Is that really true?


Not at all. Yes, a malicious page value can cause a directory to span, but even though the page is fetched from the requested URL, not all values are accepted. This is the key to URL configuration: We use the regular expression/w+ to match the page from the URL, and/w only accepts characters and numbers. Therefore, any malicious character (for example, here is the dot. and forward slash/) will be rejected at URL resolution and will not be passed to the view function at all.


Common view of objects

Direct_to_template is undoubtedly very useful, but the Django Universal view is most useful in rendering the data in the database. Because this app is so common, Django has a lot of built-in general-purpose views to help you easily generate lists and detail views of objects.


Let's take a look at one of the common Views: Object List view. We use Publisher in the fifth chapter to illustrate:

Class Publisher (models. Model): name = models. Charfield (maxlength=30) address = models. Charfield (maxlength=50) city = models. Charfield (maxlength=60) state_province = models. Charfield (maxlength=30) country = models. Charfield (maxlength=50) website = models. Urlfield () def __str__ (self): return self.nameclass meta:ordering = ["-name"]class Admin:pass

To create a list page for all the books, we use the following URL configuration:

From django.conf.urls.defaults import *from django.views.generic import list_detailfrom mysite.books.models Import Publisherpublisher_info = {"Queryset": Publisher.objects.all (),}urlpatterns = Patterns ("," (R ' ^publishers/$ ', list_ Detail.object_list, Publisher_info))

This is all the Python code that you want to write. Of course, we also need to write a template. We can clearly tell the Object_list view which template to use by including template_name in the additional parameter dictionary, but because Django uses the name of the object to derive one when it is not given a template. In this example, the derived template name will be "books/publisher_list.html", where the books part is the name of the app that defines the model,
The publisher section is lowercase for this model name.


This template will follow the context
The variables contained in the object_list are rendered, and this variable contains all the book objects. A very simple template looks like this:

{% extends "base.html"%} {% block content%}

That's all you have to do. To use the common view cool features only need to modify the parameter dictionary and pass it to the common view function. Appendix D is a complete reference for a common view; the next chapters in this chapter will cover some of the ways to customize and extend a common view.


Extending a common view

Without a doubt, using a common view can speed up development. However, in most projects, there is also a case where the general view does not meet the requirements. In fact, the most common problem for developers just contacting Django is how to use a common view to handle more situations.


Fortunately, in almost every case there is a corresponding way to simply extend the generic view to handle it. At this point, always use the following methods.


Create a friendly template context

You may have noticed that the Publisher list template in the example saves all the books in the variable object_list. This method works very well, but is not very friendly to the people who write the template: they have to understand what data they are dealing with now, for example, here is the book. It is better to use a variable name like Publisher_list, so that the value of the variable looks very clear.


We can easily modify the name of the Template_object_name parameter as follows:

Publisher_info = {"Queryset": Publisher.objects.all (), * * "template_object_name": "Publisher", **}urlpatterns = Patterns (', (R ' ^publishers/$ ', List_detail.object_list, Publisher_info))

Using useful template_object_name is always a good idea. The partner of your design template will thank you.


Add additional context

You often need to render more additional information than the generic view provides. For example, consider implementing all other publishers ' lists on each publisher page. The Object_detail general view provides the Publisher to the context, but there seems to be no way to get a list of all publishers in the template.


This is the workaround: All common views have an additional optional parameter, Extra_context. This parameter is a dictionary data type that contains additional objects to be added to the context of the template. So to provide all the publisher details to the view, we use such an info dictionary:

Publisher_info = {"Queryset": Publisher.objects.all (), "Template_object_name": "Publisher", * * "Extra_context": {"book _list ": Book.objects.all ()}**}

This puts a {{book_list}} variable into the context of the template. This method can be used to pass arbitrary data to the common view template, which is very convenient.


However, there is a very hidden bug, do not know you found it?


Now let's take a look at the problem with database queries in Extra_context. Because in this case, we put Publisher.objects.all () in the urlconf, it only executes once (when the urlconf is first loaded). When you add or remove publishers, you will find that the generic view does not reflect these modifications until you restart the Web server (for more information about when Queryset is cached and assigned, see the "Cache and query Set" section in Appendix C).


Note


This problem does not apply to the Queryset parameter of the common view. Because Django knows that some special queryset can never be cached, the common view does cache cleanup before rendering.


The solution to this problem is to use a callback (callback) instead of a variable in Extra_context. Any object that can be called, such as a function, is executed before each view render (not just once) after it is passed to Extra_context. You can define a function like this:

Def get_books (): Return Book.objects.all () Publisher_info = {"Queryset": Publisher.objects.all (), "template_object_ Name ":" publisher "," Extra_context ": **{" book_list ": get_books}**}

Or you can use another method that is not so clear but very short, in fact Publisher.objects.all itself can be called:

Publisher_info = {"Queryset": Publisher.objects.all (), "Template_object_name": "Publisher", "Extra_context": **{"book _list ": book.objects.all}**}

Note that there is no parenthesis behind the Book.objects.all, which means that this is a reference to a function and does not really call it (the generic view will call it when it is rendered).


Display a subset of objects

Now let's take a closer look at this queryset. Most common views have a Queryset parameter that tells the view to display a collection of objects (for an explanation of Queryset see chapter Fifth
The "Select Objects" section, see Appendix C for more information.


To give a simple example, we're going to sort the list of books by publication date, most recently in the top:

Book_info = {"Queryset": Book.objects.all (). order_by ("-publication_date"),}urlpatterns = Patterns ("," (R ' ^publishers /$ ', List_detail.object_list, Publisher_info), * * (R ' ^books/$ ', List_detail.object_list, Book_info), * *)

This is a fairly simple example, but it does explain the problem. Of course, you usually want to do more than reorder. If you want to present a list of all books published by a particular publisher, you can use the same technique:

**apress_books = {* * * * * "Queryset": Book.objects.filter (publisher__name= "Apress publishing"), * * * * "template_name": " books/apress_list.html "****}**urlpatterns = Patterns (", "(R ' ^publishers/$ ', list_detail.object_list, Publisher_info ), * * (R ' ^books/apress/$ ', List_detail.object_list, apress_books), * *)

Note that while using a filtered queryset, we also use a custom template name. If we don't do this, the generic view will use the previous template, which may not be the result we want.


It is also important to note that this is not the best way to deal with Publisher-related books. If we want to add another Publisher page, we have to write the URL configuration in the URL configuration, if there are many publishers, this method is unacceptable. In the following chapters we will solve this problem in the future.


Note


If you have a 404 error while requesting/books/apres/, check to make sure that the publisher in your database is named Apress
Publishing's record. The general view has a allow_empty parameter that can be used to handle the situation, see Appendix D for details.


Handling complex data filtering with function wrapping

Another common requirement is to filter the data objects by the keywords in the URL. In the previous we used to hard code the publisher name in the URL configuration to do this, but we want to use a view to display all the books of a publisher what to do? We can avoid writing a lot of manual code by wrapping the Object_list generic view. As a rule, let's start with the write URL configuration:

Urlpatterns = Patterns ("," (R ' ^publishers/$ ', List_detail.object_list, Publisher_info), * * (R ' ^books/(w+)/$ ', books_by _publisher), * *)

Next, we write Books_by_publisher this view: (The above code is in the wrong expression, before the ' W ' to add a backslash)

From django.http import http404from django.views.generic import list_detailfrom mysite.books.models import book, Publisherdef Books_by_publisher (Request, name): # Look up the publisher (and raise a 404 if it can ' t be found). Try:publishe R = Publisher.objects.get (name__iexact=name) except Publisher.DoesNotExist:raise http404# use the Object_list view for The heavy Lifting.return list_detail.object_list (Request,queryset = Book.objects.filter (Publisher=publisher), Template_name = "Books/books_by_publisher.html", Template_object_name = "Books", Extra_context = {"publisher": Publisher})

This is because the generic view is a Python function. Like other view functions, a common view accepts some parameters and returns a HttpResponse object. As a result, more can be done by wrapping a common view function.


Attention


Notice in the previous example that we passed the current publisher parameter in Extra_context. This is usually a good idea at the time of packaging; it lets the template know the previous layer of objects that are currently displayed.


Handling Additional work

Let's take a look at the last common pattern: do some extra work before and after calling the generic view.


Imagine that we have a last_accessed field in the author object, and we use this field to correct the last access time for author. Of course the general view Object_detail does not handle this problem, and we can easily write a custom view to update this field.


First, we need to set a pointer to the new custom view in the URL configuration:

From mysite.books.views Import author_detailurlpatterns = Patterns (", #...** (" R "^authors/(? p<author_id>d+)/$ ', author_detail), * *)

Next write the wrapper function:

Import datetimefrom mysite.books.models import authorfrom django.views.generic import List_detailfrom django.shortcuts Import Get_object_or_404def author_detail (Request, author_id): # Look up the author (and raise a 404 if she's not found) aut Hor = get_object_or_404 (Author, pk=author_id) # Record the last accessed dateauthor.last_accessed = Datetime.datetime.now () Author.save () # Show the detail pagereturn list_detail.object_detail (Request,queryset = Author.objects.all (), object_ id = author_id,)

Attention


This code doesn't really work unless you add the last_accessed field to your author model and create a books/author_detail.html template.


We can modify the return value of the common view in the same way. If we want to provide a plain text version of the author list for download, we can use this view:

def author_list_plaintext (Request): Response = list_detail.object_list (Request,queryset = Author.objects.all (), MimeType = "Text/plain", template_name = "Books/author_list.txt") response["content-disposition"] = "attachment; Filename=authors.txt "return response

This method works because the HttpResponse object returned by the generic view can set the HTTP header like a dictionary. To say the content-disposition, the implication is to tell the browser to download and save the page instead of displaying it in the browser.

The above is the Django general view to explain the content, more relevant content please pay attention to topic.alibabacloud.com (www.php.cn)!

  • Contact Us

    The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

    If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.