Anonymous committed 0a03669

[multi-db] Merge trunk to [3875]. Some tests still failing.

Comments (0)

Files changed (22)

     Ian Clelland <>
     Matt Croydon <>
     Jonathan Daugherty (cygnus) <>
     Jason Davies (Esaj) <>
     Alex Dedul
     Eugene Lazutkin <>
     Jeong-Min Lee
     Christopher Lenz <>
+    mattmcc
     Martin Maney <>
     Petar Marić
     Eric Moritz <>
     Robin Munn <>
     Nebojša Dorđević
+    Fraser Nevett <>
     Sam Newman <>
     Neal Norwitz <>
     oggie rob <>
     Radek Švarz <>
     Swaroop C H <>
     Aaron Swartz <>
+    Tyson Tate <>
     Tom Tobin
     Tom Insam
     Joe Topjian <>


-"Daily cleanup file"
+Daily cleanup job.
+Can be run as a cronjob to clean out old data from the database (only expired
+sessions at the moment).
 from django.db import backend, connection, transaction
-DOCUMENTATION_DIRECTORY = '/home/html/documentation/'
 def clean_up():
     # Clean up old database records
     cursor = connection.cursor()
     cursor.execute("DELETE FROM %s WHERE %s < NOW()" % \
-        (backend.quote_name('core_sessions'), backend.quote_name('expire_date')))
-    cursor.execute("DELETE FROM %s WHERE %s < NOW() - INTERVAL '1 week'" % \
-        (backend.quote_name('registration_challenges'), backend.quote_name('request_date')))
+        (backend.quote_name('django_session'), backend.quote_name('expire_date')))
 if __name__ == "__main__":


 <h1>{{ name }}</h1>
-<h2 class="subhead">{{ summary|escape }}</h2>
+<h2 class="subhead">{{ summary }}</h2>
 <p>{{ body }}</p>


             if not username.isalnum():
                 sys.stderr.write("Error: That username is invalid. Use only letters, digits and underscores.\n")
                 username = None
+                continue
             except User.DoesNotExist:


 from django.template import Context, loader
 from django.core import validators
 from django import forms
-from django.utils.translation import gettext_lazy as _
 class UserCreationForm(forms.Manipulator):
     "A form that creates a user, with no privileges, from the given username and password."


 <?xml version="1.0" encoding="UTF-8"?>
 <urlset xmlns="">
+{% spaceless %}
 {% for url in urlset %}
     <loc>{{ url.location|escape }}</loc>
     {% if url.priority %}<priority>{{ url.priority }}</priority>{% endif %}
 {% endfor %}
+{% endspaceless %}


 <?xml version="1.0" encoding="UTF-8"?>
 <sitemapindex xmlns="">
-{% for location in sitemaps %}
-	<sitemap>
-		<loc>{{ location|escape }}</loc>
-	</sitemap>
-{% endfor %}
+{% for location in sitemaps %}<sitemap><loc>{{ location|escape }}</loc></sitemap>{% endfor %}


             if hasattr(mw_instance, 'process_exception'):
                 self._exception_middleware.insert(0, mw_instance.process_exception)
-    def get_response(self, path, request):
+    def get_response(self, request):
         "Returns an HttpResponse object for the given HttpRequest"
         from django.core import exceptions, urlresolvers
         from django.core.mail import mail_admins
         resolver = urlresolvers.RegexURLResolver(r'^/', settings.ROOT_URLCONF)
-            callback, callback_args, callback_kwargs = resolver.resolve(path)
+            callback, callback_args, callback_kwargs = resolver.resolve(request.path)
             # Apply view middleware
             for middleware_method in self._view_middleware:
                 exc_info = sys.exc_info()
                 receivers = dispatcher.send(signal=signals.got_request_exception)
                 # When DEBUG is False, send an error message to the admins.
