Changeset 3739
- Timestamp:
- 09/08/06 11:35:39 (2 years ago)
- Files:
-
- django/branches/multiple-db-support/AUTHORS (modified) (3 diffs)
- django/branches/multiple-db-support/django/contrib/admin/views/auth.py (modified) (3 diffs)
- django/branches/multiple-db-support/django/contrib/sitemaps/__init__.py (modified) (1 diff)
- django/branches/multiple-db-support/django/contrib/sitemaps/views.py (modified) (1 diff)
- django/branches/multiple-db-support/django/core/management.py (modified) (1 diff)
- django/branches/multiple-db-support/django/db/backends/postgresql_psycopg2/base.py (modified) (1 diff)
- django/branches/multiple-db-support/django/db/backends/sqlite3/base.py (modified) (1 diff)
- django/branches/multiple-db-support/django/db/models/related.py (modified) (1 diff)
- django/branches/multiple-db-support/django/template/defaulttags.py (modified) (2 diffs)
- django/branches/multiple-db-support/django/template/__init__.py (modified) (4 diffs)
- django/branches/multiple-db-support/django/template/loader_tags.py (modified) (1 diff)
- django/branches/multiple-db-support/django/test/client.py (modified) (4 diffs)
- django/branches/multiple-db-support/django/test/signals.py (copied) (copied from django/trunk/django/test/signals.py)
- django/branches/multiple-db-support/django/test/simple.py (modified) (3 diffs)
- django/branches/multiple-db-support/django/test/utils.py (modified) (5 diffs)
- django/branches/multiple-db-support/django/utils/functional.py (modified) (1 diff)
- django/branches/multiple-db-support/django/views/debug.py (modified) (11 diffs)
- django/branches/multiple-db-support/django/views/static.py (modified) (1 diff)
- django/branches/multiple-db-support/docs/syndication_feeds.txt (modified) (1 diff)
- django/branches/multiple-db-support/docs/templates_python.txt (modified) (1 diff)
- django/branches/multiple-db-support/docs/testing.txt (modified) (8 diffs)
- django/branches/multiple-db-support/tests/modeltests/invalid_models/models.py (modified) (2 diffs)
- django/branches/multiple-db-support/tests/modeltests/test_client (copied) (copied from django/trunk/tests/modeltests/test_client)
- django/branches/multiple-db-support/tests/modeltests/test_client/__init__.py (copied) (copied from django/trunk/tests/modeltests/test_client/__init__.py)
- django/branches/multiple-db-support/tests/modeltests/test_client/management.py (copied) (copied from django/trunk/tests/modeltests/test_client/management.py)
- django/branches/multiple-db-support/tests/modeltests/test_client/models.py (copied) (copied from django/trunk/tests/modeltests/test_client/models.py)
- django/branches/multiple-db-support/tests/modeltests/test_client/urls.py (copied) (copied from django/trunk/tests/modeltests/test_client/urls.py)
- django/branches/multiple-db-support/tests/modeltests/test_client/views.py (copied) (copied from django/trunk/tests/modeltests/test_client/views.py)
- django/branches/multiple-db-support/tests/regressiontests/templates/tests.py (modified) (8 diffs)
- django/branches/multiple-db-support/tests/regressiontests/thread_isolation/tests.py (modified) (5 diffs)
- django/branches/multiple-db-support/tests/runtests.py (modified) (3 diffs)
- django/branches/multiple-db-support/tests/templates (copied) (copied from django/trunk/tests/templates)
- django/branches/multiple-db-support/tests/templates/404.html (copied) (copied from django/trunk/tests/templates/404.html)
- django/branches/multiple-db-support/tests/templates/500.html (copied) (copied from django/trunk/tests/templates/500.html)
- django/branches/multiple-db-support/tests/templates/login.html (copied) (copied from django/trunk/tests/templates/login.html)
- django/branches/multiple-db-support/tests/urls.py (copied) (copied from django/trunk/tests/urls.py)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
django/branches/multiple-db-support/AUTHORS
r3712 r3739 105 105 Jason McBrayer <http://www.carcosa.net/jason/> 106 106 michael.mcewan@gmail.com 107 mir@noris.de108 107 mmarshall 109 108 Eric Moritz <http://eric.themoritzfamily.com/> … … 122 121 Daniel Poelzleithner <http://poelzi.org/> 123 122 J. Rademaker 123 Michael Radziej <mir@noris.de> 124 124 Brian Ray <http://brianray.chipy.org/> 125 125 rhettg@gmail.com … … 128 128 David Schein 129 129 Pete Shinners <pete@shinners.org> 130 SmileyChris <smileychris@gmail.com> 130 131 sopel 131 132 Thomas Steinacher <tom@eggdrop.ch> django/branches/multiple-db-support/django/contrib/admin/views/auth.py
r3523 r3739 1 from django.contrib.admin.views.decorators import staff_member_required 1 2 from django.contrib.auth.forms import UserCreationForm 2 3 from django.contrib.auth.models import User … … 6 7 7 8 def user_add_stage(request): 9 if not request.user.has_perm('auth.change_user'): 10 raise PermissionDenied 8 11 manipulator = UserCreationForm() 9 12 if request.method == 'POST': … … 38 41 'username_help_text': User._meta.get_field('username').help_text, 39 42 }, context_instance=template.RequestContext(request)) 43 user_add_stage = staff_member_required(user_add_stage) django/branches/multiple-db-support/django/contrib/sitemaps/__init__.py
r3712 r3739 17 17 try: 18 18 # First, try to get the "index" sitemap URL. 19 sitemap_url = urlresolvers.reverse('django.contrib.sitemap .views.index')19 sitemap_url = urlresolvers.reverse('django.contrib.sitemaps.views.index') 20 20 except urlresolvers.NoReverseMatch: 21 21 try: 22 22 # Next, try for the "global" sitemap URL. 23 sitemap_url = urlresolvers.reverse('django.contrib.sitemap .views.sitemap')23 sitemap_url = urlresolvers.reverse('django.contrib.sitemaps.views.sitemap') 24 24 except urlresolvers.NoReverseMatch: 25 25 pass django/branches/multiple-db-support/django/contrib/sitemaps/views.py
r3712 r3739 9 9 protocol = request.is_secure() and 'https' or 'http' 10 10 for section in sitemaps.keys(): 11 sitemap_url = urlresolvers.reverse('django.contrib.sitemap .views.sitemap', kwargs={'section': section})11 sitemap_url = urlresolvers.reverse('django.contrib.sitemaps.views.sitemap', kwargs={'section': section}) 12 12 sites.append('%s://%s%s' % (protocol, current_site.domain, sitemap_url)) 13 13 xml = loader.render_to_string('sitemap_index.xml', {'sitemaps': sites}) django/branches/multiple-db-support/django/core/management.py
r3712 r3739 756 756 rel_name = RelatedObject(f.rel.to, cls, f).get_accessor_name() 757 757 rel_query_name = f.related_query_name() 758 for r in rel_opts.fields: 759 if r.name == rel_name: 760 e.add(opts, "Accessor for m2m field '%s' clashes with field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name)) 761 if r.name == rel_query_name: 762 e.add(opts, "Reverse query name for m2m field '%s' clashes with field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name)) 763 for r in rel_opts.many_to_many: 764 if r.name == rel_name: 765 e.add(opts, "Accessor for m2m field '%s' clashes with m2m field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name)) 766 if r.name == rel_query_name: 767 e.add(opts, "Reverse query name for m2m field '%s' clashes with m2m field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name)) 768 for r in rel_opts.get_all_related_many_to_many_objects(): 769 if r.field is not f: 758 # If rel_name is none, there is no reverse accessor. 759 # (This only occurs for symmetrical m2m relations to self). 760 # If this is the case, there are no clashes to check for this field, as 761 # there are no reverse descriptors for this field. 762 if rel_name is not None: 763 for r in rel_opts.fields: 764 if r.name == rel_name: 765 e.add(opts, "Accessor for m2m field '%s' clashes with field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name)) 766 if r.name == rel_query_name: 767 e.add(opts, "Reverse query name for m2m field '%s' clashes with field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name)) 768 for r in rel_opts.many_to_many: 769 if r.name == rel_name: 770 e.add(opts, "Accessor for m2m field '%s' clashes with m2m field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name)) 771 if r.name == rel_query_name: 772 e.add(opts, "Reverse query name for m2m field '%s' clashes with m2m field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name)) 773 for r in rel_opts.get_all_related_many_to_many_objects(): 774 if r.field is not f: 775 if r.get_accessor_name() == rel_name: 776 e.add(opts, "Accessor for m2m field '%s' clashes with related m2m field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.get_accessor_name(), f.name)) 777 if r.get_accessor_name() == rel_query_name: 778 e.add(opts, "Reverse query name for m2m field '%s' clashes with related m2m field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.get_accessor_name(), f.name)) 779 for r in rel_opts.get_all_related_objects(): 770 780 if r.get_accessor_name() == rel_name: 771 e.add(opts, "Accessor for m2m field '%s' clashes with related m2mfield '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.get_accessor_name(), f.name))781 e.add(opts, "Accessor for m2m field '%s' clashes with related field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.get_accessor_name(), f.name)) 772 782 if r.get_accessor_name() == rel_query_name: 773 e.add(opts, "Reverse query name for m2m field '%s' clashes with related m2m field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.get_accessor_name(), f.name)) 774 for r in rel_opts.get_all_related_objects(): 775 if r.get_accessor_name() == rel_name: 776 e.add(opts, "Accessor for m2m field '%s' clashes with related field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.get_accessor_name(), f.name)) 777 if r.get_accessor_name() == rel_query_name: 778 e.add(opts, "Reverse query name for m2m field '%s' clashes with related field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.get_accessor_name(), f.name)) 783 e.add(opts, "Reverse query name for m2m field '%s' clashes with related field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.get_accessor_name(), f.name)) 779 784 780 785 # Check admin attribute. django/branches/multiple-db-support/django/db/backends/postgresql_psycopg2/base.py
r3712 r3739 70 70 return '"%s"' % name 71 71 72 def dictfetchone(cursor): 73 "Returns a row from the cursor as a dict" 74 # TODO: cursor.dictfetchone() doesn't exist in psycopg2, 75 # but no Django code uses this. Safe to remove? 76 return cursor.dictfetchone() 77 78 def dictfetchmany(cursor, number): 79 "Returns a certain number of rows from a cursor as a dict" 80 # TODO: cursor.dictfetchmany() doesn't exist in psycopg2, 81 # but no Django code uses this. Safe to remove? 82 return cursor.dictfetchmany(number) 83 84 def dictfetchall(cursor): 85 "Returns all rows from a cursor as a dict" 86 # TODO: cursor.dictfetchall() doesn't exist in psycopg2, 87 # but no Django code uses this. Safe to remove? 88 return cursor.dictfetchall() 72 dictfetchone = util.dictfetchone 73 dictfetchmany = util.dictfetchmany 74 dictfetchall = util.dictfetchall 89 75 90 76 def get_last_insert_id(cursor, table_name, pk_name): django/branches/multiple-db-support/django/db/backends/sqlite3/base.py
r3261 r3739 64 64 65 65 def close(self): 66 if self.connection is not None: 66 from django.conf import settings 67 # If database is in memory, closing the connection destroys the database. 68 # To prevent accidental data loss, ignore close requests on an in-memory db. 69 if self.connection is not None and settings.DATABASE_NAME != ":memory:": 67 70 self.connection.close() 68 71 self.connection = None django/branches/multiple-db-support/django/db/models/related.py
r3258 r3739 132 132 # but this can be overridden with the "related_name" option. 133 133 if self.field.rel.multiple: 134 # If this is a symmetrical m2m relation on self, there is no reverse accessor. 135 if getattr(self.field.rel, 'symmetrical', False) and self.model == self.parent_model: 136 return None 134 137 return self.field.rel.related_name or (self.opts.object_name.lower() + '_set') 135 138 else: django/branches/multiple-db-support/django/template/defaulttags.py
r3712 r3739 87 87 context.push() 88 88 try: 89 values = self.sequence.resolve(context )89 values = self.sequence.resolve(context, True) 90 90 except VariableDoesNotExist: 91 91 values = [] … … 213 213 214 214 def render(self, context): 215 obj_list = self.target.resolve(context )216 if obj_list == '': # target_var wasn't found in context; fail silently215 obj_list = self.target.resolve(context, True) 216 if obj_list == None: # target_var wasn't found in context; fail silently 217 217 context[self.var_name] = [] 218 218 return '' 219 219 output = [] # list of dictionaries in the format {'grouper': 'key', 'list': [list of contents]} 220 220 for obj in obj_list: 221 grouper = self.expression.resolve(Context({'var': obj}) )221 grouper = self.expression.resolve(Context({'var': obj}), True) 222 222 # TODO: Is this a sensible way to determine equality? 223 223 if output and repr(output[-1]['grouper']) == repr(grouper): django/branches/multiple-db-support/django/template/__init__.py
r3712 r3739 138 138 139 139 class Template(object): 140 def __init__(self, template_string, origin=None ):140 def __init__(self, template_string, origin=None, name='<Unknown Template>'): 141 141 "Compilation stage" 142 142 if settings.TEMPLATE_DEBUG and origin == None: … … 145 145 # came from... 146 146 self.nodelist = compile_string(template_string, origin) 147 self.name = name 147 148 148 149 def __iter__(self): … … 435 436 i += 1 436 437 if i >= len(subject): 437 raise TemplateSyntaxError, "Searching for value. Unexpected end of string in column %d: %s" % subject438 raise TemplateSyntaxError, "Searching for value. Unexpected end of string in column %d: %s" % (i, subject) 438 439 i += 1 439 440 res = subject[p:i] … … 549 550 except VariableDoesNotExist: 550 551 if ignore_failures: 551 returnNone552 obj = None 552 553 else: 553 return settings.TEMPLATE_STRING_IF_INVALID 554 if settings.TEMPLATE_STRING_IF_INVALID: 555 return settings.TEMPLATE_STRING_IF_INVALID 556 else: 557 obj = settings.TEMPLATE_STRING_IF_INVALID 554 558 for func, args in self.filters: 555 559 arg_vals = [] django/branches/multiple-db-support/django/template/loader_tags.py
r3712 r3739 52 52 raise TemplateSyntaxError, error_msg 53 53 if hasattr(parent, 'render'): 54 return parent 54 return parent # parent is a Template object 55 55 try: 56 56 source, origin = find_template_source(parent, self.template_dirs) django/branches/multiple-db-support/django/test/client.py
r3658 r3739 1 1 from cStringIO import StringIO 2 from django.contrib.admin.views.decorators import LOGIN_FORM_KEY, _encode_post_data3 2 from django.core.handlers.base import BaseHandler 4 3 from django.core.handlers.wsgi import WSGIRequest 5 4 from django.dispatch import dispatcher 6 5 from django.http import urlencode, SimpleCookie 7 from django.te mplateimport signals6 from django.test import signals 8 7 from django.utils.functional import curry 9 8 … … 97 96 """ 98 97 def __init__(self, **defaults): 99 self.handler = TestHandler()98 self.handler = ClientHandler() 100 99 self.defaults = defaults 101 100 self.cookie = SimpleCookie() … … 127 126 on_template_render = curry(store_rendered_templates, data) 128 127 dispatcher.connect(on_template_render, signal=signals.template_rendered) 129 128 130 129 response = self.handler(environ) 131 130 … … 181 180 """ 182 181 A specialized sequence of GET and POST to log into a view that 183 is protected by @login_required or a similaraccess decorator.184 185 path should be the URL of the login page, or of any page that186 is login protected.187 188 Returns True if login was successful; False if otherwise.189 """ 190 # First, GET the login page.191 # This is required to establish the session.182 is protected by a @login_required access decorator. 183 184 path should be the URL of the page that is login protected. 185 186 Returns the response from GETting the requested URL after 187 login is complete. Returns False if login process failed. 188 """ 189 # First, GET the page that is login protected. 190 # This page will redirect to the login page. 192 191 response = self.get(path) 192 if response.status_code != 302: 193 return False 194 195 login_path, data = response['Location'].split('?') 196 next = data.split('=')[1] 197 198 # Second, GET the login page; required to set up cookies 199 response = self.get(login_path, **extra) 193 200 if response.status_code != 200: 194 201 return False 195 196 # Set up the block of form data required by the login page.202 203 # Last, POST the login data. 197 204 form_data = { 198 205 'username': username, 199 206 'password': password, 200 'this_is_the_login_form': 1, 201 'post_data': _encode_post_data({LOGIN_FORM_KEY: 1}) 207 'next' : next, 202 208 } 203 response = self.post(path, data=form_data, **extra) 204 205 # login page should give response 200 (if you requested the login 206 # page specifically), or 302 (if you requested a login 207 # protected page, to which the login can redirect). 208 return response.status_code in (200,302) 209 response = self.post(login_path, data=form_data, **extra) 210 211 # Login page should 302 redirect to the originally requested page 212 if response.status_code != 302 or response['Location'] != path: 213 return False 214 215 # Since we are logged in, request the actual page again 216 return self.get(path) django/branches/multiple-db-support/django/test/simple.py
r3712 r3739 2 2 from django.conf import settings 3 3 from django.core import management 4 from django.test.utils import setup_test_environment, teardown_test_environment 4 5 from django.test.utils import create_test_db, destroy_test_db 5 6 from django.test.testcases import OutputChecker, DocTestRunner … … 52 53 will be added to the test suite. 53 54 """ 55 setup_test_environment() 54 56 55 57 settings.DEBUG = False … … 67 69 unittest.TextTestRunner(verbosity=verbosity).run(suite) 68 70 destroy_test_db(old_name, verbosity) 71 72 teardown_test_environment() django/branches/multiple-db-support/django/test/utils.py
r3712 r3739 1 1 import sys, time 2 2 from django.conf import settings 3 3 4 from django.db import backend, connect, connection, connection_info, connections 5 from django.dispatch import dispatcher 6 from django.test import signals 7 from django.template import Template 4 8 5 9 # The prefix to put on the default database name when creating … … 7 11 TEST_DATABASE_PREFIX = 'test_' 8 12 13 def instrumented_test_render(self, context): 14 """An instrumented Template render method, providing a signal 15 that can be intercepted by the test system Client 16 17 """ 18 dispatcher.send(signal=signals.template_rendered, sender=self, template=self, context=context) 19 return self.nodelist.render(context) 20 21 def setup_test_environment(): 22 """Perform any global pre-test setup. This involves: 23 24 - Installing the instrumented test renderer 25 26 """ 27 Template.original_render = Template.render 28 Template.render = instrumented_test_render 29 30 def teardown_test_environment(): 31 """Perform any global post-test teardown. This involves: 32 33 - Restoring the original test renderer 34 35 """ 36 Template.render = Template.original_render 37 del Template.original_render 38 9 39 def _set_autocommit(connection): 10 40 "Make sure a connection is in autocommit mode." … … 56 86 print "Tests cancelled." 57 87 sys.exit(1) 58 # Close the old connection 59 connection.close() 88 89 connection.close() 90 settings.DATABASE_NAME = TEST_DATABASE_NAME 60 91 61 # Get a cursor (even though we don't need one yet). This has62 # the side effect of initializing the test database.63 cursor = connection.cursor()92 # Get a cursor (even though we don't need one yet). This has 93 # the side effect of initializing the test database. 94 cursor = connection.cursor() 64 95 65 96 # Fill OTHER_DATABASES with the TEST_DATABASES settings, … … 88 119 if verbosity >= 1: 89 120 print "Destroying test database..." 90 if settings.DATABASE_ENGINE != "sqlite3": 91 connection.close() 92 TEST_DATABASE_NAME = settings.DATABASE_NAME 93 settings.DATABASE_NAME = old_database_name 121 connection.close() 122 TEST_DATABASE_NAME = settings.DATABASE_NAME 123 settings.DATABASE_NAME = old_database_name 124 125 if settings.DATABASE_ENGINE != "sqlite3": 94 126 settings.OTHER_DATABASES = old_databases 95 127 cursor = connection.cursor() … … 98 130 cursor.execute("DROP DATABASE %s" % backend.quote_name(TEST_DATABASE_NAME)) 99 131 connection.close() 100 101 django/branches/multiple-db-support/django/utils/functional.py
r2809 r3739 1 def curry( *args, **kwargs):1 def curry(_curried_func, *args, **kwargs): 2 2 def _curried(*moreargs, **morekwargs): 3 return args[0](*(args[1:]+moreargs), **dict(kwargs.items() + morekwargs.items()))3 return _curried_func(*(args+moreargs), **dict(kwargs, **morekwargs)) 4 4 return _curried 5 5 django/branches/multiple-db-support/django/views/debug.py
r3712 r3739 116 116 'lineno': '?', 117 117 }] 118 t = Template(TECHNICAL_500_TEMPLATE )118 t = Template(TECHNICAL_500_TEMPLATE, name='Technical 500 template') 119 119 c = Context({ 120 120 'exception_type': exc_type.__name__, … … 142 142 return empty_urlconf(request) 143 143 144 t = Template(TECHNICAL_404_TEMPLATE )144 t = Template(TECHNICAL_404_TEMPLATE, name='Technical 404 template') 145 145 c = Context({ 146 146 'root_urlconf': settings.ROOT_URLCONF, … … 155 155 def empty_urlconf(request): 156 156 "Create an empty URLconf 404 error response." 157 t = Template(EMPTY_URLCONF_TEMPLATE )157 t = Template(EMPTY_URLCONF_TEMPLATE, name='Empty URLConf template') 158 158 c = Context({ 159 159 'project_name': settings.SETTINGS_MODULE.split('.')[0] … … 190 190 <meta http-equiv="content-type" content="text/html; charset=utf-8" /> 191 191 <meta name="robots" content="NONE,NOARCHIVE" /> 192 <title>{{ exception_type }} at {{ request.path }}</title>192 <title>{{ exception_type }} at {{ request.path|escape }}</title> 193 193 <style type="text/css"> 194 194 html * { padding:0; margin:0; } … … 293 293 294 294 <div id="summary"> 295 <h1>{{ exception_type }} at {{ request.path }}</h1>295 <h1>{{ exception_type }} at {{ request.path|escape }}</h1> 296 296 <h2>{{ exception_value|escape }}</h2> 297 297 <table class="meta"> … … 302 302 <tr> 303 303 <th>Request URL:</th> 304 <td>{{ request_protocol }}://{{ request.META.HTTP_HOST }}{{ request.path }}</td>304 <td>{{ request_protocol }}://{{ request.META.HTTP_HOST }}{{ request.path|escape }}</td> 305 305 </tr> 306 306 <tr> … … 310 310 <tr> 311 311 <th>Exception Value:</th> 312 <td>{{ exception_value }}</td>312 <td>{{ exception_value|escape }}</td> 313 313 </tr> 314 314 <tr> … … 413 413 {% endif %} 414 414 {% endfor %}<br/> 415 {{ exception_type }} at {{ request.path }}<br/>415 {{ exception_type }} at {{ request.path|escape }}<br/> 416 416 {{ exception_value|escape }}</code> 417 417 </td> … … 547 547 <head> 548 548 <meta http-equiv="content-type" content="text/html; charset=utf-8" /> 549 <title>Page not found at {{ request.path }}</title>549 <title>Page not found at {{ request.path|escape }}</title> 550 550 <meta name="robots" content="NONE,NOARCHIVE" /> 551 551 <style type="text/css"> … … 577 577 <tr> 578 578 <th>Request URL:</th> 579 <td>{{ request_protocol }}://{{ request.META.HTTP_HOST }}{{ request.path }}</td>579 <td>{{ request_protocol }}://{{ request.META.HTTP_HOST }}{{ request.path|escape }}</td> 580 580 </tr> 581 581 </table> … … 592 592 {% endfor %} 593 593 </ol> 594 <p>The current URL, <code>{{ request.path }}</code>, didn't match any of these.</p>594 <p>The current URL, <code>{{ request.path|escape }}</code>, didn't match any of these.</p> 595 595 {% else %} 596 596 <p>{{ reason|escape }}</p> django/branches/multiple-db-support/django/views/static.py
r3712 r3739 82 82 t = loader.get_template('static/directory_index') 83 83 except TemplateDoesNotExist: 84 t = Template(DEFAULT_DIRECTORY_INDEX_TEMPLATE )84 t = Template(DEFAULT_DIRECTORY_INDEX_TEMPLATE, name='Default directory index template') 85 85 files = [] 86 86 for f in os.listdir(fullpath): django/branches/multiple-db-support/docs/syndication_feeds.txt
r3502 r3739 708 708 ... link=u"http://www.example.com/", 709 709 ... description=u"In which I write about what I ate today.", 710 ... language=u"en") ,710 ... language=u"en") 711 711 >>> f.add_item(title=u"Hot dog today", 712 712 ... link=u"http://www.example.com/entries/1/", django/branches/multiple-db-support/docs/templates_python.txt
r3712 r3739 199 199 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 200 200 201 If a variable doesn't exist, the template system inserts the value of the 202 ``TEMPLATE_STRING_IF_INVALID`` setting, which is set to ``''`` (the empty 203 string) by default. 201 Generally, if a variable doesn't exist, the template system inserts the 202 value of the ``TEMPLATE_STRING_IF_INVALID`` setting, which is set to ``''`` 203 (the empty string) by default. 204 205 Filters that are applied to an invalid variable will only be applied if 206 ``TEMPLATE_STRING_IF_INVALID`` is set to ``''`` (the empty string). If 207 ``TEMPLATE_STRING_IF_INVALID`` is set to any other value, variable 208 filters will be ignored. 209 210 This behavior is slightly different for the ``if``, ``for`` and ``regroup`` 211 template tags. If an invalid variable is provided to one of these template 212 tags, the variable will be interpreted as ``None``. Filters are always 213 applied to invalid variables within these template tags. 204 214 205 215 Playing with Context objects django/branches/multiple-db-support/docs/testing.txt
r3712 r3739 93 93 Like doctests, Django's unit tests use a standard library module: unittest_. 94 94 As with doctests, Django's test runner looks for any unit test cases defined 95 in ``models.py``, or in a ``tests.py`` file in your application directory. 95 in ``models.py``, or in a ``tests.py`` file stored in the application 96 directory. 96 97 97 98 An equivalent unittest test case for the above example would look like:: … … 111 112 112 113 When you `run your tests`_, the test utility will find all the test cases 113 (that is, subclasses of ``unittest.TestCase``) in ``tests.py``, automatically 114 build a test suite out of those test cases, and run that suite. 114 (that is, subclasses of ``unittest.TestCase``) in ``models.py`` and 115 ``tests.py``, automatically build a test suite out of those test cases, 116 and run that suite. 115 117 116 118 For more details about ``unittest``, see the `standard library unittest … … 160 162 in different circumstances. 161 163 162 Testing utilities 163 ================= 164 164 Testing Tools 165 ============= 166 167 To assist in testing various features of your application, Django provides 168 tools that can be used to establish tests and test conditions. 169 170 * `Test Client`_ 171 * Fixtures_ 172 165 173 Test Client 166 174 ----------- 167 175 168 A dummy browser; instruments the template generation process... 176 The Test Client is a simple dummy browser. It allows you to simulate 177 GET and POST requests on a URL, and observe the response that is received. 178 This allows you to test that the correct view is executed for a given URL, 179 and that the view constructs the correct response. 180 181 As the response is generated, the Test Client gathers details on the 182 Template and Context objects that were used to generate the response. These 183 Templates and Contexts are then provided as part of the response, and can be 184 used as test conditions. 185 186 .. admonition:: Test Client vs Browser Automation? 187 188 The Test Client is not intended as a replacement for Twill_, Selenium_, 189 or other browser automation frameworks - it is intended to allow 190 testing of the contexts and templates produced by a view, 191 rather than the HTML rendered to the end-user. 192 193 A comprehensive test suite should use a combination of both: Test Client 194 tests to establish that the correct view is being called and that 195 the view is collecting the correct context data, and Browser Automation 196 tests to check that user interface behaves as expected. 197 198 .. _Twill: http://twill.idyll.org/ 199 .. _Selenium: http://www.openqa.org/selenium/ 200 201 The Test Client is stateful; if a cookie is returned as part of a response, 202 that cookie is provided as part of the next request issued to that Client 203 instance. Expiry policies for these cookies are not followed; if you want 204 a cookie to expire, either delete it manually from ``client.cookies``, or 205 create a new Client instance (which will effectively delete all cookies). 206 207 Making requests 208 ~~~~~~~~~~~~~~~ 209 210 Creating an instance of ``Client`` (``django.test.client.Client``) requires 211 no arguments at time of construction. Once constructed, the following methods 212 can be invoked on the ``Client`` instance. 213 214 ``get(path, data={})`` 215 Make a GET request on the provided ``path``. The key-value pairs in the 216 data dictionary will be used to create a GET data payload. For example:: 217 218 c = Client() 219 c.get('/customers/details/', {'name':'fred', 'age':7}) 220 221 will result in the evaluation of a GET request equivalent to:: 222 223 http://yoursite.com/customers/details/?name='fred'&age=7 224 225 ``post(path, data={})`` 226 Make a POST request on the provided ``path``. The key-value pairs in the 227 data dictionary will be used to create the POST data payload. This payload 228 will be transmitted with the mimetype ``multipart/form-data``. 229 230 However submitting files is a special case. To POST a file, you need only 231 provide the file field name as a key, and a file handle to the file you wish to 232 upload as a value. The Test Client will populate the two POST fields (i.e., 233 ``field`` and ``field_file``) required by FileField. For example:: 234 235 c = Client() 236 f = open('wishlist.doc') 237 c.post('/customers/wishes/', {'name':'fred', 'attachment':f}) 238 f.close() 239 240 will result in the evaluation of a POST request on ``/customers/wishes/``, 241 with a POST dictionary that contains `name`, `attachment` (containing the 242 file name), and `attachment_file` (containing the file data). Note that you 243 need to manually close the file after it has been provided to the POST. 244 245 ``login(path, username, password)`` 246 In a production site, it is likely that some views will be protected with 247 the @login_required URL provided by ``django.contrib.auth``. Interacting 248 with a URL that has been login protected is a slightly complex operation, 249 so the Test Client provides a simple URL to automate the login process. A 250 call to ``login()`` stimulates the series of GET and POST calls required 251 to log a user into a @login_required protected URL. 252 253 If login is possible, the final return value of ``login()`` is the response 254 that is generated by issuing a GET request on the protected URL. If login 255 is not possible, ``login()`` returns False. 256 257 Note that since the test suite will be executed using the test database, 258 which contains no users by default. As a result, logins for your production 259 site will not work. You will need to create users as part of the test suite 260 to be able to test logins to your application. 261 262 Testing Responses 263 ~~~~~~~~~~~~~~~~~ 264 265 The ``get()``, ``post()`` and ``login()`` methods all return a Response 266 object. This Response object has the following properties that can be used 267 for testing purposes: 268 269 =============== ========================================================== 270 Property Description 271 =============== ========================================================== 272 ``status_code`` The HTTP status of the response. See RFC2616_ for a 273 full list of HTTP status codes. 274 275 ``content`` The body of the response. The is the final page 276 content as rendered by the view, or any error message 277 (such as the URL for a 302 redirect). 278 279 ``template`` The Template instance that was used to render the final 280 content. Testing ``template.name`` can be particularly 281 useful; if the template was loaded from a file, 282 ``template.name`` will be the file name that was loaded. 283 284 If multiple templates were rendered, (e.g., if one 285 template includes another template),``template`` will 286 be a list of Template objects, in the order in which 287 they were rendered. 288 289 ``context`` The Context that was used to render the template that 290 produced the response content. 291 292 As with ``template``, if multiple templates were rendered 293 ``context`` will be a list of Context objects, stored in 294 the order in which they were rendered. 295 =============== ========================================================== 296 297 .. _RFC2616: http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html 298 299 The following is a simple unit test using the Test Client:: 300 301
