Effective Django. Part 2

Original author: Nathan Yergler
  • Transfer
  • Tutorial

Continued translation of Django articles from effectivedjango.com . I came across this site while studying this framework. The information posted on this resource seemed useful to me, but since I could not find a translation into Russian anywhere, I decided to do this good deed myself. This article series, I think, will be useful to web developers who take only the first steps in learning Django.



Table of contents


Chapter 3. Writing a Presentation


3.1. Presentation Basics


Django views receive an HTTP request and return an HTTP response to the user :

Any Python object called can be a view. The only tough and necessary requirement is that the called Python object must accept the request object as the first argument (usually this parameter is called - request). This means that the minimal representation will be very simple:

from django.http import HttpResponse
def hello_world(request):
    return HttpResponse("Hello, World")

Of course, like most other frameworks, Django allows you to pass arguments to a view through a URL. We will talk about this when we build our application.

3.2. General Views and Class Views


  • general representations always provide some basic functionality: visualize a template, redirect, create, edit a model, etc.
  • Beginning with version 1.3, for general views, Django has introduced class views (CBV);
  • general concepts and CBVs provide a higher level of abstraction and composability;
  • in addition, they hide a lot of complexity, which otherwise could confuse newcomers;
  • fortunately, in the newer versions of Django, the documentation for all this has become much better.

Django 1.3 introduces the class views that we will focus on in this chapter. Class Views, or CBVs, can eliminate a lot of boilerplate code from your views, especially from views for editing anything where you want to take various actions for GET and POST requests. Presentation classes will give you the opportunity to assemble functionality in parts. The disadvantage is that all this power entails some additional complication.

3.3. Class Views (CBV)


The smallest view implemented as CBV is a descendant of the Viewdoc class and implements the supported HTTP methods. Below is a very small representation of “Hello, World”, which we wrote earlier, but made as a class representation:

from django.http import HttpResponse
from django.views.generic import View
class MyView(View):
      def get(self, request, *args, **kwargs):
      	  return HttpResponse("Hello, World")

In the class view, the HTTP method names are mapped to class methods. In our case, we defined a handler for the GET request using the class method get. Just as when implemented by a function, this method takes the request object as the first parameter and returns an HTTP response.

Note: Valid signatures
You may notice several additional arguments in the function signature, compared with the representation we wrote earlier, in particular*argsand**kwargs. CBVs were first created to make Django's “general” views more flexible. They were intended to be used in a variety of different contexts, with potentially different arguments extracted from the URL. Having been writing class representations for the past year, I continue to write them using valid signatures, and each time it turns out to be useful in unexpected situations.

3.4. Contact List Output


We will start with a view that displays a list of contacts from the database.

The basic implementation of the view is very short. We can write it in just a few lines. To do this, in the file of views.pyour application, contactstype the following code:

from django.views.generic import ListView
from contacts.models import Contact
class ListContactView(ListView):
      model = Contact

The ListViewdoc class from which we inherited the view is itself composed of several impurities that implement some behavior. This gives us great power with a small amount of code. In our case, we specified the model ( model = Contact), which will cause this view to list all the model’s contacts Contactfrom our database.

3.5. Defining URLs


The URL configuration (URLconf) tells Django how to find your Python code at the request address. Django looks at the URL configuration that is defined in the urlpatternsfile variable urls.py.

Let's add a addressbook/urls.pyURL template to our file for our view, which displays a list of contacts:

from django.conf.urls import patterns, include, url
import contacts.views
urlpatterns = patterns('',
    url(r'^$', contacts.views.ListContactView.as_view(),
        name='contacts-list',),
)

  • using a function is url()not strictly required, but I prefer to use it: when you start adding more information to URL patterns, it will allow you to use named parameters, making the code cleaner;
  • The first parameter accepted by the function url()is a regular expression. Pay attention to the trailing character $; Why do you think it is important?
  • the second parameter indicates the called view. This can be either a directly called object (manually imported) or a line describing it. If this is a string, then if the URL pattern matches the query string, Django will import the necessary module (to the last point) and call the last segment of the line (after the last point);
  • Note that when we use a class representation, we are obligated to use a real object, not a string describing this object. We must do this because we are invoking a class method as_view(). This method returns a wrapper over our class that Django URL Manager can call;
  • the name given to the URL pattern will allow you to do a reverse search ;
  • The URL name is useful when linking from one view to another, or when redirecting, since you can control the structure of URLs from one place.

While a variable urlpatternsneeds to be defined, Django also allows you to define several other values ​​( variables ) for exceptional situations. These values include handler403, handler404, and handler500which indicate the Django, which view to use in the case of an HTTP error. See Django 's URL configuration documentation for more details .

Note: Import URL configuration errors
Django loads the URL configuration very early at startup and tries to import the modules found inside. If at least one of the import operations fails, the error message may be a little incomprehensible. If your project crashes due to an import error, try importing the URL configuration in an interactive shell. This allows, in most cases, to determine where problems have occurred.

3.6. Create Template