-                subject = 'Error (%s IP): %s' % ((request.META.get('REMOTE_ADDR') in settings.INTERNAL_IPS and 'internal' or 'EXTERNAL'), getattr(request, 'path', ''))
+                subject = 'Error (%s IP): %s' % ((request.META.get('REMOTE_ADDR') in settings.INTERNAL_IPS and 'internal' or 'EXTERNAL'), request.path)
                     request_repr = repr(request)


                 'REQUEST_METHOD':    self._req.method,
                 'SCRIPT_NAME':       None, # Not supported
                 'SERVER_NAME':       self._req.server.server_hostname,
-                'SERVER_PORT':       self._req.server.port,
+                'SERVER_PORT':       str(self._req.connection.local_addr[1]),
                 'SERVER_PROTOCOL':   self._req.protocol,
                 'SERVER_SOFTWARE':   'mod_python'
             request = ModPythonRequest(req)
-            response = self.get_response(req.uri, request)
+            response = self.get_response(request)
             # Apply response middleware
             for middleware_method in self._response_middleware:


     def __init__(self, environ):
         self.environ = environ
         self.path = environ['PATH_INFO']
-        self.META = environ 
+        self.META = environ
         self.method = environ['REQUEST_METHOD'].upper()
     def __repr__(self):
             request = WSGIRequest(environ)
-            response = self.get_response(request.path, request)
+            response = self.get_response(request)
             # Apply response middleware
             for middleware_method in self._response_middleware:


     validates all models of all installed apps. Writes errors, if any, to outfile.
     Returns number of errors.
-    from django.db import models, model_connection_name
+    from django.conf import settings
+    from django.db import connections, models, model_connection_name
     from django.db.models.loading import get_app_errors
     from django.db.models.fields.related import RelatedObject
     for cls in models.get_models(app):
         opts = cls._meta
         connection_name = model_connection_name(cls)
