Журнал LinuxFormat - перейти на главную

LXF108:Django

Материал из Linuxformat
Перейти к: навигация, поиск

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,loan modification 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:

  1. # -*- Coding: utf-8 -*-
  2.  
  3. "" "
  4. >>> From news.models import News
  5. >>> From datetime import datetime
  6. >>> News = News (title = "Title", description = "Description", pub_date = datetime.now (), text = "text")
  7. >>> News.save ()
  8. >>> News = News.objects.get (pk = 1)
  9. >>> Print news.title.encode ('utf-8')
  10.  Title
  11. "" "
  12. </ Source>
  13. In line 1 encoding, but since the third is very
  14. test. Note that each line begins with three characters "more" (>>>), in the interactive mode, Python. Line 10
  15. These characters do not, because it contains the expected output
  16. print from line 9.
  17.  
  18. [[Image: LXF108 85 1.png | thumb | 200px | Fig. 1. Test passed successfully!]]
  19. Before running the test, you need to add in settings.py
  20. line
  21.  TEST_DATABASE_CHARSET = "UTF8"
  22. to file encoding and the database match. Before performing the test, Django will create a special auxiliary databases, so
  23. the user specified in settings.DATABASE_USER, must have
  24. the appropriate authority. To begin testing, type:
  25.  python manage.py test news
  26. after which you will see something that shows
  27. Fig. 1.
  28.  
  29. Messages similar to appear during the creation of tables
  30. when you first install, but now it happens in a test database. In
  31. end shows the number of tests performed, their results and
  32. notified about the destruction of a test material. We checked our
  33. application (news), but, as you know, Django provides a few
  34. own applications and representations (eg, "admin") -
  35. and they also supplied with their tests. To perform them all,
  36. must enter the command:
  37.  python manage.py test
  38. adding previously in the main file the following URL-card
  39. lines:
  40. <source lang="python"> urlpatterns + = patterns ('django.contrib.auth.views',
  41. url (r '^ auth / password_reset /$',' password_reset'),
  42. ) </ Source>
  43. Here we include one of the built-in views, designed to recover your password. This is necessary since
  44. testing of the entire project is being accessed at the specified URL,
  45. and if the view is not specified, the test will fail. By the way, you
  46. also can try password_reset in (Fig. 2).
  47. [[Image: LXF108 85 2.png | frame | center | Fig. 2. Forgot your password? This problem Django!]]
  48.  
  49. === === Network Simulator
  50. The number of tests has already reached six, but in addition to creating and
  51. retrieve objects from the database, we need to test the response to
  52. GET-and POST-requests. As you know, for these purposes there
  53. special client: it emulates the query and returns the variables that are passed to the template for this URL. Add the
  54. tests.py file after line 10 the following code:
  55. <source lang="python" line="GESHI_NORMAL_LINE_NUMBERS" line start="11">
  56. >>> From django.contrib.auth.models import User
  57. >>> User = User.objects.create_user ('django_guru', 'user@example.com', 'password')
  58. >>> User.save ()
  59. >>> From django.test.client import Client
  60. >>> C = Client ()
  61. >>> C.login (username = 'django_guru', password = "password")
  62. True
  63. >>> Response = c.get ('/ news / 1 /')
  64. >>> Response.status_code
  65. 200
  66. >>> Print response.context [0] ['user']. Username
  67. django_guru
  68. >>> Response = c.post ('/ news / 1 /',{' username': "testuser", 'text':»»})
  69. >>> Response.status_code
  70. 200
  71. >>> Response = c.post ('/ news / 1 /',{' username': "testuser", 'text': »Comment text»})
  72. >>> Response.status_code
  73. 302
  74. >>> From news.models import Comment
  75. >>> Comment = Comment.objects.get (news = news)
  76. >>> Print comment.text
  77. Comment text </ source>
  78. See what is happening here. In lines 11-13 we create
  79. New User (django_guru), and in 14-15 - the test client. In
  80. line 16 django_guru authenticated, and now all of the system
  81. will be performed by  in his name. On line 18 we went to our first news page, passing the client means GET-request.
  82. To check that we have succeeded, we study the server response code
  83. (Line 19) - it should be 200, or test will fail.
  84. Then (lines 21-22), the reading of additional response data, we
  85. verify that the request is made a registered user
  86. django_guru. Now it's time to leave a comment - not in vain
  87. We logged in? Line 23 is generated POST-request (second
  88. argument to post () - dictionary data sent to the server).
  89. Note that the value of the key text is blank, and
  90. hence, the comment is not added, but the server still must return code 200 (line 25). But in line 26 we pass
  91. all necessary data, and because after the comment we
  92. redirected to the news page, the response code should be equal
  93. 302 (The requested URL moved). Lines 29-32 verify that
  94. comment was actually added, we compare the text
  95. with an initial value. Whew ... test passed.
  96.  
  97. Real Simple Syndication === ===
  98. What is a news site without the tape? RSS and / or Atom feeds are everywhere - will be
  99. and here, and Django us help you. Open the main file URL-cards and add to the end of the following lines:
  100. <source lang="python" line="GESHI_NORMAL_LINE_NUMBERS">
  101. from feeds import LatestNews
  102.  
  103. feeds = {
  104. 'Latest': LatestNews,
  105. }
  106. urlpatterns + = patterns ('',
  107. (R '^ feeds / (? P <url> .*)/$',' django.contrib.syndication.views.feed ',
  108. {'Feed_dict': feeds}),
  109. )
  110. </ Source>
  111. Next you need to prepare a tape LatestNews, which we import at row 1. Create the root directory of the project feeds the file
  112. __init__.py as follows:
  113. <source lang="python" line="GESHI_NORMAL_LINE_NUMBERS">
  114. # -*- Coding: utf-8 -*-
  115.  
  116. from django.contrib.syndication.feeds import Feed
  117. from news.models import News
  118. from django.contrib.syndication.feeds import FeedDoesNotExist
  119.  
  120. class LatestNews (Feed):
  121. title = "Latest news from our site"
  122. description = "Recent developments on the site mysite.com"
  123. link = "http://127.0.0.1:8000/news/"
  124.  
  125. def items (self):
  126. return News.objects.order_by ("-pub_date") [: 5]
  127.  
  128. def item_link (self, obj):
  129. from django.core.urlresolvers import reverse
  130. return 'http://127.0.0.1:8000% s'% reverse ('news.news_detail', kwargs = {"news_id": obj.pk})
  131. </ Source>
  132. [[Image: LXF108 86 1.png | thumb | 250px | Fig. 3. Firefox offers to subscribe to our news website updated - now hold on!]]
  133. Fields title, description and link class LatestNews are required and are responsible for elements of the same name RSS. The method items ()
  134. passes the required objects in the tape, and item_link () is responsible for the link
  135. to the site. Now create a directory of feeds media / templates, and add
  136. in it two files, latest_description.html and latest_title.html: they will
  137. responsible for the news column form. In lates_description.html write:
  138.  <nowiki> {{obj.description}} </ nowiki>
  139. and latest_title.html:
  140.  <nowiki> [{{obj.pub_date | date: "dmY"}}] {{obj.title}} </ nowiki>
  141. Obj is a record of the sample, we
  142. return in line 13, file feeds / __init__.py. Having at
  143. http://127.0.0.1:8000/feeds/latest/, we shall offer Firefox
  144. save feed. Members KDE, is likely to prefer
  145. Akregator - with him, too, there is no problem (Fig. 3, 4)
  146.  
  147. === === Understanding
  148. To make life easier for web-developer, Django has included a large
  149. number of representations to solve standard problems. For example, adding
  150. in the main file URL-mapping the following code:
  151. <source lang="python">
  152. from django.views.generic.list_detail import object_list
  153. from news.models import News
  154. urlpatterns + = patterns ('',
  155. ('^ Lastnews / $', object_list, {
  156. 'Queryset': News.objects.all (). Order_by ('-pub_date') [: 10]
  157. 'Template_name': 'news / last_news.html',
  158. 'Template_object_name': 'last_news'})
  159. ) </ Source>
  160. as well as replacing the file in news / templates / news / last_news.html
  161.  {% For news in last_news%}
  162. on
  163.  {% For news in last_news_list%}
  164. we will be able to view the latest news at
  165. 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
  166.  "Last_news": news,
  167. and replace it with
  168.  "Last_news_list": news,
  169. As you may have guessed, the general idea object_list designed to work with a list of objects. Still there is a submission for
  170. O objects, depending on the date (django.views.generic.date_based .*), which makes it very easy to create backups of records:
  171. * Archive_index - withdrawal of the last object added to the database;
  172. * Archive_ {year, month, week, day, today} - the output of all the objects in a given year, month, week, day or today;
  173. * Object_detail - the output of one object for a particular day.
  174. General ideas are available for creating, updating and
  175. 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
  176. tables and is accompanied by the calculations, the overall presentation
  177. will not help - then, they are common.
  178.  
  179. === Add === variables on the fly
  180. In the depths of the global context Django hide processors, the main task - to supply the template variables
  181. and objects. Learn which ones are connected, you can in a tuple
  182. TEMPLATE_CONTEXT_PROCESSORS in your settings.py. For example,
  183. We are now working the following processors:
  184. * Auth - information about the user: the object user, his rights of access and the messages that were sent to him;
  185. * I18n - information about the current language of the site and the client;
  186. * Request - information on request.
  187. Besides them, there is a processor debug, sending in
  188. pattern data of the executed SQL-queries, plus we can
  189. write your own! To do this we create in the root of our
  190. project directory and add the processors in it two files: __init__.py
  191. and context_processors.py. The latter should contain the following code:
  192. <source lang="python">
  193. import settings
  194. def site_settings (request):
  195. return {'SETTINGS': settings} </ source>
  196. To connect the processor, just list it in the tuple
  197. TEMPLATE_CONTEXT_PROCESSORS. We check availability:
  198. add a template news.html following:
  199.  <nowiki> {{SETTINGS.TIME_ZONE}} </ nowiki>
  200. Of course, TIME_ZONE can be replaced by any other variable that is defined in settings.py.
  201.  
  202. === === Sam himself filter
  203. 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
  204. project directory templatetags / and add the files __init__.py
  205. and filters.py. In filters.py write:
  206. <source lang="python" line="GESHI_NORMAL_LINE_NUMBERS">
  207. from django import template
  208.  
  209. register = template.Library ()
  210.  
  211. @ Register.filter
  212. def exp (value, arg):
  213. if value.isdigit () and arg.isdigit ():
  214. return int (value) ** int (arg)
  215. else:
  216. return '<span style="color:red"> Error </ span>'
  217. exp.is_safe = True </ source>
  218. 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
  219. filter in the system with the help of a decorator. Line 11 indicates
  220. that exp can return HTML-code. Because (for security), it automatically screened (<and> are replaced by &lt; and
  221. &gt; etc.), then, wanting to see pure HTML, we should prohibit
  222. this behavior manually. The next step is loading of
  223. library of filters to the template, which you need to add the
  224. the following line:
  225.  {% Load filters%}
  226. In fact, Django looks for templates created by the library in the application root, so our filter still will not be available. It
  227. not very convenient, especially if we want to use the
  228. the same filter in many applications. The solution - to create a project
  229. single library, and put in applications merely symbolic
  230. references to it.
  231. <source lang="bash"> ln-s / var / www / myproject / templatetags / / var / www / myproject / news / </ source>
  232. Now test the filter by adding any template
  233. line.
  234.  <nowiki> {{"4" | exp: "4"}} </ nowiki>
  235. At compile time, it will be replaced by 256. If we
  236. write
  237.  <nowiki> {{"a" | exp: "4"}} </ nowiki>
  238. we see the word «Error», in red.
  239. 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
  240. template:
  241.  <nowiki> {{"a" | exp: "4" | safe}} </ nowiki>
  242. After registering a filter in the system, information about it becomes available at http://127.0.0.1:8000/admin/doc/filters/
  243. (Fig. 4)
  244. [[Image: LXF108 87 1.png | frame | center | Fig. 4. The system politely tells you how to use the filter you created.]]
  245.  
  246. === === The components of
  247. If we have to perform any action before or after
  248. as would be caused by representation, or if an error occurs, you can create your own components (middleware), or use
  249. 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
  250. MIDDLEWARE_CLASSES, which lists the components involved in the project. We are:
  251. * 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.
  252. * Django.contrib.sessions.middleware.SessionMiddleware this session.
  253. * Django.contrib.auth.middleware.AuthenticationMiddleware And this - authorization.
  254. * Django.middleware.doc.XViewMiddleware used for automatic documentation Django.
  255. * Django.middleware.locale.LocaleMiddleware Internationalization.
  256. In addition to the above, the following are available in Django
  257. components (django.middleware .*):
  258. * Gzip.GZipMiddleware compression sends the page to save bandwidth.
  259. * Http.ConditionalGetMiddleware Support for conditional GET-requests to work with the Last-Modified and Etag.
  260. * Http.SetRemoteAddrFromForwardedFor reverse proxying.
  261. * Cache.CacheMiddleware The same cache, which we encountered in the previous lesson.
  262. * Transaction.TransactionMiddleware component for inclusion in SQL-queries of transaction structures: COMMIT, ROLLBACK.
  263. Note that not all databases support transactions.
  264.  
  265. And finally, django.contrib.csrf.middleware.CsrfMiddleware, protecting against CSRF-attacks.
  266.  
  267. It has become a tradition, consider how to write your
  268. own components. From a programmer's standpoint, it's just
  269. Class Python, having a number of methods called Django at some point in time. The first is the constructor
  270. __init__ (self), registering the components in the system. Next are the methods of determining the order of the code:
  271. * Process_request () - runs after the request, but before Django will look for the requested address in the URL-maps;
  272. * Process_view () - work out when the concrete representation is defined, but not yet started;
  273. * Process_response () - runs after the presentation.
  274. Used to compress the generated HTML.
  275. process_exception () - called when something goes wrong or
  276. were instituted an unhandled exception.
  277.  
  278. That is, in essence, that's all. But no - look at the sidebar and
  279. away, away, away, read the documentation or the free
  280. a book about Django - Django Book (http://www.djangobook.com); if you
  281. 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!
  282.  
  283. {{Box | center |
  284. | Title =, etc., etc., other ...
  285. | Table of Contents = Over four lessons, we had to consider almost all possible
  286. Django, but something is left out ...
  287. *, E-mail
  288. Django offers a high-level API to send a message to
  289. one action:
  290. <source lang="python"> from django.core.mail import send_mail
  291. send_mail ('Subject', 'message.', 'from@example.com', ['to@example.com'], fail_silently = False) </ source>
  292. In addition, there is a function of mass communications, alerts, site administrators and managers, as well as working with
  293. different content (HTML, text, graphics, etc.)
  294. *; CSV and PDF
  295. Django makes it easy to create data files, Comma Separated Values ​​(CSV), as well as PDF-documents using
  296. Library ReportLab (http://www.reportlab.org/rl_toolkit.html).
  297. *, Paged
  298. When the number of objects is so large that one page is enough, have the support of a special class
  299. Paginator, who helps organize paged:
  300. <source lang="python">>>> from django.core.paginator import Paginator
  301. >>> Objects = ['django', 'python', 'mysql', 'apache']
  302. >>> P = Paginator (objects, 2)
  303. >>> Page1 = p.page (1)
  304. >>> Page1.object_list
  305. ['Django', 'python'] </ source>
  306. Since most of our objects are stored in the database,
  307. Django also offers class QuerySetPaginator, which takes no list, and many objects from the database.
  308. *; Sitemaps
  309. Want to have your site properly indexed by search
  310. machines? You need to create his map! Django will help
  311. here, and the function django.contrib.sitemaps.ping_google «cause»
  312. Google to update the index for your website.
  313. ; * Managing multiple sites
  314. One of the problems with which copes Django, is
  315. control of several similar sites on the subject of a
  316. installation. The project was originally designed as a platform for news portals, news, and one could appear
  317. on multiple resources.
  318. *; To help designers
  319. Load the module templates to help designers:
  320.  {% Load webdesign%}
  321. you get at your disposal tag {% lorem%}, with
  322. which you can display certain Latin phrase «lorem
  323. ipsum ... »to fill the template" fish. "
  324. ; * And more
  325. Django has a lot of other "goodies" that are very
  326. well described in the accompanying documentation in English
  327. language.
  328. | Width =}}
Персональные инструменты
купить
подписаться
Яндекс.Метрика