1. Luke Plant
  2. django

Commits

Honz...@bcc190cf-cafb-0310-a4f2-bffc1f526a37  committed 6fcbe77

[soc2009/model-validation] Merged to trunk at r11499

  • Participants
  • Parent commits e4c6e2b
  • Branches soc2009/model-validation

Comments (0)

Files changed (16)

File django/contrib/admin/sites.py

View file
  • Ignore whitespace
         user = authenticate(username=username, password=password)
         if user is None:
             message = ERROR_MESSAGE
-            if u'@' in username:
+            if username is not None and u'@' in username:
                 # Mistakenly entered e-mail address instead of username? Look it up.
                 try:
                     user = User.objects.get(email=username)

File django/contrib/admin/templates/admin/edit_inline/tabular.html

View file
  • Ignore whitespace
      {% if inline_admin_formset.formset.can_delete %}<th>{% trans "Delete?" %}</th>{% endif %}
      </tr></thead>
 
+     <tbody>
      {% for inline_admin_form in inline_admin_formset %}
         {% if inline_admin_form.form.non_field_errors %}
         <tr><td colspan="{{ inline_admin_form.field_count }}">{{ inline_admin_form.form.non_field_errors }}</td></tr>
         </tr>
 
      {% endfor %}
-
+     </tbody>
    </table>
 
 </fieldset>

File django/contrib/admin/templatetags/admin_list.py

View file
  • Ignore whitespace
     elif i == cl.page_num:
         return mark_safe(u'<span class="this-page">%d</span> ' % (i+1))
     else:
-        return mark_safe(u'<a href="%s"%s>%d</a> ' % (cl.get_query_string({PAGE_VAR: i}), (i == cl.paginator.num_pages-1 and ' class="end"' or ''), i+1))
+        return mark_safe(u'<a href="%s"%s>%d</a> ' % (escape(cl.get_query_string({PAGE_VAR: i})), (i == cl.paginator.num_pages-1 and ' class="end"' or ''), i+1))
 paginator_number = register.simple_tag(paginator_number)
 
 def pagination(cl):
         day_lookup = cl.params.get(day_field)
         year_month_format, month_day_format = get_partial_date_formats()
 
-        link = lambda d: mark_safe(cl.get_query_string(d, [field_generic]))
+        link = lambda d: cl.get_query_string(d, [field_generic])
 
         if year_lookup and month_lookup and day_lookup:
             day = datetime.date(int(year_lookup), int(month_lookup), int(day_lookup))

File django/contrib/admin/widgets.py

View file
  • Ignore whitespace
 from django import forms
 from django.forms.widgets import RadioFieldRenderer
 from django.forms.util import flatatt
+from django.utils.html import escape
 from django.utils.text import truncate_words
 from django.utils.translation import ugettext as _
 from django.utils.safestring import mark_safe
     def label_for_value(self, value):
         key = self.rel.get_related_field().name
         obj = self.rel.to._default_manager.get(**{key: value})