+        connection = connections[connection_name]
         # Do field-specific validation.
         for f in opts.fields:
             if f.db_index not in (None, True, False):
                 e.add(opts, '"%s": "db_index" should be either None, True or False.' %
+            # Check that maxlength <= 255 if using older MySQL versions.
+            if settings.DATABASE_ENGINE == 'mysql':
+                db_version = connection.connection.get_server_version()
+                if db_version < (5, 0, 3) and isinstance(f, (models.CharField, models.CommaSeparatedIntegerField, models.SlugField)) and f.maxlength > 255:
+                    e.add(opts, '"%s": %s cannot have a "maxlength" greater than 255 when you are using a version of MySQL prior to 5.0.3 (you are using %s).' % (, f.__class__.__name__, '.'.join([str(n) for n in db_version[:3]])))
             # Check to see if the related field will clash with any
             # existing fields, m2m fields, m2m related objects or related objects
             if f.rel:


 from MySQLdb.converters import conversions
 from MySQLdb.constants import FIELD_TYPE
 import types
+import re
 DatabaseError = Database.DatabaseError
     FIELD_TYPE.TIME: util.typecast_time,
+# This should match the numerical portion of the version numbers (we can treat
+# versions like 5.0.24 and 5.0.24a as the same). Based on the list of version
+# at and
+# .
+server_version_re = re.compile(r'(\d{1,2})\.(\d{1,2})\.(\d{1,2})')
 # This is an extra debug layer over MySQL queries, to display warnings.
 # It's only used when DEBUG=True.
 class MysqlDebugWrapper:
         self.settings = settings
         self.connection = None
         self.queries = []
+        self.server_version = None
     def _valid_connection(self):
         if self.connection is not None:
             self.connection = None
+    def get_server_version(self):
+        if not self.server_version:
+            if not self._valid_connection():
+                self.cursor()
+            m = server_version_re.match(self.connection.get_server_info())
+            if not m:
+                raise Exception('Unable to determine MySQL version from version string %r' % self.connection.get_server_info())
+            self.server_version = tuple([int(x) for x in m.groups()])
+        return self.server_version
 supports_constraints = True
 supports_compound_statements = True


 from django import forms
 from django.core.exceptions import ObjectDoesNotExist
 from django.utils.functional import curry
+from django.utils.itercompat import tee
 from django.utils.text import capfirst
 from django.utils.translation import gettext, gettext_lazy
 import datetime, os, time
         self.prepopulate_from = prepopulate_from
         self.unique_for_date, self.unique_for_month = unique_for_date, unique_for_month
         self.unique_for_year = unique_for_year
-        self.choices = choices or []
+        self._choices = choices or []
         self.radio_admin = radio_admin
         self.help_text = help_text
         self.db_column = db_column
     def bind(self, fieldmapping, original, bound_field_class):
         return bound_field_class(self, fieldmapping, original)
+    def _get_choices(self):
+        if hasattr(self._choices, 'next'):
+            choices, self._choices = tee(self._choices)
+            return choices
+        else:
+            return self._choices
+    choices = property(_get_choices)
 class AutoField(Field):
     empty_strings_allowed = False
     def __init__(self, *args, **kwargs):


                         # case, because they'll be dealt with later.
                         if f == related.field:
-                            param = getattr(new_object, related.field.rel.field_name)
+                            param = getattr(new_object, related.field.rel.get_related_field().attname)
                         elif (not self.change) and isinstance(f, AutoField):
                             param = None
                         elif self.change and (isinstance(f, FileField) or not child_follow.get(, None)):
                         # Save many-to-many objects.
                         for f in related.opts.many_to_many:
                             if child_follow.get(, None) and not f.rel.edit_inline:
-                                setattr(new_rel_obj,,[f.attname]))
+                                new_value = rel_new_data[f.attname]
+                                if f.rel.raw_id_admin:
+                                    new_value = new_value[0]
+                                setattr(new_rel_obj,,
                                 if self.change:
                                     self.fields_changed.append('%s for %s "%s"' % (f.verbose_name, related.opts.verbose_name, new_rel_obj))
         raise validators.ValidationError, _("%(object)s with this %(type)s already exists for the given %(field)s.") % \
-            {'object': capfirst(opts.verbose_name), 'type': field_list[0].verbose_name, 'field': get_text_list(field_name_list[1:], 'and')}
+            {'object': capfirst(opts.verbose_name), 'type': field_list[0].verbose_name, 'field': get_text_list([f.verbose_name for f in field_list[1:]], 'and')}
 def manipulator_validator_unique_for_date(from_field, date_field, opts, lookup_type, self, field_data, all_data):
     from django.db.models.fields.related import ManyToOneRel


 from django import http
 from django.core.mail import mail_managers
 import md5
+import re
 class CommonMiddleware(object):
                 # send a note to the managers.
                 domain = http.get_host(request)
                 referer = request.META.get('HTTP_REFERER', None)
-                is_internal = referer and (domain in referer)
+                is_internal = _is_internal_request(domain, referer)
                 path = request.get_full_path()
                 if referer and not _is_ignorable_404(path) and (is_internal or '?' not in referer):
                     ua = request.META.get('HTTP_USER_AGENT', '<none>')
         if uri.endswith(end):
             return True
     return False
+def _is_internal_request(domain, referer):
+    "Return true if the referring URL is the same domain as the current request"
+    # Different subdomains are treated as different domains.
+    return referer is not None and re.match("^https?://%s/" % re.escape(domain), referer)


                 constant_arg, i18n_arg, var_arg ="constant_arg", "i18n_arg", "var_arg")
                 if i18n_arg:
                     args.append((False, _(i18n_arg.replace(r'\"', '"'))))
-                elif constant_arg:
+                elif constant_arg is not None:
                     args.append((False, constant_arg.replace(r'\"', '"')))
                 elif var_arg:
                     args.append((True, var_arg))


 class ClientHandler(BaseHandler):
-    A HTTP Handler that can be used for testing purposes. 
+    A HTTP Handler that can be used for testing purposes.
     Uses the WSGI interface to compose requests, but returns
     the raw HttpResponse object
             request = WSGIRequest(environ)