Now that we’ve defined the URL for our contact list view, we can try it out. Django includes a server suitable for development purposes, which you can use to test your project:

(venv:tutorial)$ python ./manage.py runserver 0.0.0.0:8080
Validating models...
0 errors found
November 04, 2014 - 15:25:05
Django version 1.6.7, using settings 'addressbook.settings'
Starting development server at http://0.0.0.0:8080/
Quit the server with CONTROL-C.

If you visit http: // localhost: 8080 / in your browser, you still get an errorTemplateDoesNotExists
Translator's note:
localhost specify if you are launching the browser from the same host where the server is running. If your server is running on a different host (like mine) - localhostspecify the IP address of this host instead (in my case, this 192.168.1.51).


Most common Django views (this applies ListViewto us) have a predefined name for the template they expect to find. We can see in this error message that the view was expecting to find a template file with a name contact_list.htmlthat was obtained from the model name. Let's create such a template.

By default, Django searches for patterns in applications, as well as in the directories specified in settings.TEMPLATE_DIRS. General views expect templates to be found in the application directory (in this case, the directory contacts), and the file name will contain the model name (in this case, the expected file name:contact_list.html) This comes in handy when you develop applications for reuse: the user of your application can create their own templates that will override the default templates, and they will be stored in a directory directly associated with the application.

Translator's note:
Django expects the template to be found atимя_приложения/templates/имя_приложения/имя_шаблона

For our purposes, however, we do not need an extra layer of directory structures, so we will define the template explicitly using the property of template_nameour class representation. Let's add one line to views.py:

from django.views.generic import ListView
from contacts.models import Contact
class ListContactView(ListView):
      model = Contact
      template_name = 'contact_list.html'

Create a contactssubdirectory in the directory (this is the directory with the application) templates, and create a template file in it contact_list.html:

Contacts

    {% for contact in object_list %}
  • {{ contact }}
  • {% endfor %}

If you re-open (or refresh) the browser at http: // localhost: 8080 / , you should see at least one contact that we created earlier through an interactive shell.



3.7. Create contacts


Adding information to the database through an interactive shell takes too much time, so let's create a view to add new contacts.

As with contact list output, we’ll use one of Django’s general views. In the file views.pywe will add a few lines:

from django.core.urlresolvers import reverse
from django.views.generic import ListView
from django.views.generic import CreateView
from contacts.models import Contact
class ListContactView(ListView):
	model = Contact
	template_name = 'contact_list.html'
class CreateContactView(CreateView):
	model = Contact
	template_name = 'edit_contact.html'
	def get_success_url(self):
		return reverse('contacts-list')

Translator's note:
If you are using Django version> = 1.7, you can add an CreateContactViewadditional field to the class :

    fields = ['first_name', 'last_name', 'email']

This is not necessary, but since version Django 1.7, the non-use of this field in classes with automatic generation of forms has been deprecated (you will be informed about this during tests). If you do not specify it, then all fields will be used in the editing form, but this behavior will be deleted from Django 1.8.

Most of the common views that work with forms have the concept of a “good URL”: the URL that the user is redirected to after the form has been successfully processed. All submissions that process forms adhere to the POST-redirect-GET practice for accepting changes, so updating the final page does not re-submit the form. You can implement this concept as a property of the class, or redefine the method get_success_url(), as we did. In our case, we use the function reverseto calculate the contact list URL.

Note: Context variables in class views The
set of variables available in a template when it is displayed is called Context . Context is a combination of data from a view and information from context processors .
When you use the built-in general views, it is not clear what variables are available in the context. Over time you will discover that their names (provided by the general concepts in the context of the template) are fairly consistent -form,objectandobject_listare often used - even though it will not help you in the beginning. Fortunately, the documentation on this has become very prettier since Django 1.5.
In class views, the methodget_context_data()used to add information to the context. If you overload this method, you will need to enable **kwargsand call the superclass.

The add contact template will be a little more complicated than the contact list template, but not too much. Our template contacts/templates/edit_contact.htmlwill look something like this:

Add Contact

{% csrf_token %}
    {{ form.as_ul }}
back to list

A few new pieces to note:
  • formfrom context - this is the Django Form for our model. Since we did not specify any of our own, Django created one for us. How caring;
  • if we just wrote {{ form }}we would get table rows; but we add .as_ulthat forces the input fields to be displayed as elements of an unordered list. Try using it instead .as_pand see what happens;
  • when we display a form ( e.g.: automatically generated ), only our fields are displayed, but the или кнопка отправки />, так что мы добавим их в шаблон сами;
    template tag that does not frame the form {% csrf_token %}inserts a hidden field by which Django determines that the request came from your project and that it is not a cross-site request forgery ( CSRF ). Try not to include it in the template: you will still have access to the page, but as soon as you try to submit the form, you will get an error;
    we use a template tag urlto generate a link back to the contact list. Note that contacts-listthis is the name of our view, which we specified in the URL settings. Using urlinstead of the full path, we don’t have to worry about broken links. urlin the template is equivalentreverse in Python code.

Also popular now: