Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

17890: added support for extra_context in django.contrib.admin.site.password_change #499

Closed
wants to merge 12 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions django/contrib/admin/sites.py
Original file line number Diff line number Diff line change
Expand Up @@ -256,15 +256,16 @@ def wrapper(*args, **kwargs):
def urls(self):
return self.get_urls(), self.app_name, self.name

def password_change(self, request):
def password_change(self, request, extra_context=None):
"""
Handles the "change password" task -- both form display and validation.
"""
from django.contrib.auth.views import password_change
url = reverse('admin:password_change_done', current_app=self.name)
defaults = {
'current_app': self.name,
'post_change_redirect': url
'post_change_redirect': url,
'extra_context': extra_context
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be extra_context or {}, (include a trailing comma)

}
if self.password_change_template is not None:
defaults['template_name'] = self.password_change_template
Expand Down
1 change: 0 additions & 1 deletion django/contrib/contenttypes/generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
from django.db.models import signals
from django.db import models, router, DEFAULT_DB_ALIAS
from django.db.models.fields.related import RelatedField, Field, ManyToManyRel
from django.db.models.loading import get_model
from django.forms import ModelForm
from django.forms.models import BaseModelFormSet, modelformset_factory, save_instance
from django.contrib.admin.options import InlineModelAdmin, flatten_fieldsets
Expand Down
2 changes: 1 addition & 1 deletion django/forms/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ def model_to_dict(instance, fields=None, exclude=None):
data[f.name] = []
else:
# MultipleChoiceWidget needs a list of pks, not object instances.
data[f.name] = [obj.pk for obj in f.value_from_object(instance)]
data[f.name] = list(f.value_from_object(instance).values_list('pk', flat=True))
else:
data[f.name] = f.value_from_object(instance)
return data
Expand Down
7 changes: 4 additions & 3 deletions django/views/generic/list.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,10 @@ def paginate_queryset(self, queryset, page_size):
try:
page = paginator.page(page_number)
return (paginator, page, page.object_list, page.has_other_pages())
except InvalidPage:
raise Http404(_('Invalid page (%(page_number)s)') % {
'page_number': page_number
except InvalidPage as e:
raise Http404(_('Invalid page (%(page_number)s): %(message)s') % {
'page_number': page_number,
'message': str(e)
})

def get_paginate_by(self, queryset):
Expand Down
4 changes: 2 additions & 2 deletions docs/ref/models/options.txt
Original file line number Diff line number Diff line change
Expand Up @@ -263,10 +263,10 @@ Django quotes column and table names behind the scenes.

``index_together``

.. versionadded:: 1.5

.. attribute:: Options.index_together

.. versionadded:: 1.5

Sets of field names that, taken together, are indexed::

index_together = [
Expand Down
22 changes: 11 additions & 11 deletions docs/ref/templates/builtins.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1505,27 +1505,27 @@ that many decimal places. For example:
``34.26000`` ``{{ value|floatformat:3 }}`` ``34.260``
============ ============================= ==========

If the argument passed to ``floatformat`` is negative, it will round a number
to that many decimal places -- but only if there's a decimal part to be
displayed. For example:
Particularly useful is passing 0 (zero) as the argument which will round the
float to the nearest integer.

============ ================================ ==========
``value`` Template Output
============ ================================ ==========
``34.23234`` ``{{ value|floatformat:"-3" }}`` ``34.232``
``34.00000`` ``{{ value|floatformat:"-3" }}`` ``34``
``34.26000`` ``{{ value|floatformat:"-3" }}`` ``34.260``
``34.23234`` ``{{ value|floatformat:"0" }}`` ``34``
``34.00000`` ``{{ value|floatformat:"0" }}`` ``34``
``39.56000`` ``{{ value|floatformat:"0" }}`` ``40``
============ ================================ ==========

If the argument passed to ``floatformat`` is 0 (zero), it will round the number
to the nearest integer.
If the argument passed to ``floatformat`` is negative, it will round a number
to that many decimal places -- but only if there's a decimal part to be
displayed. For example:

============ ================================ ==========
``value`` Template Output
============ ================================ ==========
``34.23234`` ``{{ value|floatformat:"0" }}`` ``34``
``34.00000`` ``{{ value|floatformat:"0" }}`` ``34``
``39.56000`` ``{{ value|floatformat:"0" }}`` ``40``
``34.23234`` ``{{ value|floatformat:"-3" }}`` ``34.232``
``34.00000`` ``{{ value|floatformat:"-3" }}`` ``34``
``34.26000`` ``{{ value|floatformat:"-3" }}`` ``34.260``
============ ================================ ==========

Using ``floatformat`` with no argument is equivalent to using ``floatformat``
Expand Down
4 changes: 4 additions & 0 deletions docs/releases/1.5.txt
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,10 @@ Django 1.5 also includes several smaller improvements worth noting:
* The :ref:`cache-based session backend <cached-sessions-backend>` can store
session data in a non-default cache.

* Multi-column indexes can now be created on models. Read the
:attr:`~django.db.models.Options.index_together` documentation for more
information.

Backwards incompatible changes in 1.5
=====================================

Expand Down
41 changes: 40 additions & 1 deletion tests/modeltests/model_forms/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -561,6 +561,42 @@ def test_unique_for_date_with_nullable_date(self):
"slug": "Django 1.0"}, instance=p)
self.assertTrue(form.is_valid())

class ModelToDictTests(TestCase):
"""
Tests for forms.models.model_to_dict
"""
def test_model_to_dict_many_to_many(self):
categories=[
Category(name='TestName1', slug='TestName1', url='url1'),
Category(name='TestName2', slug='TestName2', url='url2'),
Category(name='TestName3', slug='TestName3', url='url3')
]
for c in categories:
c.save()
writer = Writer(name='Test writer')
writer.save()

art = Article(
headline='Test article',
slug='test-article',
pub_date=datetime.date(1988, 1, 4),
writer=writer,
article='Hello.'
)
art.save()
for c in categories:
art.categories.add(c)
art.save()

with self.assertNumQueries(1):
d = model_to_dict(art)

#Ensure all many-to-many categories appear in model_to_dict
for c in categories:
self.assertIn(c.pk, d['categories'])
#Ensure many-to-many relation appears as a list
self.assertIsInstance(d['categories'], list)

class OldFormForXTests(TestCase):
def test_base_form(self):
self.assertEqual(Category.objects.count(), 0)
Expand Down Expand Up @@ -1024,7 +1060,10 @@ def test_with_data(self):
# Add a Category object *after* the ModelMultipleChoiceField has already been
# instantiated. This proves clean() checks the database during clean() rather
# than caching it at time of instantiation.
c6 = Category.objects.create(id=6, name='Sixth', url='6th')
# Note, we are using an id of 1006 here since tests that run before
# this may create categories with primary keys up to 6. Use
# a number that is will not conflict.
c6 = Category.objects.create(id=1006, name='Sixth', url='6th')
self.assertEqual(c6.name, 'Sixth')
self.assertQuerysetEqual(f.clean([c6.id]), ["Sixth"])

Expand Down
3 changes: 3 additions & 0 deletions tests/regressiontests/admin_views/customadmin.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ class Admin2(admin.AdminSite):
def index(self, request, extra_context=None):
return super(Admin2, self).index(request, {'foo': '*bar*'})

def password_change(self, request, extra_context={'EXTRA_CONTEXT': 'this is some extra context'}):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pass the context like the index method above does. it's bad practice to include mutables (in this case a dictionary) as the default of a kwarg

return super(Admin2, self).password_change(request, extra_context)

def get_urls(self):
return patterns('',
(r'^my_view/$', self.admin_view(self.my_view)),
Expand Down
7 changes: 7 additions & 0 deletions tests/regressiontests/admin_views/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -781,6 +781,13 @@ def testCustomAdminSitePasswordChangeTemplate(self):
self.assertTemplateUsed(response, 'custom_admin/password_change_form.html')
self.assertContains(response, 'Hello from a custom password change form template')

def testCustomAdminSitePasswordChangeWithExtraContext(self):
"#17890: Test support for extra_context in password_change"
request = self.client.get('/test_admin/admin2/password_change/')
self.assertIsInstance(request, TemplateResponse)
self.assertTemplateUsed(request, 'custom_admin/password_change_form.html')
self.assertTrue('this is some extra context' in request.content)

def testCustomAdminSitePasswordChangeDoneTemplate(self):
response = self.client.get('/test_admin/admin2/password_change/done/')
self.assertIsInstance(response, TemplateResponse)
Expand Down
13 changes: 12 additions & 1 deletion tests/regressiontests/generic_views/list.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

from django.core.exceptions import ImproperlyConfigured
from django.test import TestCase
from django.test.utils import override_settings
from django.views.generic.base import View
from django.utils.encoding import force_str

from .models import Author, Artist

Expand Down Expand Up @@ -171,8 +173,17 @@ def test_paginated_list_view_does_not_load_entire_table(self):
with self.assertNumQueries(3):
self.client.get('/list/authors/notempty/paginated/')

@override_settings(DEBUG=True)
def test_paginated_list_view_returns_useful_message_on_invalid_page(self):
# test for #19240
# tests that source exception's message is included in page
self._make_authors(1)
res = self.client.get('/list/authors/paginated/2/')
self.assertEqual(res.status_code, 404)
self.assertEqual(force_str(res.context.get('reason')),
"Invalid page (2): That page contains no results")

def _make_authors(self, n):
Author.objects.all().delete()
for i in range(n):
Author.objects.create(name='Author %02i' % i, slug='a%s' % i)

1 change: 1 addition & 0 deletions tests/templates/custom_admin/password_change_form.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@

{% block content %}
Hello from a custom password change form template
{{ EXTRA_CONTEXT }}
{{ block.super }}
{% endblock %}