-            response = self.get_response(request.path, request)
+            response = self.get_response(request)
             # Apply response middleware
             for middleware_method in self._response_middleware:
         return response
 def store_rendered_templates(store, signal, sender, template, context):
     A simple method for encoding multipart POST data from a dictionary of
     form values.
     The key will be used as the form data name; the value will be transmitted
     as content. If the value is a file, the contents of the file will be sent
     as an application/octet-stream; otherwise, str(value) will be sent.
         '--' + boundary + '--',
 class Client:
-    A class that can act as a client for testing purposes. 
+    A class that can act as a client for testing purposes.
     It allows the user to compose GET and POST requests, and
     obtain the response that the server gave to those requests.
     The server Response objects are annotated with the details
     Client objects are stateful - they will retain cookie (and
     thus session) details for the lifetime of the Client instance.
     This is not intended as a replacement for Twill/Selenium or
     the like - it is here to allow testing against the
     contexts and templates produced by a view, rather than the
         self.handler = ClientHandler()
         self.defaults = defaults
         self.cookie = SimpleCookie()
     def request(self, **request):
-        The master request method. Composes the environment dictionary 
+        The master request method. Composes the environment dictionary
         and passes to the handler, returning the result of the handler.
         Assumes defaults for the query environment, which can be overridden
         using the arguments to the request.
             'PATH_INFO':         '/',
             'QUERY_STRING':      '',
             'REQUEST_METHOD':    'GET',
-            'SCRIPT_NAME':       None, 
+            'SCRIPT_NAME':       None,
             'SERVER_NAME':       'testserver',
             'SERVER_PORT':       80,
             'SERVER_PROTOCOL':   'HTTP/1.1',
-        }        
+        }
-        environ.update(request)        
+        environ.update(request)
         # Curry a data dictionary into an instance of
         # the template renderer callback function
         data = {}
         on_template_render = curry(store_rendered_templates, data)
         dispatcher.connect(on_template_render, signal=signals.template_rendered)
         response = self.handler(environ)
         # Add any rendered template detail to the response
