Anonymous committed 001c0d2

[full-history] Trunk merge from [3577]

Comments (0)

Files changed (43)

     Amit Chakradeo <>
     Ian Clelland <>
     Matt Croydon <>
     Jonathan Daugherty (cygnus) <>
     Jason Davies (Esaj) <>
     Baishampayan Ghose
+    Simon Greenhill <>
     Espen Grindhaug <>
     Brant Harris
     Ivan Sagalaev (Maniac) <>
     David Schein
+    Thomas Steinacher <>
     Radek Švarz <>
     Swaroop C H <>
     Aaron Swartz <>
     Tom Tobin
     Tom Insam
     Joe Topjian <>
+    Karen Tracey <>
     Amit Upadhyay
     Geert Vanderkelen
     Milton Waddams


         print "this script should be run from the django svn tree or your project or app tree"
-    for (dirpath, dirnames, filenames) in os.walk(basedir):
+    for dirpath, dirnames, filenames in os.walk(basedir):
         for f in filenames:
             if f.endswith('.po'):
                 sys.stderr.write('processing file %s in %s\n' % (f, dirpath))


 SESSION_COOKIE_NAME = 'sessionid'         # Cookie name. This can be whatever you want.
 SESSION_COOKIE_AGE = 60 * 60 * 24 * 7 * 2 # Age of cookie, in seconds (default: 2 weeks).
 SESSION_COOKIE_DOMAIN = None              # A string like "", or None for standard domain cookie.
+SESSION_COOKIE_SECURE = False             # Whether the session cookie should be secure (https:// only).
 SESSION_SAVE_EVERY_REQUEST = False        # Whether to save the session data on every request.
 SESSION_EXPIRE_AT_BROWSER_CLOSE = False   # Whether sessions expire when a user closes his browser.


Binary file modified.


 msgstr "счёт времени"
 #: contrib/comments/
+#, fuzzy
 msgid "karma score"
 msgstr "Карма счёт"
 #: contrib/admin/templates/admin/index.html:17
 #, python-format
 msgid "Models available in the %(name)s application."
-msgstr "Модели доступны в %(name)s приложении."
+msgstr "Модели доступны в %(name) приложении."
 #: contrib/admin/templates/admin/index.html:28
 #: contrib/admin/templates/admin/change_form.html:15


 ROOT_URLCONF = '{{ project_name }}.urls'
-    # Put strings here, like "/home/html/django_templates".
+    # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
     # Always use forward slashes, even on Windows.
+    # Don't forget to use absolute paths, not relative paths.


     } else {
         href = triggeringLink.href + '?pop=1';
-    var win =, name, 'height=500,width=740,resizable=yes,scrollbars=yes');
+    var win =, name, 'height=500,width=800,resizable=yes,scrollbars=yes');
     return false;


+{% extends "admin/change_form.html" %}
+{% load i18n %}
+{% block after_field_sets %}
+<p>{% trans "First, enter a username and password. Then, you'll be able to edit more user options." %}</p>
+<fieldset class="module aligned">
+<div class="form-row">
+  {{ form.username.html_error_list }}
+  <label for="id_username" class="required">{% trans 'Username' %}:</label> {{ form.username }}
+  <p class="help">{{ username_help_text }}</p>
+<div class="form-row">
+  {{ form.password1.html_error_list }}
+  <label for="id_password1" class="required">{% trans 'Password' %}:</label> {{ form.password1 }}
+<div class="form-row">
+  {{ form.password2.html_error_list }}
+  <label for="id_password2" class="required">{% trans 'Password (again)' %}:</label> {{ form.password2 }}
+  <p class="help">{% trans 'Enter the same password as above, for verification.' %}</p>
+{% endblock %}


   {% if has_absolute_url %}<li><a href="../../../r/{{ content_type_id }}/{{ object_id }}/" class="viewsitelink">{% trans "View on site" %}</a></li>{% endif%}
 {% endif %}{% endif %}
-<form {% if has_file_field %}enctype="multipart/form-data" {% endif %}action="{{ form_url }}" method="post">{% block form_top %}{% endblock %}
+<form {% if has_file_field %}enctype="multipart/form-data" {% endif %}action="{{ form_url }}" method="post" id="{{ opts.module_name }}_form">{% block form_top %}{% endblock %}
 {% if is_popup %}<input type="hidden" name="_popup" value="1" />{% endif %}
 {% if opts.admin.save_on_top %}{% submit_row %}{% endif %}


          <th{{ fw.header_class_attribute }}>{{ fw.field.verbose_name|capfirst|escape }}</th>
       {% endif %}
    {% endfor %}
+   </tr></thead>
    {% for fcw in bound_related_object.form_field_collection_wrappers %}
       {% if change %}{% if original_row_needed %}
          {% if fcw.obj.original %}


     ('^doc/tags/$', 'django.contrib.admin.views.doc.template_tag_index'),
     ('^doc/filters/$', 'django.contrib.admin.views.doc.template_filter_index'),
     ('^doc/views/$', 'django.contrib.admin.views.doc.view_index'),