-        return '&nbsp;<strong>%s</strong>' % truncate_words(obj, 14)
+        return '&nbsp;<strong>%s</strong>' % escape(truncate_words(obj, 14))
 
 class ManyToManyRawIdWidget(ForeignKeyRawIdWidget):
     """

File django/contrib/auth/tests/__init__.py

View file
  • Ignore whitespace
 
 __test__ = {
     'BASIC_TESTS': BASIC_TESTS,
-    'PASSWORDRESET_TESTS': PasswordResetTest,
     'FORM_TESTS': FORM_TESTS,
     'TOKEN_GENERATOR_TESTS': TOKEN_GENERATOR_TESTS,
-    'CHANGEPASSWORD_TESTS': ChangePasswordTest,
-    'LOGIN_TESTS': LoginTest,
-    'LOGOUT_TESTS': LogoutTest,
 }

File django/core/management/base.py

View file
  • Ignore whitespace
             if subdir.startswith('.'):
                 del subdirs[i]
         for f in files:
-            if f.endswith('.pyc'):
+            if not f.endswith('.py'):
+                # Ignore .pyc, .pyo, .py.class etc, as they cause various
+                # breakages.
                 continue
             path_old = os.path.join(d, f)
             path_new = os.path.join(top_dir, relative_dir, f.replace('%s_name' % app_or_project, name))

File django/core/urlresolvers.py

View file
  • Ignore whitespace
                     candidate = result % unicode_kwargs
                 if re.search(u'^%s' % pattern, candidate, re.UNICODE):
                     return candidate
+        # lookup_view can be URL label, or dotted path, or callable, Any of
+        # these can be passed in at the top, but callables are not friendly in
+        # error messages.
+        m = getattr(lookup_view, '__module__', None)
+        n = getattr(lookup_view, '__name__', None)
+        if m is not None and n is not None:
+            lookup_view_s = "%s.%s" % (m, n)
+        else:
+            lookup_view_s = lookup_view
         raise NoReverseMatch("Reverse for '%s' with arguments '%s' and keyword "
-                "arguments '%s' not found." % (lookup_view, args, kwargs))
+                "arguments '%s' not found." % (lookup_view_s, args, kwargs))
 
 def resolve(path, urlconf=None):
     return get_resolver(urlconf).resolve(path)

File django/forms/widgets.py

View file
  • Ignore whitespace
 class Textarea(Widget):
     def __init__(self, attrs=None):
         # The 'rows' and 'cols' attributes are required for HTML correctness.
-        self.attrs = {'cols': '40', 'rows': '10'}
+        default_attrs = {'cols': '40', 'rows': '10'}
         if attrs:
-            self.attrs.update(attrs)
+            default_attrs.update(attrs)
+        super(Textarea, self).__init__(default_attrs)
 
     def render(self, name, value, attrs=None):
         if value is None: value = ''

File django/utils/datastructures.py

View file
  • Ignore whitespace
         return iter(self.keyOrder)
 
     def values(self):
-        return [super(SortedDict, self).__getitem__(k) for k in self.keyOrder]
+        return map(super(SortedDict, self).__getitem__, self.keyOrder)
 
     def itervalues(self):
         for key in self.keyOrder:

File docs/ref/forms/widgets.txt

View file
  • Ignore whitespace
     .. versionchanged:: 1.1
        The ``date_format`` and ``time_format`` arguments were not supported in Django 1.0.
 
+.. class:: SelectDateWidget
+
+    Wrapper around three select widgets: one each for month, day, and year.
+    Note that this widget lives in a separate file from the standard widgets.
+
+    .. code-block:: python
+
+        from django.forms.extras.widgets import SelectDateWidget
+
+        date = forms.DateField(widget=SelectDateWidget())
 
 Specifying widgets
 ------------------

File docs/ref/request-response.txt

View file
  • Ignore whitespace
 
    Returns ``True`` if the request was made via an ``XMLHttpRequest``, by
    checking the ``HTTP_X_REQUESTED_WITH`` header for the string
-   ``'XMLHttpRequest'``. The following major JavaScript libraries all send this
-   header:
-
-       * jQuery
-       * Dojo
-       * MochiKit
-       * MooTools
-       * Prototype
-       * YUI
-
+   ``'XMLHttpRequest'``. Most modern JavaScript libraries send this header.
    If you write your own XMLHttpRequest call (on the browser side), you'll
    have to set this header manually if you want ``is_ajax()`` to work.
 

File docs/topics/auth.txt

View file
  • Ignore whitespace
 Authentication support is bundled as a Django application in
 ``django.contrib.auth``. To install it, do the following:
 
-    1. Put ``'django.contrib.auth'`` in your :setting:`INSTALLED_APPS` setting.
+    1. Put ``'django.contrib.auth'`` and ``'django.contrib.contenttypes'`` in
+       your :setting:`INSTALLED_APPS` setting.
+       (The :class:`~django.contrib.auth.models.Permisson` model in
+       :mod:`django.contrib.auth` depends on :mod:`django.contrib.contenttypes`.)
     2. Run the command ``manage.py syncdb``.
 
 Note that the default :file:`settings.py` file created by
-:djadmin:`django-admin.py startproject` includes ``'django.contrib.auth'`` in
-:setting:`INSTALLED_APPS` for convenience. If your :setting:`INSTALLED_APPS`
-already contains ``'django.contrib.auth'``, feel free to run
+:djadmin:`django-admin.py startproject` includes ``'django.contrib.auth'`` and
+``'django.contrib.contenttypes'`` in :setting:`INSTALLED_APPS` for convenience.
+If your :setting:`INSTALLED_APPS` already contains these apps, feel free to run
 :djadmin:`manage.py syncdb` again; you can run that command as many times as
 you'd like, and each time it'll only install what's needed.
 

File docs/topics/generic-views.txt

View file
  • Ignore whitespace
         publisher = models.ForeignKey(Publisher)
         publication_date = models.DateField()
 
-To build a list page of all books, we'd use a URLconf along these lines::
+To build a list page of all publishers, we'd use a URLconf along these lines::
 
     from django.conf.urls.defaults import *
     from django.views.generic import list_detail
 .. highlightlang:: html+django
 
 This template will be rendered against a context containing a variable called
-``object_list`` that contains all the book objects. A very simple template
+``object_list`` that contains all the publisher objects. A very simple template
 might look like the following::
 
     {% extends "base.html" %}
 You might have noticed that our sample publisher list template stores all the
 books in a variable named ``object_list``. While this works just fine, it isn't
 all that "friendly" to template authors: they have to "just know" that they're
-dealing with books here. A better name for that variable would be
+dealing with publishers here. A better name for that variable would be
 ``publisher_list``; that variable's content is pretty obvious.
 
 We can change the name of that variable easily with the ``template_object_name``
 --------------------
 
 Often you simply need to present some extra information beyond that provided by
-the generic view. For example, think of showing a list of all the other
-publishers on each publisher detail page. The ``object_detail`` generic view
-provides the publisher to the context, but it seems there's no way to get a list
-of *all* publishers in that template.
+the generic view. For example, think of showing a list of all the books on each
+publisher detail page. The ``object_detail`` generic view provides the
+publisher to the context, but it seems there's no way to get additional
+information in that template.
 
 But there is: all generic views take an extra optional parameter,
 ``extra_context``. This is a dictionary of extra objects that will be added to
-the template's context. So, to provide the list of all publishers on the detail
+the template's context. So, to provide the list of all books on the detail
 detail view, we'd use an info dict like this:
 
 .. parsed-literal::
 However, there's actually a subtle bug here -- can you spot it?
 
 The problem has to do with when the queries in ``extra_context`` are evaluated.
-Because this example puts ``Publisher.objects.all()`` in the URLconf, it will
+Because this example puts ``Book.objects.all()`` in the URLconf, it will
 be evaluated only once (when the URLconf is first loaded). Once you add or
-remove publishers, you'll notice that the generic view doesn't reflect those
+remove books, you'll notice that the generic view doesn't reflect those
 changes until you reload the Web server (see :ref:`caching-and-querysets`
 for more information about when QuerySets are cached and evaluated).
 

File tests/regressiontests/admin_views/tests.py

View file
  • Ignore whitespace
                      LOGIN_FORM_KEY: 1,
                      'username': 'joepublic',
                      'password': 'secret'}
+        self.no_username_login = {
+                     LOGIN_FORM_KEY: 1,
+                     'password': 'secret'}
 
     def testLogin(self):
         """
         # Login.context is a list of context dicts we just need to check the first one.
         self.assert_(login.context[0].get('error_message'))
 