-        # If there was only one template rendered (the most likely case), 
+        # If there was only one template rendered (the most likely case),
         # flatten the list to a single element
         for detail in ('template', 'context'):
             if data.get(detail):
                     setattr(response, detail, data[detail])
                 setattr(response, detail, None)
         if response.cookies:
         return response
     def get(self, path, data={}, **extra):
         "Request a response from the server using GET."
         r = {
             'REQUEST_METHOD': 'GET',
         return self.request(**r)
     def post(self, path, data={}, **extra):
         "Request a response from the server using POST."
         BOUNDARY = 'BoUnDaRyStRiNg'
         encoded = encode_multipart(BOUNDARY, data)
             'wsgi.input':     stream,
         return self.request(**r)
     def login(self, path, username, password, **extra):
         A specialized sequence of GET and POST to log into a view that
         is protected by a @login_required access decorator.
         path should be the URL of the page that is login protected.
-        Returns the response from GETting the requested URL after 
+        Returns the response from GETting the requested URL after
         login is complete. Returns False if login process failed.
-        # First, GET the page that is login protected. 
+        # First, GET the page that is login protected.
         # This page will redirect to the login page.
         response = self.get(path)
         if response.status_code != 302:
             return False
         login_path, data = response['Location'].split('?')
         next = data.split('=')[1]
         response = self.get(login_path, **extra)
         if response.status_code != 200:
             return False
         # Last, POST the login data.
         form_data = {
             'username': username,


+Providing iterator functions that are not in all version of Python we support.
+Where possible, we try to use the system-native version and only fall back to
+these implementations if necessary.
+import itertools
+def compat_tee(iterable):
+    """Return two independent iterators from a single iterable.
+    Based on
+    """
+    # Note: Using a dictionary and a list as the default arguments here is
+    # deliberate and safe in this instance.
+    def gen(next, data={}, cnt=[0]):
+        dpop = data.pop
+        for i in itertools.count():
+            if i == cnt[0]:
+                item = data[i] = next()
+                cnt[0] += 1
+            else:
+                item = dpop(i)
+            yield item
+    next = iter(iterable).next
+    return gen(next), gen(next)
+if hasattr(itertools, 'tee'):
+    tee = itertools.tee
+    tee = compat_tee
 .. _MySQL:
 .. _`SQLite 3`:
+Do I lose anything by using Python 2.3 versus newer Python versions, such as Python 2.5?
+No. Django itself is guaranteed to work with any version of Python from 2.3
+and higher.
+If you use a Python version newer than 2.3, you will, of course, be able to
+take advantage of newer Python features in your own code, along with the speed
+improvements and other optimizations that have been made to the Python language
+itself. But the Django framework itself should work equally well on 2.3 as it
+does on 2.4 or 2.5.
 Do I have to use mod_python?


 `HttpRequest object`_. Note that this processor is not enabled by default;
 you'll have to activate it.
+Writing your own context processors
+A context processor has a very simple interface: It's just a Python function
+that takes one argument, an ``HttpRequest`` object, and returns a dictionary
+that gets added to the template context. Each context processor *must* return
+a dictionary.
+Custom context processors can live anywhere in your code base. All Django cares
+about is that your custom context processors are pointed-to by your
 Loading templates


 >>> format(my_birthday, 'N')
->>> format(my_birthday, 'O')
+>>> no_tz or format(my_birthday, 'O') == '+0100'
 >>> format(my_birthday, 'P')
 '10 p.m.'
->>> format(my_birthday, 'r')
-'Sun, 8 Jul 1979 22:00:00 +0100'
+>>> no_tz or format(my_birthday, 'r') == 'Sun, 8 Jul 1979 22:00:00 +0100'
 >>> format(my_birthday, 's')
 >>> format(my_birthday, 'S')
 >>> format(my_birthday, 't')
->>> format(my_birthday, 'T')
->>> format(my_birthday, 'U')
+>>> no_tz or format(my_birthday, 'T') == 'CET'
+>>> no_tz or format(my_birthday, 'U') == '300531600'
 >>> format(my_birthday, 'w')
 >>> format(my_birthday, 'W')
 >>> format(my_birthday, 'z')
->>> format(my_birthday, 'Z')
+>>> no_tz or format(my_birthday, 'Z') == '3600'
->>> format(summertime, 'I')
->>> format(summertime, 'O')
->>> format(wintertime, 'I')
->>> format(wintertime, 'O')
+>>> no_tz or format(summertime, 'I') == '1'
+>>> no_tz or format(summertime, 'O') == '+0200'
+>>> no_tz or format(wintertime, 'I') == '0'
+>>> no_tz or format(wintertime, 'O') == '+0100'
 >>> format(my_birthday, r'Y z \C\E\T')
 '1979 189 CET'
 os.environ['TZ'] = 'Europe/Copenhagen'
+    time.tzset()
+    no_tz = False
+except AttributeError:
+    no_tz = True
 my_birthday = datetime.datetime(1979, 7, 8, 22, 00)
 summertime = datetime.datetime(2005, 10, 30, 1, 00)


             # Escaped backslash using known escape char
             'basic-syntax35': (r'{{ var|default_if_none:"foo\now" }}', {"var": None}, r'foo\now'),
+            # Empty strings can be passed as arguments to filters
+            'basic-syntax36': (r'{{ var|join:"" }}', {'var': ['a', 'b', 'c']}, 'abc'),
             ### COMMENT TAG ###########################################################
             'comment-tag01': ("{% comment %}this is hidden{% endcomment %}hello", {}, "hello"),
             'comment-tag02': ("{% comment %}this is hidden{% endcomment %}hello{% comment %}foo{% endcomment %}", {}, "hello"),
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.