diff options
Diffstat (limited to 'docs')
| -rw-r--r-- | docs/add_ons.txt | 9 | ||||
| -rw-r--r-- | docs/model-api.txt | 38 | ||||
| -rw-r--r-- | docs/newforms.txt | 47 | ||||
| -rw-r--r-- | docs/request_response.txt | 115 | ||||
| -rw-r--r-- | docs/testing.txt | 135 |
5 files changed, 267 insertions, 77 deletions
diff --git a/docs/add_ons.txt b/docs/add_ons.txt index d937eb2141..1756fe5720 100644 --- a/docs/add_ons.txt +++ b/docs/add_ons.txt @@ -139,6 +139,15 @@ See the `flatpages documentation`_. .. _flatpages documentation: ../flatpages/ +localflavor +=========== + +**New in Django development version** + +A collection of various Django snippets that are useful only for a particular +country or culture. For example, ``django.contrib.localflavor.usa.forms`` +contains a ``USZipCodeField`` that you can use to validate U.S. zip codes. + markup ====== diff --git a/docs/model-api.txt b/docs/model-api.txt index 8abd88f7ec..0a10918d54 100644 --- a/docs/model-api.txt +++ b/docs/model-api.txt @@ -874,8 +874,8 @@ the relationship should work. All are optional: force Django to add the descriptor for the reverse relationship, allowing ``ManyToMany`` relationships to be non-symmetrical. - - ``db_table`` The name of the table to create for storing the many-to-many + + ``db_table`` The name of the table to create for storing the many-to-many data. If this is not provided, Django will assume a default name based upon the names of the two tables being joined. @@ -1272,8 +1272,8 @@ A few special cases to note about ``list_display``: return '<span style="color: #%s;">%s %s</span>' % (self.color_code, self.first_name, self.last_name) colored_name.allow_tags = True - * If the string given is a method of the model that returns True or False - Django will display a pretty "on" or "off" icon if you give the method a + * If the string given is a method of the model that returns True or False + Django will display a pretty "on" or "off" icon if you give the method a ``boolean`` attribute whose value is ``True``. Here's a full example model:: @@ -1412,7 +1412,7 @@ This should be set to a list of field names that will be searched whenever somebody submits a search query in that text box. These fields should be some kind of text field, such as ``CharField`` or -``TextField``. You can also perform a related lookup on a ``ForeignKey`` with +``TextField``. You can also perform a related lookup on a ``ForeignKey`` with the lookup API "follow" notation:: search_fields = ['foreign_key__related_fieldname'] @@ -1721,11 +1721,29 @@ But this template code is good:: <a href="{{ object.get_absolute_url }}">{{ object.name }}</a> -(Yes, we know ``get_absolute_url()`` couples URLs to models, which violates the -DRY principle, because URLs are defined both in a URLconf and in the model. -This is a rare case in which we've intentionally violated that principle for -the sake of convenience. With that said, we're working on an even cleaner way -of specifying URLs in a more DRY fashion.) +The ``permalink`` decorator +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**New in Django development version.** + +The problem with the way we wrote ``get_absolute_url()`` above is that it +slightly violates the DRY principle: the URL for this object is defined both +in the URLConf file and in the model. + +You can further decouple your models from the URLconf using the ``permalink`` +decorator. This decorator is passed the view function and any parameters you +would use for accessing this instance directly. Django then works out the +correct full URL path using the URLconf. For example:: + + from django.db.models import permalink + + def get_absolute_url(self): + return ('people.views.details', str(self.id)) + get_absolute_url = permalink(get_absolute_url) + +In this way, you're tying the model's absolute URL to the view that is used +to display it, without repeating the URL information anywhere. You can still +use the ``get_absolute_url`` method in templates, as before. Executing custom SQL -------------------- diff --git a/docs/newforms.txt b/docs/newforms.txt index 063f686ed5..33aaf14357 100644 --- a/docs/newforms.txt +++ b/docs/newforms.txt @@ -51,9 +51,10 @@ too messy. The choice is yours. Overview ======== -As with the ``django.forms`` ("manipulators") system before it, ``django.newforms`` -is intended to handle HTML form display, validation and redisplay. It's what -you use if you want to perform server-side validation for an HTML form. +As with the ``django.forms`` ("manipulators") system before it, +``django.newforms`` is intended to handle HTML form display, data processing +(validation) and redisplay. It's what you use if you want to perform +server-side validation for an HTML form. For example, if your Web site has a contact form that visitors can use to send you e-mail, you'd use this library to implement the display of the HTML @@ -571,6 +572,46 @@ is a list-like object that is displayed as an HTML ``<ul>`` when printed:: >>> str(f['subject'].errors) '' +Subclassing forms +----------------- + +If you subclass a custom ``Form`` class, the resulting ``Form`` class will +include all fields of the parent class(es), followed by the fields you define +in the subclass. + +In this example, ``ContactFormWithPriority`` contains all the fields from +``ContactForm``, plus an additional field, ``priority``. The ``ContactForm`` +fields are ordered first:: + + >>> class ContactFormWithPriority(ContactForm): + ... priority = forms.CharField() + >>> f = ContactFormWithPriority(auto_id=False) + >>> print f.as_ul() + <li>Subject: <input type="text" name="subject" maxlength="100" /></li> + <li>Message: <input type="text" name="message" /></li> + <li>Sender: <input type="text" name="sender" /></li> + <li>Cc myself: <input type="checkbox" name="cc_myself" /></li> + <li>Priority: <input type="text" name="priority" /></li> + +It's possible to subclass multiple forms, treating forms as "mix-ins." In this +example, ``BeatleForm`` subclasses both ``PersonForm`` and ``InstrumentForm`` +(in that order), and its field list includes the fields from the parent +classes:: + + >>> class PersonForm(Form): + ... first_name = CharField() + ... last_name = CharField() + >>> class InstrumentForm(Form): + ... instrument = CharField() + >>> class BeatleForm(PersonForm, InstrumentForm): + ... haircut_type = CharField() + >>> b = BeatleForm(auto_id=False) + >>> print b.as_ul() + <li>First name: <input type="text" name="first_name" /></li> + <li>Last name: <input type="text" name="last_name" /></li> + <li>Instrument: <input type="text" name="instrument" /></li> + <li>Haircut type: <input type="text" name="haircut_type" /></li> + Fields ====== diff --git a/docs/request_response.txt b/docs/request_response.txt index afea0bcd53..6dfe78a686 100644 --- a/docs/request_response.txt +++ b/docs/request_response.txt @@ -432,3 +432,118 @@ types of HTTP responses. Like ``HttpResponse``, these subclasses live in ``HttpResponseServerError`` Acts just like ``HttpResponse`` but uses a 500 status code. + +Returning errors +================ + +Returning HTTP error codes in Django is easy. We've already mentioned the +``HttpResponseNotFound``, ``HttpResponseForbidden``, +``HttpResponseServerError``, etc., subclasses; just return an instance of one +of those subclasses instead of a normal ``HttpResponse`` in order to signify +an error. For example:: + + def my_view(request): + # ... + if foo: + return HttpResponseNotFound('<h1>Page not found</h1>') + else: + return HttpResponse('<h1>Page was found</h1>') + +Because 404 errors are by far the most common HTTP error, there's an easier way +to handle those errors. + +The Http404 exception +--------------------- + +When you return an error such as ``HttpResponseNotFound``, you're responsible +for defining the HTML of the resulting error page:: + + return HttpResponseNotFound('<h1>Page not found</h1>') + +For convenience, and because it's a good idea to have a consistent 404 error page +across your site, Django provides an ``Http404`` exception. If you raise +``Http404`` at any point in a view function, Django will catch it and return the +standard error page for your application, along with an HTTP error code 404. + +Example usage:: + + from django.http import Http404 + + def detail(request, poll_id): + try: + p = Poll.objects.get(pk=poll_id) + except Poll.DoesNotExist: + raise Http404 + return render_to_response('polls/detail.html', {'poll': p}) + +In order to use the ``Http404`` exception to its fullest, you should create a +template that is displayed when a 404 error is raised. This template should be +called ``404.html`` and located in the top level of your template tree. + +Customing error views +--------------------- + +The 404 (page not found) view +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +When you raise an ``Http404`` exception, Django loads a special view devoted +to handling 404 errors. By default, it's the view +``django.views.defaults.page_not_found``, which loads and renders the template +``404.html``. + +This means you need to define a ``404.html`` template in your root template +directory. This template will be used for all 404 errors. + +This ``page_not_found`` view should suffice for 99% of Web applications, but if +you want to override the 404 view, you can specify ``handler404`` in your +URLconf, like so:: + + handler404 = 'mysite.views.my_custom_404_view' + +Behind the scenes, Django determines the 404 view by looking for ``handler404``. +By default, URLconfs contain the following line:: + + from django.conf.urls.defaults import * + +That takes care of setting ``handler404`` in the current module. As you can see +in ``django/conf/urls/defaults.py``, ``handler404`` is set to +``'django.views.defaults.page_not_found'`` by default. + +Three things to note about 404 views: + + * The 404 view is also called if Django doesn't find a match after checking + every regular expression in the URLconf. + + * If you don't define your own 404 view -- and simply use the default, + which is recommended -- you still have one obligation: To create a + ``404.html`` template in the root of your template directory. The default + 404 view will use that template for all 404 errors. + + * If ``DEBUG`` is set to ``True`` (in your settings module) then your 404 + view will never be used, and the traceback will be displayed instead. + +The 500 (server error) view +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Similarly, Django executes special-case behavior in the case of runtime errors +in view code. If a view results in an exception, Django will, by default, call +the view ``django.views.defaults.server_error``, which loads and renders the +template ``500.html``. + +This means you need to define a ``500.html`` template in your root template +directory. This template will be used for all server errors. + +This ``server_error`` view should suffice for 99% of Web applications, but if +you want to override the view, you can specify ``handler500`` in your +URLconf, like so:: + + handler500 = 'mysite.views.my_custom_error_view' + +Behind the scenes, Django determines the error view by looking for ``handler500``. +By default, URLconfs contain the following line:: + + from django.conf.urls.defaults import * + +That takes care of setting ``handler500`` in the current module. As you can see +in ``django/conf/urls/defaults.py``, ``handler500`` is set to +``'django.views.defaults.server_error'`` by default. diff --git a/docs/testing.txt b/docs/testing.txt index cab31ed63b..33014723cd 100644 --- a/docs/testing.txt +++ b/docs/testing.txt @@ -92,7 +92,7 @@ Writing unittests Like doctests, Django's unit tests use a standard library module: unittest_. As with doctests, Django's test runner looks for any unit test cases defined -in ``models.py``, or in a ``tests.py`` file stored in the application +in ``models.py``, or in a ``tests.py`` file stored in the application directory. An equivalent unittest test case for the above example would look like:: @@ -111,8 +111,8 @@ An equivalent unittest test case for the above example would look like:: self.assertEquals(self.cat.speak(), 'The cat says "meow"') When you `run your tests`_, the test utility will find all the test cases -(that is, subclasses of ``unittest.TestCase``) in ``models.py`` and -``tests.py``, automatically build a test suite out of those test cases, +(that is, subclasses of ``unittest.TestCase``) in ``models.py`` and +``tests.py``, automatically build a test suite out of those test cases, and run that suite. For more details about ``unittest``, see the `standard library unittest @@ -164,12 +164,12 @@ in different circumstances. Testing Tools ============= -To assist in testing various features of your application, Django provides +To assist in testing various features of your application, Django provides tools that can be used to establish tests and test conditions. * `Test Client`_ * Fixtures_ - + Test Client ----------- @@ -178,23 +178,23 @@ GET and POST requests on a URL, and observe the response that is received. This allows you to test that the correct view is executed for a given URL, and that the view constructs the correct response. -As the response is generated, the Test Client gathers details on the +As the response is generated, the Test Client gathers details on the Template and Context objects that were used to generate the response. These Templates and Contexts are then provided as part of the response, and can be used as test conditions. .. admonition:: Test Client vs Browser Automation? - The Test Client is not intended as a replacement for Twill_, Selenium_, - or other browser automation frameworks - it is intended to allow - testing of the contexts and templates produced by a view, + The Test Client is not intended as a replacement for Twill_, Selenium_, + or other browser automation frameworks - it is intended to allow + testing of the contexts and templates produced by a view, rather than the HTML rendered to the end-user. - + A comprehensive test suite should use a combination of both: Test Client - tests to establish that the correct view is being called and that + tests to establish that the correct view is being called and that the view is collecting the correct context data, and Browser Automation tests to check that user interface behaves as expected. - + .. _Twill: http://twill.idyll.org/ .. _Selenium: http://www.openqa.org/selenium/ @@ -202,7 +202,7 @@ used as test conditions. Making requests ~~~~~~~~~~~~~~~ -Creating an instance of ``Client`` (``django.test.client.Client``) requires +Creating an instance of ``Client`` (``django.test.client.Client``) requires no arguments at time of construction. Once constructed, the following methods can be invoked on the ``Client`` instance. @@ -217,23 +217,29 @@ can be invoked on the ``Client`` instance. http://yoursite.com/customers/details/?name=fred&age=7 -``post(path, data={})`` - Make a POST request on the provided ``path``. The key-value pairs in the - data dictionary will be used to create the POST data payload. This payload - will be transmitted with the mimetype ``multipart/form-data``. - - However submitting files is a special case. To POST a file, you need only - provide the file field name as a key, and a file handle to the file you wish to - upload as a value. The Test Client will populate the two POST fields (i.e., - ``field`` and ``field_file``) required by FileField. For example:: +``post(path, data={}, content_type=MULTIPART_CONTENT)`` + Make a POST request on the provided ``path``. If you provide a content type + (e.g., ``text/xml`` for an XML payload), the contents of ``data`` will be + sent as-is in the POST request, using the content type in the HTTP + ``Content-Type`` header. + + If you do not provide a value for ``content_type``, the values in + ``data`` will be transmitted with a content type of ``multipart/form-data``. + The key-value pairs in the data dictionary will be encoded as a multipart + message and used to create the POST data payload. + + Submitting files is a special case. To POST a file, you need only + provide the file field name as a key, and a file handle to the file you wish to + upload as a value. The Test Client will populate the two POST fields (i.e., + ``field`` and ``field_file``) required by Django's FileField. For example:: c = Client() f = open('wishlist.doc') c.post('/customers/wishes/', {'name':'fred', 'attachment':f}) f.close() - will result in the evaluation of a POST request on ``/customers/wishes/``, - with a POST dictionary that contains `name`, `attachment` (containing the + will result in the evaluation of a POST request on ``/customers/wishes/``, + with a POST dictionary that contains `name`, `attachment` (containing the file name), and `attachment_file` (containing the file data). Note that you need to manually close the file after it has been provided to the POST. @@ -245,48 +251,48 @@ can be invoked on the ``Client`` instance. call to ``login()`` stimulates the series of GET and POST calls required to log a user into a @login_required protected view. - If login is possible, the final return value of ``login()`` is the response + If login is possible, the final return value of ``login()`` is the response that is generated by issuing a GET request on the protected URL. If login is not possible, ``login()`` returns False. - Note that since the test suite will be executed using the test database, + Note that since the test suite will be executed using the test database, which contains no users by default. As a result, logins for your production - site will not work. You will need to create users as part of the test suite - to be able to test logins to your application. + site will not work. You will need to create users as part of the test suite + to be able to test logins to your application. Testing Responses ~~~~~~~~~~~~~~~~~ -The ``get()``, ``post()`` and ``login()`` methods all return a Response -object. This Response object has the following properties that can be used +The ``get()``, ``post()`` and ``login()`` methods all return a Response +object. This Response object has the following properties that can be used for testing purposes: =============== ========================================================== Property Description =============== ========================================================== - ``status_code`` The HTTP status of the response. See RFC2616_ for a + ``status_code`` The HTTP status of the response. See RFC2616_ for a full list of HTTP status codes. - ``content`` The body of the response. The is the final page - content as rendered by the view, or any error message + ``content`` The body of the response. The is the final page + content as rendered by the view, or any error message (such as the URL for a 302 redirect). - ``template`` The Template instance that was used to render the final - content. Testing ``template.name`` can be particularly - useful; if the template was loaded from a file, - ``template.name`` will be the file name that was loaded. + ``template`` The Template instance that was used to render the final + content. Testing ``template.name`` can be particularly + useful; if the template was loaded from a file, + ``template.name`` will be the file name that was loaded. - If multiple templates were rendered, (e.g., if one - template includes another template),``template`` will - be a list of Template objects, in the order in which + If multiple templates were rendered, (e.g., if one + template includes another template),``template`` will + be a list of Template objects, in the order in which they were rendered. - ``context`` The Context that was used to render the template that + ``context`` The Context that was used to render the template that produced the response content. - As with ``template``, if multiple templates were rendered - ``context`` will be a list of Context objects, stored in - the order in which they were rendered. + As with ``template``, if multiple templates were rendered + ``context`` will be a list of Context objects, stored in + the order in which they were rendered. =============== ========================================================== .. _RFC2616: http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html @@ -295,11 +301,11 @@ Exceptions ~~~~~~~~~~ If you point the Test Client at a view that raises an exception, that exception -will be visible in the test case. You can then use a standard ``try...catch`` +will be visible in the test case. You can then use a standard ``try...catch`` block, or ``unittest.TestCase.assertRaises()`` to test for exceptions. -The only exceptions that are not visible in a Test Case are ``Http404``, -``PermissionDenied`` and ``SystemExit``. Django catches these exceptions +The only exceptions that are not visible in a Test Case are ``Http404``, +``PermissionDenied`` and ``SystemExit``. Django catches these exceptions internally and converts them into the appropriate HTTP responses codes. Persistent state @@ -307,8 +313,8 @@ Persistent state The Test Client is stateful; if a cookie is returned as part of a response, that cookie is provided as part of the next request issued by that Client -instance. Expiry policies for these cookies are not followed; if you want -a cookie to expire, either delete it manually or create a new Client +instance. Expiry policies for these cookies are not followed; if you want +a cookie to expire, either delete it manually or create a new Client instance (which will effectively delete all cookies). There are two properties of the Test Client which are used to store persistent @@ -323,25 +329,26 @@ part of a test condition. ``session`` A dictionary-like object containing session information. See the `session documentation`_ for full details. + =============== ========================================================== .. _`session documentation`: ../sessions/ - + Example ~~~~~~~ The following is a simple unit test using the Test Client:: - + import unittest from django.test.client import Client - + class SimpleTest(unittest.TestCase): def setUp(self): # Every test needs a client self.client = Client() - def test_details(self): + def test_details(self): # Issue a GET request response = self.client.get('/customer/details/') - + # Check that the respose is 200 OK self.failUnlessEqual(response.status_code, 200) # Check that the rendered context contains 5 customers @@ -368,13 +375,13 @@ but you only want to run the animals unit tests, run:: When you run your tests, you'll see a bunch of text flow by as the test database is created and models are initialized. This test database is -created from scratch every time you run your tests. +created from scratch every time you run your tests. -By default, the test database gets its name by prepending ``test_`` to -the database name specified by the ``DATABASE_NAME`` setting; all other +By default, the test database gets its name by prepending ``test_`` to +the database name specified by the ``DATABASE_NAME`` setting; all other database settings will the same as they would be for the project normally. -If you wish to use a name other than the default for the test database, -you can use the ``TEST_DATABASE_NAME`` setting to provide a name. +If you wish to use a name other than the default for the test database, +you can use the ``TEST_DATABASE_NAME`` setting to provide a name. Once the test database has been established, Django will run your tests. If everything goes well, at the end you'll see:: @@ -447,7 +454,7 @@ arguments: The module list is the list of Python modules that contain the models to be tested. This is the same format returned by ``django.db.models.get_apps()`` - Verbosity determines the amount of notification and debug information that + Verbosity determines the amount of notification and debug information that will be printed to the console; `0` is no output, `1` is normal output, and `2` is verbose output. @@ -458,12 +465,12 @@ To assist in the creation of your own test runner, Django provides a number of utility methods in the ``django.test.utils`` module. ``setup_test_environment()`` - Performs any global pre-test setup, such as the installing the - instrumentation of the template rendering system. + Performs any global pre-test setup, such as the installing the + instrumentation of the template rendering system. ``teardown_test_environment()`` - Performs any global post-test teardown, such as removing the instrumentation - of the template rendering system. + Performs any global post-test teardown, such as removing the instrumentation + of the template rendering system. ``create_test_db(verbosity=1, autoclobber=False)`` Creates a new test database, and run ``syncdb`` against it. |