+        # Requests without username should not return 500 errors.
+        request = self.client.get('/test_admin/admin/')
+        self.failUnlessEqual(request.status_code, 200)
+        login = self.client.post('/test_admin/admin/', self.no_username_login)
+        self.failUnlessEqual(login.status_code, 200)
+        # Login.context is a list of context dicts we just need to check the first one.
+        self.assert_(login.context[0].get('error_message'))
+
     def testLoginSuccessfullyRedirectsToOriginalUrl(self):
         request = self.client.get('/test_admin/admin/')
         self.failUnlessEqual(request.status_code, 200)

File tests/regressiontests/forms/error_messages.py

View file
  • Ignore whitespace
 Traceback (most recent call last):
 ...
 ValidationError: [u'4 IS INVALID CHOICE']
+
+# Subclassing ErrorList #######################################################
+
+>>> from django.utils.safestring import mark_safe
+>>>
+>>> class TestForm(Form):
+...      first_name = CharField()
+...      last_name = CharField()
+...      birthday = DateField()
+...
+...      def clean(self):
+...          raise ValidationError("I like to be awkward.")
+...
+>>> class CustomErrorList(util.ErrorList):
+...      def __unicode__(self):
+...          return self.as_divs()
+...      def as_divs(self):
+...          if not self: return u''
+...          return mark_safe(u'<div class="error">%s</div>'
+...                    % ''.join([u'<p>%s</p>' % e for e in self]))
+...
+
+This form should print errors the default way.
+
+>>> form1 = TestForm({'first_name': 'John'})
+>>> print form1['last_name'].errors
+<ul class="errorlist"><li>This field is required.</li></ul>
+>>> print form1.errors['__all__']
+<ul class="errorlist"><li>I like to be awkward.</li></ul>
+
+This one should wrap error groups in the customized way.
+
+>>> form2 = TestForm({'first_name': 'John'}, error_class=CustomErrorList)
+>>> print form2['last_name'].errors
+<div class="error"><p>This field is required.</p></div>
+>>> print form2.errors['__all__']
+<div class="error"><p>I like to be awkward.</p></div>
+
 """

File tests/regressiontests/templates/filters.py

View file
  • Ignore whitespace
         'filter-force-escape05': ('{% autoescape off %}{{ a|force_escape|escape }}{% endautoescape %}', {"a": "x&y"}, u"x&amp;y"),
         'filter-force-escape06': ('{{ a|force_escape|escape }}', {"a": "x&y"}, u"x&amp;y"),
         'filter-force-escape07': ('{% autoescape off %}{{ a|escape|force_escape }}{% endautoescape %}', {"a": "x&y"}, u"x&amp;y"),
-        'filter-force-escape07': ('{{ a|escape|force_escape }}', {"a": "x&y"}, u"x&amp;y"),
+        'filter-force-escape08': ('{{ a|escape|force_escape }}', {"a": "x&y"}, u"x&amp;y"),
 
         # The contents in "linebreaks" and "linebreaksbr" are escaped
         # according to the current autoescape setting.