-    ('^doc/views/jump/$', 'django.contrib.admin.views.doc.jump_to_view'),
     ('^doc/views/(?P<view>[^/]+)/$', 'django.contrib.admin.views.doc.view_detail'),
     ('^doc/models/$', 'django.contrib.admin.views.doc.model_index'),
     ('^doc/models/(?P<app_label>[^\.]+)\.(?P<model_name>[^/]+)/$', 'django.contrib.admin.views.doc.model_detail'),
 #    ('^doc/templates/$', 'django.views.admin.doc.template_index'),
     ('^doc/templates/(?P<template>.*)/$', 'django.contrib.admin.views.doc.template_detail'),
+    # "Add user" -- a special-case view
+    ('^auth/user/add/$', 'django.contrib.admin.views.auth.user_add_stage'),
     # Add/change/delete/history
     ('^([^/]+)/([^/]+)/$', 'django.contrib.admin.views.main.change_list'),
     ('^([^/]+)/([^/]+)/add/$', 'django.contrib.admin.views.main.add_stage'),


+from django.contrib.auth.forms import UserCreationForm
+from django.contrib.auth.models import User
+from django import forms, template
+from django.shortcuts import render_to_response
+from django.http import HttpResponseRedirect
+def user_add_stage(request):
+    manipulator = UserCreationForm()
+    if request.method == 'POST':
+        new_data = request.POST.copy()
+        errors = manipulator.get_validation_errors(new_data)
+        if not errors:
+            new_user =
+            msg = _('The %(name)s "%(obj)s" was added successfully.') % {'name': 'user', 'obj': new_user}
+            if request.POST.has_key("_addanother"):
+                request.user.message_set.create(message=msg)
+                return HttpResponseRedirect(request.path)
+            else:
+                request.user.message_set.create(message=msg + ' ' + _("You may edit it again below."))
+                return HttpResponseRedirect('../%s/' %
+    else:
+        errors = new_data = {}
+    form = forms.FormWrapper(manipulator, new_data, errors)
+    return render_to_response('admin/auth/user/add_form.html', {
+        'title': _('Add user'),
+        'form': form,
+        'is_popup': request.REQUEST.has_key('_popup'),
+        'add': True,
+        'change': False,
+        'has_delete_permission': False,
+        'has_change_permission': True,
+        'has_file_field': False,
+        'has_absolute_url': False,
+        'auto_populated_fields': (),
+        'bound_field_sets': (),
+        'first_form_field_id': 'id_username',
+        'opts': User._meta,
+        'username_help_text': User._meta.get_field('username').help_text,
+    }, context_instance=template.RequestContext(request))


         for tag_name, tag_func in library.tags.items():
             title, body, metadata = utils.parse_docstring(tag_func.__doc__)
             if title:
-                title = utils.parse_rst(title, 'tag', 'tag:' + tag_name)
+                title = utils.parse_rst(title, 'tag', _('tag:') + tag_name)
             if body:
-                body = utils.parse_rst(body, 'tag', 'tag:' + tag_name)
+                body = utils.parse_rst(body, 'tag', _('tag:') + tag_name)
             for key in metadata:
-                metadata[key] = utils.parse_rst(metadata[key], 'tag', 'tag:' + tag_name)
+                metadata[key] = utils.parse_rst(metadata[key], 'tag', _('tag:') + tag_name)
             if library in template.builtins:
                 tag_library = None
         for filter_name, filter_func in library.filters.items():
             title, body, metadata = utils.parse_docstring(filter_func.__doc__)
             if title:
-                title = utils.parse_rst(title, 'filter', 'filter:' + filter_name)
+                title = utils.parse_rst(title, 'filter', _('filter:') + filter_name)
             if body:
-                body = utils.parse_rst(body, 'filter', 'filter:' + filter_name)
+                body = utils.parse_rst(body, 'filter', _('filter:') + filter_name)
             for key in metadata:
-                metadata[key] = utils.parse_rst(metadata[key], 'filter', 'filter:' + filter_name)
+                metadata[key] = utils.parse_rst(metadata[key], 'filter', _('filter:') + filter_name)
             if library in template.builtins:
                 tag_library = None
         raise Http404
     title, body, metadata = utils.parse_docstring(view_func.__doc__)
     if title:
-        title = utils.parse_rst(title, 'view', 'view:' + view)
+        title = utils.parse_rst(title, 'view', _('view:') + view)
     if body:
-        body = utils.parse_rst(body, 'view', 'view:' + view)
+        body = utils.parse_rst(body, 'view', _('view:') + view)
     for key in metadata:
-        metadata[key] = utils.parse_rst(metadata[key], 'model', 'view:' + view)
+        metadata[key] = utils.parse_rst(metadata[key], 'model', _('view:') + view)
     return render_to_response('admin_doc/view_detail.html', {
         'name': view,
         'summary': title,
         app_mod = models.get_app(app_label)
     except ImproperlyConfigured:
-        raise Http404, "App %r not found" % app_label
+        raise Http404, _("App %r not found") % app_label
     model = None
     for m in models.get_models(app_mod):
         if m._meta.object_name.lower() == model_name:
             model = m
     if model is None:
-        raise Http404, "Model %r not found in app %r" % (model_name, app_label)
+        raise Http404, _("Model %r not found in app %r") % (model_name, app_label)
     opts = model._meta
         if isinstance(field, models.ForeignKey):
             data_type = related_object_name =
             app_label =
-            verbose = utils.parse_rst(("the related `%s.%s` object"  % (app_label, data_type)), 'model', 'model:' + data_type)
+            verbose = utils.parse_rst((_("the related `%s.%s` object")  % (app_label, data_type)), 'model', _('model:') + data_type)
             data_type = get_readable_field_data_type(field)
             verbose = field.verbose_name
             verbose = func.__doc__
             if verbose:
-                verbose = utils.parse_rst(utils.trim_docstring(verbose), 'model', 'model:' + opts.module_name)
+                verbose = utils.parse_rst(utils.trim_docstring(verbose), 'model', _('model:') + opts.module_name)
                 'name': func_name,
                 'data_type': get_return_data_type(func_name),
     # Gather related objects
     for rel in opts.get_all_related_objects():
-        verbose = "related `%s.%s` objects" % (rel.opts.app_label, rel.opts.object_name)
+        verbose = _("related `%s.%s` objects") % (rel.opts.app_label, rel.opts.object_name)
         accessor = rel.get_accessor_name()
             'name'      : "%s.all" % accessor,
             'data_type' : 'List',
-            'verbose'   : utils.parse_rst("all " + verbose , 'model', 'model:' + opts.module_name),
+            'verbose'   : utils.parse_rst(_("all %s") % verbose , 'model', _('model:') + opts.module_name),
             'name'      : "%s.count" % accessor,
             'data_type' : 'Integer',
-            'verbose'   : utils.parse_rst("number of " + verbose , 'model', 'model:' + opts.module_name),
+            'verbose'   : utils.parse_rst(_("number of %s") % verbose , 'model', _('model:') + opts.module_name),
     return render_to_response('admin_doc/model_detail.html', {
         elif hasattr(p, '_get_url_patterns'):
             views.extend(extract_views_from_urlpatterns(p.url_patterns, base + p.regex.pattern))
-            raise TypeError, "%s does not appear to be a urlpattern object" % p
+            raise TypeError, _("%s does not appear to be a urlpattern object") % p
     return views
 named_group_matcher = re.compile(r'\(\?P(<\w+>).+?\)')


                     post_url_continue += "?_popup=1"
                 return HttpResponseRedirect(post_url_continue % pk_value)
             if request.POST.has_key("_popup"):
-                return HttpResponse('<script type="text/javascript">opener.dismissAddAnotherPopup(window, %s, "%s");</script>' % \
+                return HttpResponse('<script type="text/javascript">opener.dismissAddAnotherPopup(window, %r, "%s");</script>' % \
                     (pk_value, str(new_object).replace('"', '\\"')))
             elif request.POST.has_key("_addanother"):
                 request.user.message_set.create(message=msg + ' ' + (_("You may add another %s below.") % opts.verbose_name))


 from django.core import validators
 from django import forms
+class UserCreationForm(forms.Manipulator):
+    "A form that creates a user, with no privileges, from the given username and password."
+    def __init__(self):
+        self.fields = (
+            forms.TextField(field_name='username', length=30, maxlength=30, is_required=True,
+                validator_list=[validators.isAlphaNumeric, self.isValidUsername]),
+            forms.PasswordField(field_name='password1', length=30, maxlength=60, is_required=True),
+            forms.PasswordField(field_name='password2', length=30, maxlength=60, is_required=True,
+                validator_list=[validators.AlwaysMatchesOtherField('password1', "The two password fields didn't match.")]),
+        )
+    def isValidUsername(self, field_data, all_data):
+        try:
+            User.objects.get(username=field_data)
+        except User.DoesNotExist:
+            return
+        raise validators.ValidationError, 'A user with that username already exists.'
+    def save(self, new_data):
+        "Creates the user."
+        return User.objects.create_user(new_data['username'], '', new_data['password1'])
 class AuthenticationForm(forms.Manipulator):
     Base class for authenticating users. Extend this to get a form that accepts


 For full documentation, see either of these:
-    * The file django/docs/flatpages.txt in the Django distribution
+    * The file docs/flatpages.txt in the Django distribution
     * on the Web
-Both have identical content.
+Both have identical content.


                 new_session =, request.session._session,
            + datetime.timedelta(seconds=settings.SESSION_COOKIE_AGE))
                 response.set_cookie(settings.SESSION_COOKIE_NAME, session_key,
-                    max_age=max_age, expires=expires, domain=settings.SESSION_COOKIE_DOMAIN)
+                    max_age=max_age, expires=expires, domain=settings.SESSION_COOKIE_DOMAIN,
+                    secure=settings.SESSION_COOKIE_SECURE or None)
         return response


             "Edit your settings file and change DATABASE_ENGINE to something like 'postgresql' or 'mysql'.\n"))
-    # Get installed models, so we generate REFERENCES right
+    # Get installed models, so we generate REFERENCES right.
+    # We trim models from the current app so that the sqlreset command does not
+    # generate invalid SQL (leaving models out of known_models is harmless, so
+    # we can be conservative).
+    app_models = models.get_models(app)
     final_output = []
-    known_models = set(_get_installed_models(_get_table_list()))
+    known_models = set([model for model in _get_installed_models(_get_table_list()) if model not in app_models])
     pending_references = {}
-    app_models = models.get_models(app)
     for model in app_models:
         output, references = _get_sql_model_create(model, known_models)
     # but don't exist physically
     not_installed_models = set(pending_references.keys())
     if not_installed_models:
-        final_output.append('-- The following references should be added but depend on non-existant tables:')
+        alter_sql = []
         for model in not_installed_models:
-            final_output.extend(['-- ' + sql for sql in
+            alter_sql.extend(['-- ' + sql for sql in
                 _get_sql_for_pending_references(model, pending_references)])
+        if alter_sql:
+            final_output.append('-- The following references should be added but depend on non-existent tables:')
+            final_output.extend(alter_sql)
     return final_output
 get_sql_create.help_doc = "Prints the CREATE TABLE SQL statements for the given app name(s)."
                         (style.SQL_KEYWORD('ALTER TABLE'),
-                        style.SQL_FIELD(backend.quote_name("%s_referencing_%s_%s" % (col, r_table, r_col)))))
+                        style.SQL_FIELD(backend.quote_name('%s_refs_%s_%x' % (col, r_col, abs(hash((table, r_table))))))))
                 del references_to_delete[model]
     # Output DROP TABLE statements for many-to-many tables.
     introspection_module = get_introspection_module()
-    def table2model(table_name):
-        object_name = table_name.title().replace('_', '')
-        return object_name.endswith('s') and object_name[:-1] or object_name
+    table2model = lambda table_name: table_name.title().replace('_', '')
     cursor = connection.cursor()
     yield "# This is an auto-generated Django model module."
             comment_notes = [] # Holds Field notes, to be displayed in a Python comment.
             extra_params = {}  # Holds Field parameters such as 'db_column'.
+            if ' ' in att_name:
+                extra_params['db_column'] = att_name
+                att_name = att_name.replace(' ', '')
+                comment_notes.append('Field renamed to remove spaces.')
             if keyword.iskeyword(att_name):
                 extra_params['db_column'] = att_name
                 att_name += '_field'
                             f = opts.get_field(fn)
                         except models.FieldDoesNotExist:
                             e.add(opts, '"admin.list_filter" refers to %r, which isn\'t a field.' % fn)
+                # date_hierarchy
+                if opts.admin.date_hierarchy:
+                    try:
+                        f = opts.get_field(opts.admin.date_hierarchy)
+                    except models.FieldDoesNotExist:
+                        e.add(opts, '"admin.date_hierarchy" refers to %r, which isn\'t a field.' % opts.admin.date_hierarchy)
         # Check ordering attribute.
         if opts.ordering:
 dbshell.args = ""
 def runfcgi(args):
-    """Run this project as a FastCGI application. requires flup."""
+    "Runs this project as a FastCGI application. Requires flup."
+    from django.conf import settings
+    from django.utils import translation
+    # Activate the current language, because it won't get activated later.
+    try:
+        translation.activate(settings.LANGUAGE_CODE)
+    except AttributeError:
+        pass
     from django.core.servers.fastcgi import runfastcgi
 runfcgi.args = '[various KEY=val options, use `runfcgi help` for help]'
         if action not in NO_SQL_TRANSACTION:
             print style.SQL_KEYWORD("COMMIT;")
-def execute_manager(settings_mod, argv=None):
+def setup_environ(settings_mod):
+    """
+    Configure the runtime environment. This can also be used by external
+    scripts wanting to set up a similar environment to
+    """
     # Add this project to sys.path so that it's importable in the conventional
     # way. For example, if this file ( lives in a directory
     # "myproject", this code would add "/path/to/myproject" to sys.path.
     # Set DJANGO_SETTINGS_MODULE appropriately.
     os.environ['DJANGO_SETTINGS_MODULE'] = '%s.settings' % project_name
+    return project_directory
+def execute_manager(settings_mod, argv=None):
+    project_directory = setup_environ(settings_mod)
     action_mapping = DEFAULT_ACTION_MAPPING.copy()
     # Remove the "startproject" command from the action_mapping, because that's


         env['PATH_INFO'] = urllib.unquote(path)
         env['QUERY_STRING'] = query
-        host = self.address_string()
-        if host != self.client_address[0]:
-            env['REMOTE_HOST'] = host
         env['REMOTE_ADDR'] = self.client_address[0]
         if self.headers.typeheader is None:


 class RegexURLPattern(object):
     def __init__(self, regex, callback, default_args=None):
         # regex is a string representing a regular expression.
-        # callback is something like '',
-        # which represents the path to a module and a view function name.
+        # callback is either a string like ''
+        # which represents the path to a module and a view function name, or a
+        # callable object (view).
         self.regex = re.compile(regex)
-        self.callback = callback
+        if callable(callback):
+            self._callback = callback
+        else:
+            self._callback = None
+            self._callback_str = callback
         self.default_args = default_args or {}
     def resolve(self, path):
             # In both cases, pass any extra_kwargs as **kwargs.
-            try: # Lazily load self.func.
-                return self.func, args, kwargs
-            except AttributeError:
-                self.func = self.get_callback()
-            return self.func, args, kwargs
+            return self.callback, args, kwargs
-    def get_callback(self):
-        mod_name, func_name = get_mod_func(self.callback)
+    def _get_callback(self):
+        if self._callback is not None:
+            return self._callback
+        mod_name, func_name = get_mod_func(self._callback_str)
-            return getattr(__import__(mod_name, '', '', ['']), func_name)
+            self._callback = getattr(__import__(mod_name, '', '', ['']), func_name)
         except ImportError, e:
             raise ViewDoesNotExist, "Could not import %s. Error was: %s" % (mod_name, str(e))
         except AttributeError, e:
             raise ViewDoesNotExist, "Tried %s in module %s. Error was: %s" % (func_name, mod_name, str(e))
+        return self._callback
+    callback = property(_get_callback)
     def reverse(self, viewname, *args, **kwargs):
-        if viewname != self.callback:
+        mod_name, func_name = get_mod_func(viewname)
+        try:
+            lookup_view = getattr(__import__(mod_name, '', '', ['']), func_name)
+        except (ImportError, AttributeError):
+            raise NoReverseMatch
+        if lookup_view != self.callback:
             raise NoReverseMatch
         return self.reverse_helper(*args, **kwargs)
     def resolve500(self):
         return self._resolve_special('500')
-    def reverse(self, viewname, *args, **kwargs):
+    def reverse(self, lookup_view, *args, **kwargs):
+        if not callable(lookup_view):
+            mod_name, func_name = get_mod_func(lookup_view)
+            try:
+                lookup_view = getattr(__import__(mod_name, '', '', ['']), func_name)
+            except (ImportError, AttributeError):
+                raise NoReverseMatch
         for pattern in self.urlconf_module.urlpatterns:
             if isinstance(pattern, RegexURLResolver):
-                    return pattern.reverse_helper(viewname, *args, **kwargs)
+                    return pattern.reverse_helper(lookup_view, *args, **kwargs)
                 except NoReverseMatch:
-            elif pattern.callback == viewname:
+            elif pattern.callback == lookup_view:
                     return pattern.reverse_helper(*args, **kwargs)
                 except NoReverseMatch:
         raise NoReverseMatch
-    def reverse_helper(self, viewname, *args, **kwargs):
-        sub_match = self.reverse(viewname, *args, **kwargs)
+    def reverse_helper(self, lookup_view, *args, **kwargs):
+        sub_match = self.reverse(lookup_view, *args, **kwargs)
         result = reverse_helper(self.regex, *args, **kwargs)
         return result + sub_match


     from django.core.exceptions import ImproperlyConfigured
     raise ImproperlyConfigured, "Error loading psycopg2 module: %s" % e
+# Register Unicode conversions
+import psycopg2.extensions
 DatabaseError = Database.DatabaseError


     def inner(*args, **kwargs):
         bits = func(*args, **kwargs)
         viewname = bits[0]
-        return reverse(bits[0], None, *bits[1:2])
+        return reverse(bits[0], None, *bits[1:3])
     return inner
 class LazyDate(object):
         return "<LazyDate: %s>" %
     def __get_value__(self):
-        return +
+        return ( +
     def __getattr__(self, attr):
         return getattr(self.__get_value__(), attr)


             # If it does already exist, do an UPDATE.
             if cursor.fetchone():
                 db_values = [f.get_db_prep_save(f.pre_save(self, False)) for f in non_pks]
-                cursor.execute("UPDATE %s SET %s WHERE %s=%%s" % \
-                    (backend.quote_name(self._meta.db_table),
-                    ','.join(['%s=%%s' % backend.quote_name(f.column) for f in non_pks]),
-                    backend.quote_name(,
-                    db_values + [pk_val])
+                if db_values:
+                    cursor.execute("UPDATE %s SET %s WHERE %s=%%s" % \
+                        (backend.quote_name(self._meta.db_table),
+                        ','.join(['%s=%%s' % backend.quote_name(f.column) for f in non_pks]),
+                        backend.quote_name(,
+                        db_values + [pk_val])
                 record_exists = False
         if not pk_set or not record_exists:


 BLANK_CHOICE_NONE = [("", "None")]
 # prepares a value for use in a LIKE query
-prep_for_like_query = lambda x: str(x).replace("%", "\%").replace("_", "\_")
+prep_for_like_query = lambda x: str(x).replace("\\", "\\\\").replace("%", "\%").replace("_", "\_")
 # returns the <ul> class for a given radio_admin value
 get_ul_class = lambda x: 'radiolist%s' % ((x == HORIZONTAL) and ' inline' or '')


                 _app_errors[app_name] = e
     return _app_list
-def get_app(app_label, emptyOK = False):
+def get_app(app_label, emptyOK=False):
     "Returns the module containing the models for the given app_label. If the app has no models in it and 'emptyOK' is True, returns None."
     get_apps() # Run get_apps() to populate the _app_list cache. Slightly hackish.
     for app_name in settings.INSTALLED_APPS:
         return model_list
-def get_model(app_label, model_name, seed_cache = True):
+def get_model(app_label, model_name, seed_cache=True):
     Returns the model matching the given app_label and case-insensitive


             child_follow = self.follow.get(, None)
             if child_follow:
-                obj_list = expanded_data[related.var_name].items()
+                obj_list = expanded_data.get(related.var_name, {}).items()
                 if not obj_list:


     def get_full_path(self):
         return ''
     def is_secure(self):
         return os.environ.get("HTTPS") == "on"
             if val is not None:
                 self.cookies[key][var.replace('_', '-')] = val
-    def delete_cookie(self, key):
-        try:
-            self.cookies[key]['max_age'] = 0
-        except KeyError:
-            pass
+    def delete_cookie(self, key, path='/', domain=None):
+        self.cookies[key] = ''
+        if path is not None:
+            self.cookies[key]['path'] = path
+        if domain is not None:
+            self.cookies[key]['domain'] = path
+        self.cookies[key]['expires'] = 0
+        self.cookies[key]['max-age'] = 0
     def _get_content(self):
         content = ''.join(self._iterator)


 def time(value, arg=None):
     "Formats a time according to the given format"
     from django.utils.dateformat import time_format
-    if not value:
+    if value in (None, ''):
         return ''
     if arg is None:
         arg = settings.TIME_FORMAT
     is used instead. If the provided argument contains a comma, the text before
     the comma is used for the singular case.
-    if not ',' in arg: 
+    if not ',' in arg:
         arg = ',' + arg
     bits = arg.split(',')
     if len(bits) > 2:


             return (open(filepath).read(), filepath)
         except IOError:
-    if template_dirs:
+    if tried:
         error_msg = "Tried %s" % tried
         error_msg = "Your TEMPLATE_DIRS setting is empty. Change it to point to at least one template directory."


 from django.template import RequestContext
 from django.http import Http404, HttpResponse, HttpResponseRedirect
 from django.core.exceptions import ObjectDoesNotExist, ImproperlyConfigured
+from django.utils.translation import gettext
 def create_object(request, model, template_name=None,
         template_loader=loader, extra_context=None, post_save_redirect=None,
             new_object =
             if request.user.is_authenticated():
-                request.user.message_set.create(message="The %s was created successfully." % model._meta.verbose_name)
+                request.user.message_set.create(message=gettext("The %(verbose_name)s was created successfully.") % {"verbose_name": model._meta.verbose_name})
             # Redirect to the new object: first by trying post_save_redirect,
             # then by obj.get_absolute_url; fail if neither works.
             object =
             if request.user.is_authenticated():
-                request.user.message_set.create(message="The %s was updated successfully." % model._meta.verbose_name)
+                request.user.message_set.create(message=gettext("The %(verbose_name)s was updated successfully.") % {"verbose_name": model._meta.verbose_name})
             # Do a post-after-redirect so that reload works, etc.
             if post_save_redirect:
     if request.method == 'POST':
         if request.user.is_authenticated():
-            request.user.message_set.create(message="The %s was deleted." % model._meta.verbose_name)
+            request.user.message_set.create(message=gettext("The %(verbose_name)s was deleted.") % {"verbose_name": model._meta.verbose_name})
         return HttpResponseRedirect(post_delete_redirect)
         if not template_name:
 A convenience method for creating an object and saving it all in one step.  Thus::
     p = Person.objects.create(first_name="Bruce", last_name="Springsteen")
     p = Person(first_name="Bruce", last_name="Springsteen")
 are equivalent.
           b.entry_set.remove(e) # Disassociates Entry e from Blog b.
       In order to prevent database inconsistency, this method only exists on
-      ``ForeignKey``s where ``null=True``. If the related field can't be set to
-      ``None`` (``NULL``), then an object can't be removed from a relation
-      without being added to another. In the above example, removing ``e`` from
-      ``b.entry_set()`` is equivalent to doing `` = None``, and because
-      the ``blog`` ``ForeignKey`` doesn't have ``null=True``, this is invalid.
+      ``ForeignKey`` objects where ``null=True``. If the related field can't be
+      set to ``None`` (``NULL``), then an object can't be removed from a
+      relation without being added to another. In the above example, removing
+      ``e`` from ``b.entry_set()`` is equivalent to doing `` = None``,
+      and because the ``blog`` ``ForeignKey`` doesn't have ``null=True``, this
+      is invalid.
     * ``clear()``: Removes all objects from the related object set.
 Queries involving related objects follow the same rules as queries involving
-normal value fields. When specifying the the value for a query to match, you 
-may use either an object instance itself, or the primary key value for the 
+normal value fields. When specifying the the value for a query to match, you
+may use either an object instance itself, or the primary key value for the
 For example, if you have a Blog object ``b`` with ``id=5``, the following
 three queries would be identical::
     Entry.objects.filter(blog=b) # Query using object instance
     Entry.objects.filter( # Query using id from instance
     Entry.objects.filter(blog=5) # Query using id directly


+How to read the Django documentation
+We've put a lot of effort into making Django's documentation useful, easy to
+read and as complete as possible. Here are a few tips on how to make the best
+of it, along with some style guidelines.
+(Yes, this is documentation about documentation. Rest assured we have no plans
+to write a document about how to read the document about documentation.)
+How documentation is updated
+Just as the Django code base is developed and improved on a daily basis, our
+documentation is consistently improving. We improve documentation for several
+    * To make content fixes, such as grammar/typo corrections.
+    * To add information and/or examples to existing sections that need to be
+      expanded.
+    * To document Django features that aren't yet documented. (The list of
+      such features is shrinking but exists nonetheless.)
+    * To add documentation for new features as new features get added, or as
+      Django APIs or behaviors change.
+Django's documentation is kept in the same source control system as its code.
+It lives in the `django/trunk/docs`_ directory of our Subversion repository.
+Each document is a separate text file that covers a narrowly focused topic,
+such as the "generic views" framework or how to construct a database model.
+.. _django/trunk/docs:
+Where to get it
+You can read Django documentation in several ways. They are, in order of
+On the Web
+The most recent version of the Django documentation lives at
+ . These HTML pages are generated
+automatically from the text files in source control every 15 minutes. That
+means they reflect the "latest and greatest" in Django -- they include the very
+latest corrections and additions, and they discuss the latest Django features,
+which may only be available to users of the Django development version. (See
+"Differences between versions" below.)
+A key advantage of the Web-based documentation is the comment section at the
+bottom of each document. This is an area for anybody to submit changes,
+corrections and suggestions about the given document. The Django developers
+frequently monitor the comments there and use them to improve the documentation
+for everybody.
+We encourage you to help improve the docs: it's easy! Note, however, that
+comments should explicitly relate to the documentation, rather than asking
+broad tech-support questions. If you need help with your particular Django
+setup, try the `django-users mailing list`_ instead of posting a comment to the
+.. _django-users mailing list:
+In plain text
+For offline reading, or just for convenience, you can read the Django
+documentation in plain text.
+If you're using an official release of Django, note that the zipped package
+(tarball) of the code includes a ``docs/`` directory, which contains all the
+documentation for that release.
+If you're using the development version of Django (aka the Subversion "trunk"),
+note that the ``docs/`` directory contains all of the documentation. You can
+``svn update`` it, just as you ``svn update`` the Python code, in order to get
+the latest changes.
+You can check out the latest Django documentation from Subversion using this
+shell command::
+    svn co django_docs
+One low-tech way of taking advantage of the text documentation is by using the
+Unix ``grep`` utility to search for a phrase in all of the documentation. For
+example, this will show you each mention of the phrase "edit_inline" in any
+Django document::
+    grep edit_inline /path/to/django/docs/*.txt
+The text documentation is written in ReST (ReStructured Text) format. That
+means it's easy to read but is also formatted in a way that makes it easy to
+convert into other formats, such as HTML. If you're interested, the script that
+converts the ReST text docs into's HTML lives at
+``_ in
+the Django Subversion repository.
+Differences between versions
+As previously mentioned, the text documentation in our Subversion repository
+contains the "latest and greatest" changes and additions. These changes often
+include documentation of new features added in the Django development version
+-- the Subversion ("trunk") version of Django. For that reason, it's worth
+pointing out our policy on keeping straight the documentation for various
+versions of the framework.
+We follow this policy:
+    * The primary documentation on is an HTML version of the
+      latest docs in Subversion. These docs always correspond to the latest
+      official Django release, plus whatever features we've added/changed in
+      the framework *since* the latest release.
+    * As we add features to Django's development version, we try to update the
+      documentation in the same Subversion commit transaction.
+    * To distinguish feature changes/additions in the docs, we use the phrase
+      **New in Django development version**. In practice, this means that the
+      current documentation on can be used by users of either
+      the latest release *or* the development version.
+    * Documentation for a particular Django release is frozen once the version
+      has been released officially. It remains a snapshot of the docs as of the
+      moment of the release. We will make exceptions to this rule in
+      the case of retroactive security updates or other such retroactive
+      changes. Once documentation is frozen, we add a note to the top of each
+      frozen document that says "These docs are frozen for Django version XXX"
+      and links to the current version of that document.
+    * Once a document is frozen for a Django release, we remove comments from
+      that page, in favor of having comments on the latest version of that
+      document. This is for the sake of maintainability and usability, so that
+      users have one, and only one, place to leave comments on a particular
+      document. We realize that some people may be stuck on a previous version
+      of Django, but we believe the usability problems with multiple versions
+      of a document the outweigh the benefits.
+    * The `main documentation Web page`_ includes links to documentation for
+      all previous versions.
+.. _main documentation Web page:
 How do I create users without having to edit password hashes?
-We don't recommend you create users via the admin interface, because at the
-moment it requires you to edit password hashes manually. (Passwords are hashed
-using one-way hash algorithms for security; there's currently no Web interface
-for changing passwords by entering the actual password rather than the hash.)
+If you'd like to use the admin site to create users, upgrade to the Django
+development version, where this problem was fixed on Aug. 4, 2006.
-To create a user, you'll have to use the Python API. See `creating users`_ for
-full info.
+You can also use the Python API. See `creating users`_ for full info.
 .. _creating users:


 This example redirects from ``/foo/<id>/`` to ``/bar/<id>/``::
     urlpatterns = patterns('django.views.generic.simple',
-        ('^foo/(?p<id>\d+)/$', 'redirect_to', {'url': '/bar/%(id)s/'}),
+        ('^foo/(?P<id>\d+)/$', 'redirect_to', {'url': '/bar/%(id)s/'}),
 This example returns a 410 HTTP error for requests to ``/bar/``::
        the absolute URL to your image in a template with ``{{
        object.get_mug_shot_url }}``.
+For example, say your ``MEDIA_ROOT`` is set to ``'/home/media'``, and
+``upload_to`` is set to ``'photos/%Y/%m/%d'``. The ``'%Y/%m/%d'`` part of
+``upload_to`` is strftime formatting; ``'%Y'`` is the four-digit year,
+``'%m'`` is the two-digit month and ``'%d'`` is the two-digit day. If you
+upload a file on Jan. 15, 2007, it will be saved in the directory
 .. _`strftime formatting`:


    Returns the ``path``, plus an appended query string, if applicable.
    Example: ``"/music/bands/the_beatles/?print=true"``
    Returns ``True`` if the request is secure; that is, if it was made with
     .. _`cookie Morsel`:
+``delete_cookie(key, path='/', domain=None)``
     Deletes the cookie with the given key. Fails silently if the key doesn't
+    The ``path`` and ``domain`` arguments are new in the Django development version.
+    Due to the way cookies work, ``path`` and ``domain`` should be the same
+    values you used in ``set_cookie()`` -- otherwise the cookie may not be deleted.
     Returns the content as a Python string, encoding it from a Unicode object
     if necessary. Note this is a property, not a method, so use ``r.content``
 The name of the cookie to use for sessions. This can be whatever you want.
+**New in Django development version**
+Default: ``False``
+Whether to use a secure cookie for the session cookie. If this is set to
+``True``, the cookie will be marked as "secure," which means browsers may
+ensure that the cookie is only sent under an HTTPS connection.
 The name of the cookie to use for sessions. This can be whatever you want.
 See the `session docs`_.
+**New in Django development version**
+Default: ``False``
+Whether to use a secure cookie for the session cookie. If this is set to
+``True``, the cookie will be marked as "secure," which means browsers may
+ensure that the cookie is only sent under an HTTPS connection.
+See the `session docs`_.


 URLconf, regardless of whether the line's view actually accepts those options
 as valid. For this reason, this technique is only useful if you're certain that
 every view in the the included URLconf accepts the extra options you're passing.
+Passing callable objects instead of strings
+**New in the Django development version.**
+Some developers find it more natural to pass the actual Python function object
+rather than a string containing the path to its module. This alternative is
+supported -- you can pass any callable object as the view.
+For example, given this URLconf in "string" notation::
+    urlpatterns = patterns('',
+        (r'^archive/$', 'mysite.views.archive'),
+        (r'^about/$', 'mysite.views.about'),
+        (r'^contact/$', ''),
+    )
+You can accomplish the same thing by passing objects rather than strings. Just
+be sure to import the objects::
+    from mysite.views import archive, about, contact
+    urlpatterns = patterns('',
+        (r'^archive/$', archive),
+        (r'^about/$', about),
+        (r'^contact/$', contact),
+    )
+The following example is functionally identical. It's just a bit more compact
+because it imports the module that contains the views, rather than importing
+each view individually::
+    from mysite import views
+    urlpatterns = patterns('',
+        (r'^archive/$', views.archive),
+        (r'^about/$', views.about),
+        (r'^contact/$',,
+    )
+The style you use is up to you.
+Note that if you use this technique -- passing objects rather than strings --
+the view prefix (as explained in "The view prefix" above) will have no effect.
         '': ['*.TXT'],
         'django.conf': ['locale/*/LC_MESSAGES/*'],
         'django.contrib.admin': ['templates/admin/*.html',
+                                 'templates/admin/auth/user/*.html',


 >>> is not None
+>>> existing = Empty(


     def __str__(self):
         return self.headline
-API_TESTS = """
+API_TESTS = r"""
 # Create a couple of Articles.
 >>> from datetime import datetime
 >>> a1 = Article(headline='Article 1', pub_date=datetime(2005, 7, 26))
 <Article: Article 1>
 # Underscores and percent signs have special meaning in the underlying
-# database library, but Django handles the quoting of them automatically.
+# SQL code, but Django handles the quoting of them automatically.
 >>> a8 = Article(headline='Article_ with underscore', pub_date=datetime(2005, 11, 20))
 >>> Article.objects.filter(headline__startswith='Article')
 [<Article: Article_ with underscore>, <Article: Article 5>, <Article: Article 6>, <Article: Article 4>, <Article: Article 2>, <Article: Article 3>, <Article: Article 7>, <Article: Article 1>]
 >>> Article.objects.filter(headline__startswith='Article_')
 [<Article: Article_ with underscore>]
 >>> a9 = Article(headline='Article% with percent sign', pub_date=datetime(2005, 11, 21))
 >>> Article.objects.filter(headline__startswith='Article')
 [<Article: Article% with percent sign>, <Article: Article 5>, <Article: Article 6>, <Article: Article 4>, <Article: Article 2>, <Article: Article 3>, <Article: Article 7>, <Article: Article 1>]
 >>> Article.objects.exclude(headline="Article 7")
 [<Article: Article% with percent sign>, <Article: Article_ with underscore>, <Article: Article 5>, <Article: Article 6>, <Article: Article 4>, <Article: Article 2>, <Article: Article 3>, <Article: Article 1>]
+# Backslashes also have special meaning in the underlying SQL code, but Django
+# automatically quotes them appropriately.
+>>> a10 = Article(headline='Article with \\ backslash', pub_date=datetime(2005, 11, 22))
+>>> Article.objects.filter(headline__contains='\\')
+[<Article: Article with \ backslash>]


 >>> time(datetime.time(13), "h")
+>>> time(datetime.time(0), "h")
 # real testing is done in, where we can provide our own 'now'
 >>> timesince( - datetime.timedelta(1))
 '1 day'