LXF108:Django
Steve (обсуждение | вклад) (→Финальные штрихи) |
Henryford (обсуждение | вклад) |
||
Строка 1: | Строка 1: | ||
− | {{ | + | Cycle {{/ Django}} |
− | == | + | == == The final touches |
− | : '' | + | :''PART 4 Lessons Django comes to an end, there comes a time for exams - if not for you, for applications for sure. '''Nikita Shultays''' (http://shultais.ru) will deal with testing and go over other features of this framework.'' |
− | + | Newsline is ready - but whether it will meet expectations | |
− | + | users? The answer to this question can be tested, the best - in the real world, but some | |
− | + | basic things you can check at the stage of development [http://www.thesiswritingservice.com/ thesis writers]. If you | |
− | + | time to look at the tutorial [[LXF108: Rails | Rails]], you already know about the methodology of TDD. However, we'll go the other way, and will test | |
− | + | application not to write, and after. | |
− | + | The point is - a serious and complex, as we need to consider | |
− | + | interaction with the database, a compilation of templates, processes and GET- | |
− | POST- | + | POST-requests and other system components: a failure in any of |
− | + | They can cause disrupt the entire site. Go to this problem | |
− | + | can be approached from two sides: | |
− | * | + | * Testing in your browser. We are talking about programs Twill (http://twill.idyll.org) and Selenium (http://selenium.openqa.org): they "remember" the sequence of your actions for each page, and then reproduce it on demand. For example, you can type in form fields obviously incorrect data, get the expected error and repeat the test whenever a major change in the code of your application. |
− | * | + | * Testing on the server. And then Django does not leave us to fend for themselves, offering just two options: doctest (tested via documentation) and unittest (unit testing), plus a special client to send a GET-and POST-requests. |
− | + | If you've been programming in Python, then you probably | |
− | + | will be closer doctest, and migrants from the Java world have more in | |
− | + | taste unittest. There are no restrictions on their use is imposed: you can choose one system or use both at once. We also discuss the doctest. | |
− | === | + | === Document it! === |
− | + | Line documentation in Python - it is plain text that you place | |
− | + | after the definition of a function or class directly in the source | |
− | + | code. It also provides content for the attribute __doc__. As | |
− | + | Typically, it is placed in triple quotes ("""), that allows you to enter | |
− | + | complex structures with line breaks, indentation, the same quotes and ... tests. That's what we use. | |
− | + | Tests can be found in the model files (models.py) - to check the latest - and in special files tests.py, located | |
− | + | in the application directory. For example, create a news / tests.py | |
− | + | to the following: | |
<source lang="python" line="GESHI_NORMAL_LINE_NUMBERS"> | <source lang="python" line="GESHI_NORMAL_LINE_NUMBERS"> | ||
− | # -*- | + | # -*- Coding: utf-8 -*- |
− | """ | + | "" " |
− | >>> | + | >>> From news.models import News |
− | >>> | + | >>> From datetime import datetime |
− | >>> | + | >>> News = News (title = "Title", description = "Description", pub_date = datetime.now (), text = "text") |
− | >>> | + | >>> News.save () |
− | >>> | + | >>> News = News.objects.get (pk = 1) |
− | >>> | + | >>> Print news.title.encode ('utf-8') |
− | + | Title | |
− | """ | + | "" " |
− | </ | + | </ Source> |
− | + | In line 1 encoding, but since the third is very | |
− | + | test. Note that each line begins with three characters "more" (>>>), in the interactive mode, Python. Line 10 | |
− | + | These characters do not, because it contains the expected output | |
− | print | + | print from line 9. |
− | [[ | + | [[Image: LXF108 85 1.png | thumb | 200px | Fig. 1. Test passed successfully!]] |
− | + | Before running the test, you need to add in settings.py | |
− | + | line | |
− | + | TEST_DATABASE_CHARSET = "UTF8" | |
− | + | to file encoding and the database match. Before performing the test, Django will create a special auxiliary databases, so | |
− | + | the user specified in settings.DATABASE_USER, must have | |
− | + | the appropriate authority. To begin testing, type: | |
− | + | python manage.py test news | |
− | + | after which you will see something that shows | |
− | + | Fig. 1. | |
− | + | Messages similar to appear during the creation of tables | |
− | + | when you first install, but now it happens in a test database. In | |
− | + | end shows the number of tests performed, their results and | |
− | + | notified about the destruction of a test material. We checked our | |
− | + | application (news), but, as you know, Django provides a few | |
− | + | own applications and representations (eg, "admin") - | |
− | + | and they also supplied with their tests. To perform them all, | |
− | + | must enter the command: | |
− | + | python manage.py test | |
− | + | adding previously in the main file the following URL-card | |
− | + | lines: | |
− | <source lang="python">urlpatterns += patterns('django.contrib.auth.views', | + | <source lang="python"> urlpatterns + = patterns ('django.contrib.auth.views', |
− | url(r'^auth/password_reset/$','password_reset'), | + | url (r '^ auth / password_reset /$',' password_reset'), |
− | )</ | + | ) </ Source> |
− | + | Here we include one of the built-in views, designed to recover your password. This is necessary since | |
− | + | testing of the entire project is being accessed at the specified URL, | |
− | + | and if the view is not specified, the test will fail. By the way, you | |
− | + | also can try password_reset in (Fig. 2). | |
− | [[ | + | [[Image: LXF108 85 2.png | frame | center | Fig. 2. Forgot your password? This problem Django!]] |
− | === | + | === === Network Simulator |
− | + | The number of tests has already reached six, but in addition to creating and | |
− | + | retrieve objects from the database, we need to test the response to | |
− | GET- | + | GET-and POST-requests. As you know, for these purposes there |
− | + | special client: it emulates the query and returns the variables that are passed to the template for this URL. Add the | |
− | + | tests.py file after line 10 the following code: | |
<source lang="python" line="GESHI_NORMAL_LINE_NUMBERS" line start="11"> | <source lang="python" line="GESHI_NORMAL_LINE_NUMBERS" line start="11"> | ||
− | >>> | + | >>> From django.contrib.auth.models import User |
− | >>> | + | >>> User = User.objects.create_user ('django_guru', 'user@example.com', 'password') |
− | >>> | + | >>> User.save () |
− | >>> | + | >>> From django.test.client import Client |
− | >>> | + | >>> C = Client () |
− | >>> | + | >>> C.login (username = 'django_guru', password = "password") |
True | True | ||
− | >>> | + | >>> Response = c.get ('/ news / 1 /') |
− | >>> | + | >>> Response.status_code |
200 | 200 | ||
− | >>> | + | >>> Print response.context [0] ['user']. Username |
django_guru | django_guru | ||
− | >>> | + | >>> Response = c.post ('/ news / 1 /',{' username': "testuser", 'text':»»}) |
− | >>> | + | >>> Response.status_code |
200 | 200 | ||
− | >>> | + | >>> Response = c.post ('/ news / 1 /',{' username': "testuser", 'text': »Comment text»}) |
− | >>> | + | >>> Response.status_code |
302 | 302 | ||
− | >>> | + | >>> From news.models import Comment |
− | >>> | + | >>> Comment = Comment.objects.get (news = news) |
− | >>> | + | >>> Print comment.text |
− | Comment text</source> | + | Comment text </ source> |
− | + | See what is happening here. In lines 11-13 we create | |
− | + | New User (django_guru), and in 14-15 - the test client. In | |
− | + | line 16 django_guru authenticated, and now all of the system | |
− | + | will be performed by [http://www.mycaal.com loan modification] in his name. On line 18 we went to our first news page, passing the client means GET-request. | |
− | + | To check that we have succeeded, we study the server response code | |
− | ( | + | (Line 19) - it should be 200, or test will fail. |
− | + | Then (lines 21-22), the reading of additional response data, we | |
− | + | verify that the request is made a registered user | |
− | django_guru. | + | django_guru. Now it's time to leave a comment - not in vain |
− | + | We logged in? Line 23 is generated POST-request (second | |
− | + | argument to post () - dictionary data sent to the server). | |
− | + | Note that the value of the key text is blank, and | |
− | + | hence, the comment is not added, but the server still must return code 200 (line 25). But in line 26 we pass | |
− | + | all necessary data, and because after the comment we | |
− | + | redirected to the news page, the response code should be equal | |
− | 302 ( | + | 302 (The requested URL moved). Lines 29-32 verify that |
− | + | comment was actually added, we compare the text | |
− | + | with an initial value. Whew ... test passed. | |
− | === | + | Real Simple Syndication === === |
− | + | What is a news site without the tape? RSS and / or Atom feeds are everywhere - will be | |
− | + | and here, and Django us help you. Open the main file URL-cards and add to the end of the following lines: | |
<source lang="python" line="GESHI_NORMAL_LINE_NUMBERS"> | <source lang="python" line="GESHI_NORMAL_LINE_NUMBERS"> | ||
from feeds import LatestNews | from feeds import LatestNews | ||
feeds = { | feeds = { | ||
− | ' | + | 'Latest': LatestNews, |
} | } | ||
− | urlpatterns += patterns('', | + | urlpatterns + = patterns ('', |
− | ( | + | (R '^ feeds / (? P <url> .*)/$',' django.contrib.syndication.views.feed ', |
− | {' | + | {'Feed_dict': feeds}), |
) | ) | ||
− | </ | + | </ Source> |
− | + | Next you need to prepare a tape LatestNews, which we import at row 1. Create the root directory of the project feeds the file | |
− | __init__.py | + | __init__.py as follows: |
<source lang="python" line="GESHI_NORMAL_LINE_NUMBERS"> | <source lang="python" line="GESHI_NORMAL_LINE_NUMBERS"> | ||
− | # -*- | + | # -*- Coding: utf-8 -*- |
from django.contrib.syndication.feeds import Feed | from django.contrib.syndication.feeds import Feed | ||
Строка 151: | Строка 151: | ||
from django.contrib.syndication.feeds import FeedDoesNotExist | from django.contrib.syndication.feeds import FeedDoesNotExist | ||
− | class LatestNews(Feed): | + | class LatestNews (Feed): |
− | title = " | + | title = "Latest news from our site" |
− | description = " | + | description = "Recent developments on the site mysite.com" |
link = "http://127.0.0.1:8000/news/" | link = "http://127.0.0.1:8000/news/" | ||
− | def items(self): | + | def items (self): |
− | return News.objects.order_by("-pub_date")[:5] | + | return News.objects.order_by ("-pub_date") [: 5] |
− | def item_link(self, obj): | + | def item_link (self, obj): |
from django.core.urlresolvers import reverse | from django.core.urlresolvers import reverse | ||
− | return 'http://127.0.0.1:8000%s' % reverse('news.news_detail',kwargs={"news_id":obj.pk}) | + | return 'http://127.0.0.1:8000% s'% reverse ('news.news_detail', kwargs = {"news_id": obj.pk}) |
− | </ | + | </ Source> |
− | [[ | + | [[Image: LXF108 86 1.png | thumb | 250px | Fig. 3. Firefox offers to subscribe to our news website updated - now hold on!]] |
− | + | Fields title, description and link class LatestNews are required and are responsible for elements of the same name RSS. The method items () | |
− | + | passes the required objects in the tape, and item_link () is responsible for the link | |
− | + | to the site. Now create a directory of feeds media / templates, and add | |
− | + | in it two files, latest_description.html and latest_title.html: they will | |
− | + | responsible for the news column form. In lates_description.html write: | |
− | + | <nowiki> {{obj.description}} </ nowiki> | |
− | + | and latest_title.html: | |
− | + | <nowiki> [{{obj.pub_date | date: "dmY"}}] {{obj.title}} </ nowiki> | |
− | + | Obj is a record of the sample, we | |
− | + | return in line 13, file feeds / __init__.py. Having at | |
− | http://127.0.0.1:8000/feeds/latest/, | + | http://127.0.0.1:8000/feeds/latest/, we shall offer Firefox |
− | + | save feed. Members KDE, is likely to prefer | |
− | Akregator | + | Akregator - with him, too, there is no problem (Fig. 3, 4) |
− | === | + | === === Understanding |
− | + | To make life easier for web-developer, Django has included a large | |
− | + | number of representations to solve standard problems. For example, adding | |
− | + | in the main file URL-mapping the following code: | |
<source lang="python"> | <source lang="python"> | ||
from django.views.generic.list_detail import object_list | from django.views.generic.list_detail import object_list | ||
from news.models import News | from news.models import News | ||
− | urlpatterns += patterns('', | + | urlpatterns + = patterns ('', |
− | ('^ | + | ('^ Lastnews / $', object_list, { |
− | ' | + | 'Queryset': News.objects.all (). Order_by ('-pub_date') [: 10] |
− | ' | + | 'Template_name': 'news / last_news.html', |
− | ' | + | 'Template_object_name': 'last_news'}) |
− | )</ | + | ) </ Source> |
− | + | as well as replacing the file in news / templates / news / last_news.html | |
− | + | {% For news in last_news%} | |
− | + | on | |
− | + | {% For news in last_news_list%} | |
− | + | we will be able to view the latest news at | |
− | http://127.0.0.1:8000/lastnews/, | + | http://127.0.0.1:8000/lastnews/, causing no idea news.last_news. To make available both options must be found in presenting the line news.last_news |
− | + | "Last_news": news, | |
− | + | and replace it with | |
− | + | "Last_news_list": news, | |
− | + | As you may have guessed, the general idea object_list designed to work with a list of objects. Still there is a submission for | |
− | + | O objects, depending on the date (django.views.generic.date_based .*), which makes it very easy to create backups of records: | |
− | * | + | * Archive_index - withdrawal of the last object added to the database; |
− | * | + | * Archive_ {year, month, week, day, today} - the output of all the objects in a given year, month, week, day or today; |
− | * | + | * Object_detail - the output of one object for a particular day. |
− | + | General ideas are available for creating, updating and | |
− | + | deleting objects. They all work a little faster than by hand, but can solve only the most basic tasks. If the data in your application are selected from several | |
− | + | tables and is accompanied by the calculations, the overall presentation | |
− | + | will not help - then, they are common. | |
− | === | + | === Add === variables on the fly |
− | + | In the depths of the global context Django hide processors, the main task - to supply the template variables | |
− | + | and objects. Learn which ones are connected, you can in a tuple | |
− | TEMPLATE_CONTEXT_PROCESSORS | + | TEMPLATE_CONTEXT_PROCESSORS in your settings.py. For example, |
− | + | We are now working the following processors: | |
− | * | + | * Auth - information about the user: the object user, his rights of access and the messages that were sent to him; |
− | * | + | * I18n - information about the current language of the site and the client; |
− | * request | + | * Request - information on request. |
− | + | Besides them, there is a processor debug, sending in | |
− | + | pattern data of the executed SQL-queries, plus we can | |
− | + | write your own! To do this we create in the root of our | |
− | + | project directory and add the processors in it two files: __init__.py | |
− | + | and context_processors.py. The latter should contain the following code: | |
<source lang="python"> | <source lang="python"> | ||
import settings | import settings | ||
− | def site_settings(request): | + | def site_settings (request): |
− | return {'SETTINGS': settings}</source> | + | return {'SETTINGS': settings} </ source> |
− | + | To connect the processor, just list it in the tuple | |
− | TEMPLATE_CONTEXT_PROCESSORS. | + | TEMPLATE_CONTEXT_PROCESSORS. We check availability: |
− | + | add a template news.html following: | |
− | + | <nowiki> {{SETTINGS.TIME_ZONE}} </ nowiki> | |
− | + | Of course, TIME_ZONE can be replaced by any other variable that is defined in settings.py. | |
− | === | + | === === Sam himself filter |
− | + | With filters we met in [[LXF105: Django | LXF105]], but often there are situations when supplied with Django options are not enough. To write your own filter, create a radically | |
− | + | project directory templatetags / and add the files __init__.py | |
− | + | and filters.py. In filters.py write: | |
<source lang="python" line="GESHI_NORMAL_LINE_NUMBERS"> | <source lang="python" line="GESHI_NORMAL_LINE_NUMBERS"> | ||
from django import template | from django import template | ||
− | register = template.Library() | + | register = template.Library () |
− | @ | + | @ Register.filter |
− | def exp(value, arg): | + | def exp (value, arg): |
− | if value.isdigit() and arg.isdigit(): | + | if value.isdigit () and arg.isdigit (): |
− | return int(value)**int(arg) | + | return int (value) ** int (arg) |
else: | else: | ||
− | return '<span style= | + | return '<span style="color:red"> Error </ span>' |
− | exp.is_safe = True</source > | + | exp.is_safe = True </ source> |
− | + | We have created a filter exp, which will have a value and an exponent and raises one another, if the arguments are not numbers, an error is generated. In line 5 we register | |
− | + | filter in the system with the help of a decorator. Line 11 indicates | |
− | + | that exp can return HTML-code. Because (for security), it automatically screened (<and> are replaced by < and | |
− | & | + | > etc.), then, wanting to see pure HTML, we should prohibit |
− | + | this behavior manually. The next step is loading of | |
− | + | library of filters to the template, which you need to add the | |
− | + | the following line: | |
− | + | {% Load filters%} | |
− | + | In fact, Django looks for templates created by the library in the application root, so our filter still will not be available. It | |
− | + | not very convenient, especially if we want to use the | |
− | + | the same filter in many applications. The solution - to create a project | |
− | + | single library, and put in applications merely symbolic | |
− | + | references to it. | |
− | <source lang="bash">ln -s /var/www/myproject/templatetags/ /var/www/myproject/news/</source> | + | <source lang="bash"> ln-s / var / www / myproject / templatetags / / var / www / myproject / news / </ source> |
− | + | Now test the filter by adding any template | |
− | + | line. | |
− | + | <nowiki> {{"4" | exp: "4"}} </ nowiki> | |
− | + | At compile time, it will be replaced by 256. If we | |
− | + | write | |
− | + | <nowiki> {{"a" | exp: "4"}} </ nowiki> | |
− | + | we see the word «Error», in red. | |
− | + | By the way, if we did not specify a filter in line 11 exp.is_safe = True, you could simply apply the filter directly into the safe | |
− | + | template: | |
− | + | <nowiki> {{"a" | exp: "4" | safe}} </ nowiki> | |
− | + | After registering a filter in the system, information about it becomes available at http://127.0.0.1:8000/admin/doc/filters/ | |
− | ( | + | (Fig. 4) |
− | [[ | + | [[Image: LXF108 87 1.png | frame | center | Fig. 4. The system politely tells you how to use the filter you created.]] |
− | === | + | === === The components of |
− | + | If we have to perform any action before or after | |
− | + | as would be caused by representation, or if an error occurs, you can create your own components (middleware), or use | |
− | + | supplied with Django. We've already done this, when studied caching ([[LXF107: Django | LXF107]]). I recall that in the settings.py file is a tuple | |
− | MIDDLEWARE_CLASSES, | + | MIDDLEWARE_CLASSES, which lists the components involved in the project. We are: |
− | * | + | * Django.middleware.common.CommonMiddleware solve common problems: normalizes the URL (adds a www and the trailing /), prohibits access to the site specific robot interacts with Etag. |
− | * | + | * Django.contrib.sessions.middleware.SessionMiddleware this session. |
− | * | + | * Django.contrib.auth.middleware.AuthenticationMiddleware And this - authorization. |
− | * | + | * Django.middleware.doc.XViewMiddleware used for automatic documentation Django. |
− | * | + | * Django.middleware.locale.LocaleMiddleware Internationalization. |
− | + | In addition to the above, the following are available in Django | |
− | + | components (django.middleware .*): | |
− | * | + | * Gzip.GZipMiddleware compression sends the page to save bandwidth. |
− | * | + | * Http.ConditionalGetMiddleware Support for conditional GET-requests to work with the Last-Modified and Etag. |
− | * | + | * Http.SetRemoteAddrFromForwardedFor reverse proxying. |
− | * | + | * Cache.CacheMiddleware The same cache, which we encountered in the previous lesson. |
− | * | + | * Transaction.TransactionMiddleware component for inclusion in SQL-queries of transaction structures: COMMIT, ROLLBACK. |
− | + | Note that not all databases support transactions. | |
− | + | And finally, django.contrib.csrf.middleware.CsrfMiddleware, protecting against CSRF-attacks. | |
− | + | It has become a tradition, consider how to write your | |
− | + | own components. From a programmer's standpoint, it's just | |
− | + | Class Python, having a number of methods called Django at some point in time. The first is the constructor | |
− | __init__(self), | + | __init__ (self), registering the components in the system. Next are the methods of determining the order of the code: |
− | * | + | * Process_request () - runs after the request, but before Django will look for the requested address in the URL-maps; |
− | * | + | * Process_view () - work out when the concrete representation is defined, but not yet started; |
− | * | + | * Process_response () - runs after the presentation. |
− | + | Used to compress the generated HTML. | |
− | process_exception() | + | process_exception () - called when something goes wrong or |
− | + | were instituted an unhandled exception. | |
− | + | That is, in essence, that's all. But no - look at the sidebar and | |
− | + | away, away, away, read the documentation or the free | |
− | + | a book about Django - Django Book (http://www.djangobook.com); if you | |
− | + | prefer Russian, I advise you to look at http://cargo.caml.ru/djangobook. Finally, apply the acquired knowledge into practice - and let us know if you have something really worthwhile! | |
− | {{ | + | {{Box | center | |
− | | | + | | Title =, etc., etc., other ... |
− | | | + | | Table of Contents = Over four lessons, we had to consider almost all possible |
− | Django, | + | Django, but something is left out ... |
− | * | + | *, E-mail |
− | Django | + | Django offers a high-level API to send a message to |
− | + | one action: | |
− | <source lang="python">from django.core.mail import send_mail | + | <source lang="python"> from django.core.mail import send_mail |
− | send_mail(' | + | send_mail ('Subject', 'message.', 'from@example.com', ['to@example.com'], fail_silently = False) </ source> |
− | + | In addition, there is a function of mass communications, alerts, site administrators and managers, as well as working with | |
− | + | different content (HTML, text, graphics, etc.) | |
− | *; CSV | + | *; CSV and PDF |
− | Django | + | Django makes it easy to create data files, Comma Separated Values (CSV), as well as PDF-documents using |
− | + | Library ReportLab (http://www.reportlab.org/rl_toolkit.html). | |
− | * | + | *, Paged |
− | + | When the number of objects is so large that one page is enough, have the support of a special class | |
− | Paginator, | + | Paginator, who helps organize paged: |
<source lang="python">>>> from django.core.paginator import Paginator | <source lang="python">>>> from django.core.paginator import Paginator | ||
− | >>> | + | >>> Objects = ['django', 'python', 'mysql', 'apache'] |
− | >>> | + | >>> P = Paginator (objects, 2) |
− | >>> | + | >>> Page1 = p.page (1) |
− | >>> | + | >>> Page1.object_list |
− | [' | + | ['Django', 'python'] </ source> |
− | + | Since most of our objects are stored in the database, | |
− | Django | + | Django also offers class QuerySetPaginator, which takes no list, and many objects from the database. |
− | *; | + | *; Sitemaps |
− | + | Want to have your site properly indexed by search | |
− | + | machines? You need to create his map! Django will help | |
− | + | here, and the function django.contrib.sitemaps.ping_google «cause» | |
− | Google | + | Google to update the index for your website. |
− | + | ; * Managing multiple sites | |
− | + | One of the problems with which copes Django, is | |
− | + | control of several similar sites on the subject of a | |
− | + | installation. The project was originally designed as a platform for news portals, news, and one could appear | |
− | + | on multiple resources. | |
− | *; | + | *; To help designers |
− | + | Load the module templates to help designers: | |
− | + | {% Load webdesign%} | |
− | + | you get at your disposal tag {% lorem%}, with | |
− | + | which you can display certain Latin phrase «lorem | |
− | ipsum ... | + | ipsum ... »to fill the template" fish. " |
− | * | + | ; * And more |
− | Django | + | Django has a lot of other "goodies" that are very |
− | + | well described in the accompanying documentation in English | |
− | + | language. | |
− | | | + | | Width =}} |
Версия 11:02, 20 июля 2011
|
|
|
Cycle Шаблон:/ Django == == The final touches
- PART 4 Lessons Django comes to an end, there comes a time for exams - if not for you, for applications for sure. Nikita Shultays (http://shultais.ru) will deal with testing and go over other features of this framework.
Newsline is ready - but whether it will meet expectations users? The answer to this question can be tested, the best - in the real world, but some basic things you can check at the stage of development thesis writers. If you time to look at the tutorial Rails, you already know about the methodology of TDD. However, we'll go the other way, and will test application not to write, and after.
The point is - a serious and complex, as we need to consider interaction with the database, a compilation of templates, processes and GET- POST-requests and other system components: a failure in any of They can cause disrupt the entire site. Go to this problem can be approached from two sides:
- Testing in your browser. We are talking about programs Twill (http://twill.idyll.org) and Selenium (http://selenium.openqa.org): they "remember" the sequence of your actions for each page, and then reproduce it on demand. For example, you can type in form fields obviously incorrect data, get the expected error and repeat the test whenever a major change in the code of your application.
- Testing on the server. And then Django does not leave us to fend for themselves, offering just two options: doctest (tested via documentation) and unittest (unit testing), plus a special client to send a GET-and POST-requests.
If you've been programming in Python, then you probably will be closer doctest, and migrants from the Java world have more in taste unittest. There are no restrictions on their use is imposed: you can choose one system or use both at once. We also discuss the doctest.
Document it!
Line documentation in Python - it is plain text that you place after the definition of a function or class directly in the source code. It also provides content for the attribute __doc__. As Typically, it is placed in triple quotes ("""), that allows you to enter complex structures with line breaks, indentation, the same quotes and ... tests. That's what we use.
Tests can be found in the model files (models.py) - to check the latest - and in special files tests.py, located in the application directory. For example, create a news / tests.py to the following:
# -*- Coding: utf-8 -*-
"" "
>>> From news.models import News
>>> From datetime import datetime
>>> News = News (title = "Title", description = "Description", pub_date = datetime.now (), text = "text")
>>> News.save ()
>>> News = News.objects.get (pk = 1)
>>> Print news.title.encode ('utf-8')
Title
"" "
</ Source>
In line 1 encoding, but since the third is very
test. Note that each line begins with three characters "more" (>>>), in the interactive mode, Python. Line 10
These characters do not, because it contains the expected output
print from line 9.
[[Image: LXF108 85 1.png | thumb | 200px | Fig. 1. Test passed successfully!]]
Before running the test, you need to add in settings.py
line
TEST_DATABASE_CHARSET = "UTF8"
to file encoding and the database match. Before performing the test, Django will create a special auxiliary databases, so
the user specified in settings.DATABASE_USER, must have
the appropriate authority. To begin testing, type:
python manage.py test news
after which you will see something that shows
Fig. 1.
Messages similar to appear during the creation of tables
when you first install, but now it happens in a test database. In
end shows the number of tests performed, their results and
notified about the destruction of a test material. We checked our
application (news), but, as you know, Django provides a few
own applications and representations (eg, "admin") -
and they also supplied with their tests. To perform them all,
must enter the command:
python manage.py test
adding previously in the main file the following URL-card
lines:
<source lang="python"> urlpatterns + = patterns ('django.contrib.auth.views',
url (r '^ auth / password_reset /$',' password_reset'),
) </ Source>
Here we include one of the built-in views, designed to recover your password. This is necessary since
testing of the entire project is being accessed at the specified URL,
and if the view is not specified, the test will fail. By the way, you
also can try password_reset in (Fig. 2).
[[Image: LXF108 85 2.png | frame | center | Fig. 2. Forgot your password? This problem Django!]]
=== === Network Simulator
The number of tests has already reached six, but in addition to creating and
retrieve objects from the database, we need to test the response to
GET-and POST-requests. As you know, for these purposes there
special client: it emulates the query and returns the variables that are passed to the template for this URL. Add the
tests.py file after line 10 the following code:
<source lang="python" line="GESHI_NORMAL_LINE_NUMBERS" line start="11">
>>> From django.contrib.auth.models import User
>>> User = User.objects.create_user ('django_guru', 'user@example.com', 'password')
>>> User.save ()
>>> From django.test.client import Client
>>> C = Client ()
>>> C.login (username = 'django_guru', password = "password")
True
>>> Response = c.get ('/ news / 1 /')
>>> Response.status_code
200
>>> Print response.context [0] ['user']. Username
django_guru
>>> Response = c.post ('/ news / 1 /',{' username': "testuser", 'text':»»})
>>> Response.status_code
200
>>> Response = c.post ('/ news / 1 /',{' username': "testuser", 'text': »Comment text»})
>>> Response.status_code
302
>>> From news.models import Comment
>>> Comment = Comment.objects.get (news = news)
>>> Print comment.text
Comment text </ source>
See what is happening here. In lines 11-13 we create
New User (django_guru), and in 14-15 - the test client. In
line 16 django_guru authenticated, and now all of the system
will be performed by [http://www.mycaal.com loan modification] in his name. On line 18 we went to our first news page, passing the client means GET-request.
To check that we have succeeded, we study the server response code
(Line 19) - it should be 200, or test will fail.
Then (lines 21-22), the reading of additional response data, we
verify that the request is made a registered user
django_guru. Now it's time to leave a comment - not in vain
We logged in? Line 23 is generated POST-request (second
argument to post () - dictionary data sent to the server).
Note that the value of the key text is blank, and
hence, the comment is not added, but the server still must return code 200 (line 25). But in line 26 we pass
all necessary data, and because after the comment we
redirected to the news page, the response code should be equal
302 (The requested URL moved). Lines 29-32 verify that
comment was actually added, we compare the text
with an initial value. Whew ... test passed.
Real Simple Syndication === ===
What is a news site without the tape? RSS and / or Atom feeds are everywhere - will be
and here, and Django us help you. Open the main file URL-cards and add to the end of the following lines:
<source lang="python" line="GESHI_NORMAL_LINE_NUMBERS">
from feeds import LatestNews
feeds = {
'Latest': LatestNews,
}
urlpatterns + = patterns ('',
(R '^ feeds / (? P <url> .*)/$',' django.contrib.syndication.views.feed ',
{'Feed_dict': feeds}),
)
</ Source>
Next you need to prepare a tape LatestNews, which we import at row 1. Create the root directory of the project feeds the file
__init__.py as follows:
<source lang="python" line="GESHI_NORMAL_LINE_NUMBERS">
# -*- Coding: utf-8 -*-
from django.contrib.syndication.feeds import Feed
from news.models import News
from django.contrib.syndication.feeds import FeedDoesNotExist
class LatestNews (Feed):
title = "Latest news from our site"
description = "Recent developments on the site mysite.com"
link = "http://127.0.0.1:8000/news/"
def items (self):
return News.objects.order_by ("-pub_date") [: 5]
def item_link (self, obj):
from django.core.urlresolvers import reverse
return 'http://127.0.0.1:8000% s'% reverse ('news.news_detail', kwargs = {"news_id": obj.pk})
</ Source>
[[Image: LXF108 86 1.png | thumb | 250px | Fig. 3. Firefox offers to subscribe to our news website updated - now hold on!]]
Fields title, description and link class LatestNews are required and are responsible for elements of the same name RSS. The method items ()
passes the required objects in the tape, and item_link () is responsible for the link
to the site. Now create a directory of feeds media / templates, and add
in it two files, latest_description.html and latest_title.html: they will
responsible for the news column form. In lates_description.html write:
<nowiki> {{obj.description}} </ nowiki>
and latest_title.html:
<nowiki> [{{obj.pub_date | date: "dmY"}}] {{obj.title}} </ nowiki>
Obj is a record of the sample, we
return in line 13, file feeds / __init__.py. Having at
http://127.0.0.1:8000/feeds/latest/, we shall offer Firefox
save feed. Members KDE, is likely to prefer
Akregator - with him, too, there is no problem (Fig. 3, 4)
=== === Understanding
To make life easier for web-developer, Django has included a large
number of representations to solve standard problems. For example, adding
in the main file URL-mapping the following code:
<source lang="python">
from django.views.generic.list_detail import object_list
from news.models import News
urlpatterns + = patterns ('',
('^ Lastnews / $', object_list, {
'Queryset': News.objects.all (). Order_by ('-pub_date') [: 10]
'Template_name': 'news / last_news.html',
'Template_object_name': 'last_news'})
) </ Source>
as well as replacing the file in news / templates / news / last_news.html
{% For news in last_news%}
on
{% For news in last_news_list%}
we will be able to view the latest news at
http://127.0.0.1:8000/lastnews/, causing no idea news.last_news. To make available both options must be found in presenting the line news.last_news
"Last_news": news,
and replace it with
"Last_news_list": news,
As you may have guessed, the general idea object_list designed to work with a list of objects. Still there is a submission for
O objects, depending on the date (django.views.generic.date_based .*), which makes it very easy to create backups of records:
* Archive_index - withdrawal of the last object added to the database;
* Archive_ {year, month, week, day, today} - the output of all the objects in a given year, month, week, day or today;
* Object_detail - the output of one object for a particular day.
General ideas are available for creating, updating and
deleting objects. They all work a little faster than by hand, but can solve only the most basic tasks. If the data in your application are selected from several
tables and is accompanied by the calculations, the overall presentation
will not help - then, they are common.
=== Add === variables on the fly
In the depths of the global context Django hide processors, the main task - to supply the template variables
and objects. Learn which ones are connected, you can in a tuple
TEMPLATE_CONTEXT_PROCESSORS in your settings.py. For example,
We are now working the following processors:
* Auth - information about the user: the object user, his rights of access and the messages that were sent to him;
* I18n - information about the current language of the site and the client;
* Request - information on request.
Besides them, there is a processor debug, sending in
pattern data of the executed SQL-queries, plus we can
write your own! To do this we create in the root of our
project directory and add the processors in it two files: __init__.py
and context_processors.py. The latter should contain the following code:
<source lang="python">
import settings
def site_settings (request):
return {'SETTINGS': settings} </ source>
To connect the processor, just list it in the tuple
TEMPLATE_CONTEXT_PROCESSORS. We check availability:
add a template news.html following:
<nowiki> {{SETTINGS.TIME_ZONE}} </ nowiki>
Of course, TIME_ZONE can be replaced by any other variable that is defined in settings.py.
=== === Sam himself filter
With filters we met in [[LXF105: Django | LXF105]], but often there are situations when supplied with Django options are not enough. To write your own filter, create a radically
project directory templatetags / and add the files __init__.py
and filters.py. In filters.py write:
<source lang="python" line="GESHI_NORMAL_LINE_NUMBERS">
from django import template
register = template.Library ()
@ Register.filter
def exp (value, arg):
if value.isdigit () and arg.isdigit ():
return int (value) ** int (arg)
else:
return '<span style="color:red"> Error </ span>'
exp.is_safe = True </ source>
We have created a filter exp, which will have a value and an exponent and raises one another, if the arguments are not numbers, an error is generated. In line 5 we register
filter in the system with the help of a decorator. Line 11 indicates
that exp can return HTML-code. Because (for security), it automatically screened (<and> are replaced by < and
> etc.), then, wanting to see pure HTML, we should prohibit
this behavior manually. The next step is loading of
library of filters to the template, which you need to add the
the following line:
{% Load filters%}
In fact, Django looks for templates created by the library in the application root, so our filter still will not be available. It
not very convenient, especially if we want to use the
the same filter in many applications. The solution - to create a project
single library, and put in applications merely symbolic
references to it.
<source lang="bash"> ln-s / var / www / myproject / templatetags / / var / www / myproject / news / </ source>
Now test the filter by adding any template
line.
<nowiki> {{"4" | exp: "4"}} </ nowiki>
At compile time, it will be replaced by 256. If we
write
<nowiki> {{"a" | exp: "4"}} </ nowiki>
we see the word «Error», in red.
By the way, if we did not specify a filter in line 11 exp.is_safe = True, you could simply apply the filter directly into the safe
template:
<nowiki> {{"a" | exp: "4" | safe}} </ nowiki>
After registering a filter in the system, information about it becomes available at http://127.0.0.1:8000/admin/doc/filters/
(Fig. 4)
[[Image: LXF108 87 1.png | frame | center | Fig. 4. The system politely tells you how to use the filter you created.]]
=== === The components of
If we have to perform any action before or after
as would be caused by representation, or if an error occurs, you can create your own components (middleware), or use
supplied with Django. We've already done this, when studied caching ([[LXF107: Django | LXF107]]). I recall that in the settings.py file is a tuple
MIDDLEWARE_CLASSES, which lists the components involved in the project. We are:
* Django.middleware.common.CommonMiddleware solve common problems: normalizes the URL (adds a www and the trailing /), prohibits access to the site specific robot interacts with Etag.
* Django.contrib.sessions.middleware.SessionMiddleware this session.
* Django.contrib.auth.middleware.AuthenticationMiddleware And this - authorization.
* Django.middleware.doc.XViewMiddleware used for automatic documentation Django.
* Django.middleware.locale.LocaleMiddleware Internationalization.
In addition to the above, the following are available in Django
components (django.middleware .*):
* Gzip.GZipMiddleware compression sends the page to save bandwidth.
* Http.ConditionalGetMiddleware Support for conditional GET-requests to work with the Last-Modified and Etag.
* Http.SetRemoteAddrFromForwardedFor reverse proxying.
* Cache.CacheMiddleware The same cache, which we encountered in the previous lesson.
* Transaction.TransactionMiddleware component for inclusion in SQL-queries of transaction structures: COMMIT, ROLLBACK.
Note that not all databases support transactions.
And finally, django.contrib.csrf.middleware.CsrfMiddleware, protecting against CSRF-attacks.
It has become a tradition, consider how to write your
own components. From a programmer's standpoint, it's just
Class Python, having a number of methods called Django at some point in time. The first is the constructor
__init__ (self), registering the components in the system. Next are the methods of determining the order of the code:
* Process_request () - runs after the request, but before Django will look for the requested address in the URL-maps;
* Process_view () - work out when the concrete representation is defined, but not yet started;
* Process_response () - runs after the presentation.
Used to compress the generated HTML.
process_exception () - called when something goes wrong or
were instituted an unhandled exception.
That is, in essence, that's all. But no - look at the sidebar and
away, away, away, read the documentation or the free
a book about Django - Django Book (http://www.djangobook.com); if you
prefer Russian, I advise you to look at http://cargo.caml.ru/djangobook. Finally, apply the acquired knowledge into practice - and let us know if you have something really worthwhile!
{{Box | center |
| Title =, etc., etc., other ...
| Table of Contents = Over four lessons, we had to consider almost all possible
Django, but something is left out ...
*, E-mail
Django offers a high-level API to send a message to
one action:
<source lang="python"> from django.core.mail import send_mail
send_mail ('Subject', 'message.', 'from@example.com', ['to@example.com'], fail_silently = False) </ source>
In addition, there is a function of mass communications, alerts, site administrators and managers, as well as working with
different content (HTML, text, graphics, etc.)
*; CSV and PDF
Django makes it easy to create data files, Comma Separated Values (CSV), as well as PDF-documents using
Library ReportLab (http://www.reportlab.org/rl_toolkit.html).
*, Paged
When the number of objects is so large that one page is enough, have the support of a special class
Paginator, who helps organize paged:
<source lang="python">>>> from django.core.paginator import Paginator
>>> Objects = ['django', 'python', 'mysql', 'apache']
>>> P = Paginator (objects, 2)
>>> Page1 = p.page (1)
>>> Page1.object_list
['Django', 'python'] </ source>
Since most of our objects are stored in the database,
Django also offers class QuerySetPaginator, which takes no list, and many objects from the database.
*; Sitemaps
Want to have your site properly indexed by search
machines? You need to create his map! Django will help
here, and the function django.contrib.sitemaps.ping_google «cause»
Google to update the index for your website.
; * Managing multiple sites
One of the problems with which copes Django, is
control of several similar sites on the subject of a
installation. The project was originally designed as a platform for news portals, news, and one could appear
on multiple resources.
*; To help designers
Load the module templates to help designers:
{% Load webdesign%}
you get at your disposal tag {% lorem%}, with
which you can display certain Latin phrase «lorem
ipsum ... »to fill the template" fish. "
; * And more
Django has a lot of other "goodies" that are very
well described in the accompanying documentation in English
language.
| Width =}}