summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorChristopher Adams <christopher.r.adams@gmail.com>2014-02-01 14:23:31 -0500
committerTim Graham <timograham@gmail.com>2014-02-11 14:05:12 -0500
commiteefc88feefec0c3685bfb102714530b751b4ae90 (patch)
tree3cab4b02c13b76b6355d475d91ca2e157a126b18 /tests
parenta718fcf201b04ba254e9073be82f51ae1ae3a853 (diff)
Fixed #2445 -- Allowed limit_choices_to attribute to be a callable.
ForeignKey or ManyToManyField attribute ``limit_choices_to`` can now be a callable that returns either a ``Q`` object or a dict. Thanks michael at actrix.gen.nz for the original suggestion.
Diffstat (limited to 'tests')
-rw-r--r--tests/admin_views/admin.py3
-rw-r--r--tests/admin_views/models.py27
-rw-r--r--tests/admin_views/tests.py29
-rw-r--r--tests/model_forms/models.py20
-rw-r--r--tests/model_forms/tests.py40
5 files changed, 115 insertions, 4 deletions
diff --git a/tests/admin_views/admin.py b/tests/admin_views/admin.py
index ae12764897..e17942e831 100644
--- a/tests/admin_views/admin.py
+++ b/tests/admin_views/admin.py
@@ -34,7 +34,7 @@ from .models import (Article, Chapter, Child, Parent, Picture, Widget,
UnchangeableObject, UserMessenger, Simple, Choice, ShortMessage, Telegram,
FilteredManager, EmptyModelHidden, EmptyModelVisible, EmptyModelMixin,
State, City, Restaurant, Worker, ParentWithDependentChildren,
- DependentChild)
+ DependentChild, StumpJoke)
def callable_year(dt_value):
@@ -884,6 +884,7 @@ site.register(ParentWithDependentChildren, ParentWithDependentChildrenAdmin)
site.register(EmptyModelHidden, EmptyModelHiddenAdmin)
site.register(EmptyModelVisible, EmptyModelVisibleAdmin)
site.register(EmptyModelMixin, EmptyModelMixinAdmin)
+site.register(StumpJoke)
# Register core models we need in our tests
from django.contrib.auth.models import User, Group
diff --git a/tests/admin_views/models.py b/tests/admin_views/models.py
index ac4d4f20c5..4cc58f5e88 100644
--- a/tests/admin_views/models.py
+++ b/tests/admin_views/models.py
@@ -173,6 +173,33 @@ class Sketch(models.Model):
return self.title
+def today_callable_dict():
+ return {"last_action__gte": datetime.datetime.today()}
+
+
+def today_callable_q():
+ return models.Q(last_action__gte=datetime.datetime.today())
+
+
+@python_2_unicode_compatible
+class Character(models.Model):
+ username = models.CharField(max_length=100)
+ last_action = models.DateTimeField()
+
+ def __str__(self):
+ return self.username
+
+
+@python_2_unicode_compatible
+class StumpJoke(models.Model):
+ variation = models.CharField(max_length=100)
+ most_recently_fooled = models.ForeignKey(Character, limit_choices_to=today_callable_dict, related_name="+")
+ has_fooled_today = models.ManyToManyField(Character, limit_choices_to=today_callable_q, related_name="+")
+
+ def __str__(self):
+ return self.variation
+
+
class Fabric(models.Model):
NG_CHOICES = (
('Textured', (
diff --git a/tests/admin_views/tests.py b/tests/admin_views/tests.py
index 2bfc3258f5..f5c90bc1d0 100644
--- a/tests/admin_views/tests.py
+++ b/tests/admin_views/tests.py
@@ -52,7 +52,7 @@ from .models import (Article, BarAccount, CustomArticle, EmptyModel, FooAccount,
Report, MainPrepopulated, RelatedPrepopulated, UnorderedObject,
Simple, UndeletableObject, UnchangeableObject, Choice, ShortMessage,
Telegram, Pizza, Topping, FilteredManager, City, Restaurant, Worker,
- ParentWithDependentChildren)
+ ParentWithDependentChildren, Character)
from .admin import site, site2, CityAdmin
@@ -3662,6 +3662,33 @@ class ReadonlyTest(TestCase):
@override_settings(PASSWORD_HASHERS=('django.contrib.auth.hashers.SHA1PasswordHasher',))
+class LimitChoicesToInAdminTest(TestCase):
+ urls = "admin_views.urls"
+ fixtures = ['admin-views-users.xml']
+
+ def setUp(self):
+ self.client.login(username='super', password='secret')
+
+ def tearDown(self):
+ self.client.logout()
+
+ def test_limit_choices_to_as_callable(self):
+ """Test for ticket 2445 changes to admin."""
+ threepwood = Character.objects.create(
+ username='threepwood',
+ last_action=datetime.datetime.today() + datetime.timedelta(days=1),
+ )
+ marley = Character.objects.create(
+ username='marley',
+ last_action=datetime.datetime.today() - datetime.timedelta(days=1),
+ )
+ response = self.client.get('/test_admin/admin/admin_views/stumpjoke/add/')
+ # The allowed option should appear twice; the limited option should not appear.
+ self.assertContains(response, threepwood.username, count=2)
+ self.assertNotContains(response, marley.username)
+
+
+@override_settings(PASSWORD_HASHERS=('django.contrib.auth.hashers.SHA1PasswordHasher',))
class RawIdFieldsTest(TestCase):
urls = "admin_views.urls"
fixtures = ['admin-views-users.xml']
diff --git a/tests/model_forms/models.py b/tests/model_forms/models.py
index 72bf1ff26a..2b83a179ed 100644
--- a/tests/model_forms/models.py
+++ b/tests/model_forms/models.py
@@ -8,6 +8,7 @@ words, most of these tests should be rewritten.
"""
from __future__ import unicode_literals
+import datetime
import os
import tempfile
@@ -71,7 +72,6 @@ class Article(models.Model):
status = models.PositiveIntegerField(choices=ARTICLE_STATUS, blank=True, null=True)
def save(self):
- import datetime
if not self.id:
self.created = datetime.date.today()
return super(Article, self).save()
@@ -329,3 +329,21 @@ class CustomErrorMessage(models.Model):
def clean(self):
if self.name1 == 'FORBIDDEN_VALUE':
raise ValidationError({'name1': [ValidationError('Model.clean() error messages.')]})
+
+
+def today_callable_dict():
+ return {"last_action__gte": datetime.datetime.today()}
+
+
+def today_callable_q():
+ return models.Q(last_action__gte=datetime.datetime.today())
+
+
+class Character(models.Model):
+ username = models.CharField(max_length=100)
+ last_action = models.DateTimeField()
+
+
+class StumpJoke(models.Model):
+ most_recently_fooled = models.ForeignKey(Character, limit_choices_to=today_callable_dict, related_name="+")
+ has_fooled_today = models.ManyToManyField(Character, limit_choices_to=today_callable_q, related_name="+")
diff --git a/tests/model_forms/tests.py b/tests/model_forms/tests.py
index c64bad5241..a0507a1e1c 100644
--- a/tests/model_forms/tests.py
+++ b/tests/model_forms/tests.py
@@ -22,7 +22,8 @@ from .models import (Article, ArticleStatus, BetterWriter, BigInt, Book,
DerivedPost, ExplicitPK, FlexibleDatePost, ImprovedArticle,
ImprovedArticleWithParentLink, Inventory, Post, Price,
Product, TextFile, Writer, WriterProfile, Colour, ColourfulItem,
- ArticleStatusNote, DateTimePost, CustomErrorMessage, test_images)
+ ArticleStatusNote, DateTimePost, CustomErrorMessage, test_images,
+ StumpJoke, Character)
if test_images:
from .models import ImageFile, OptionalImageFile
@@ -521,6 +522,12 @@ class FieldOverridesTroughFormMetaForm(forms.ModelForm):
}
+class StumpJokeForm(forms.ModelForm):
+ class Meta:
+ model = StumpJoke
+ fields = '__all__'
+
+
class TestFieldOverridesTroughFormMeta(TestCase):
def test_widget_overrides(self):
form = FieldOverridesTroughFormMetaForm()
@@ -1921,3 +1928,34 @@ class ModelFormInheritanceTests(TestCase):
self.assertEqual(list(type(str('NewForm'), (ModelForm, Mixin, Form), {})().fields.keys()), ['name'])
self.assertEqual(list(type(str('NewForm'), (ModelForm, Form, Mixin), {})().fields.keys()), ['name', 'age'])
self.assertEqual(list(type(str('NewForm'), (ModelForm, Form), {'age': None})().fields.keys()), ['name'])
+
+
+class LimitChoicesToTest(TestCase):
+ """
+ Tests the functionality of ``limit_choices_to``.
+ """
+ def setUp(self):
+ self.threepwood = Character.objects.create(
+ username='threepwood',
+ last_action=datetime.datetime.today() + datetime.timedelta(days=1),
+ )
+ self.marley = Character.objects.create(
+ username='marley',
+ last_action=datetime.datetime.today() - datetime.timedelta(days=1),
+ )
+
+ def test_limit_choices_to_callable_for_fk_rel(self):
+ """
+ A ForeignKey relation can use ``limit_choices_to`` as a callable, re #2554.
+ """
+ stumpjokeform = StumpJokeForm()
+ self.assertIn(self.threepwood, stumpjokeform.fields['most_recently_fooled'].queryset)
+ self.assertNotIn(self.marley, stumpjokeform.fields['most_recently_fooled'].queryset)
+
+ def test_limit_choices_to_callable_for_m2m_rel(self):
+ """
+ A ManyToMany relation can use ``limit_choices_to`` as a callable, re #2554.
+ """
+ stumpjokeform = StumpJokeForm()
+ self.assertIn(self.threepwood, stumpjokeform.fields['has_fooled_today'].queryset)
+ self.assertNotIn(self.marley, stumpjokeform.fields['has_fooled_today'].queryset)