summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorUnai Zalakain <unai@gisa-elkartea.org>2013-10-24 17:28:09 +0200
committerSimon Charette <charette.s@gmail.com>2013-10-29 17:10:12 -0400
commitfd219fa24c7911adab60e1f5e4fd3d7f9d82a969 (patch)
treebebe575f54927599841c3be976eccfeeb7d84e49 /tests
parent497930b7f69e2c298faa3f784c4523ea351e5e6f (diff)
Fixed #8261 -- ModelAdmin hook for customising the "show on site" button
``ModelAdmin.view_on_site`` defines wether to show a link to the object on the admin detail page. If ``True``, cleverness (i.e. ``Model.get_absolute_url``) is used to get the url. If it's a callable, the callable is called with the object as the only parameter. If ``False``, not link is displayed. With the aim of maitaining backwards compatibility, ``True`` is the default.
Diffstat (limited to 'tests')
-rw-r--r--tests/admin_views/admin.py36
-rw-r--r--tests/admin_views/fixtures/admin-views-restaurants.xml63
-rw-r--r--tests/admin_views/models.py16
-rw-r--r--tests/admin_views/tests.py89
4 files changed, 201 insertions, 3 deletions
diff --git a/tests/admin_views/admin.py b/tests/admin_views/admin.py
index 7dd6c91e71..36b35aeefe 100644
--- a/tests/admin_views/admin.py
+++ b/tests/admin_views/admin.py
@@ -31,7 +31,7 @@ from .models import (Article, Chapter, Account, Media, Child, Parent, Picture,
AdminOrderedCallable, Report, Color2, UnorderedObject, MainPrepopulated,
RelatedPrepopulated, UndeletableObject, UnchangeableObject, UserMessenger, Simple, Choice,
ShortMessage, Telegram, FilteredManager, EmptyModelHidden,
- EmptyModelVisible, EmptyModelMixin)
+ EmptyModelVisible, EmptyModelMixin, State, City, Restaurant, Worker)
def callable_year(dt_value):
@@ -74,6 +74,7 @@ class ChapterXtra1Admin(admin.ModelAdmin):
class ArticleAdmin(admin.ModelAdmin):
list_display = ('content', 'date', callable_year, 'model_year', 'modeladmin_year')
list_filter = ('date', 'section')
+ view_on_site = False
fieldsets = (
('Some fields', {
'classes': ('collapse',),
@@ -735,6 +736,35 @@ class EmptyModelMixinAdmin(admin.ModelAdmin):
form = FormWithVisibleAndHiddenField
fieldsets = EmptyModelVisibleAdmin.fieldsets
+class CityInlineAdmin(admin.TabularInline):
+ model = City
+ view_on_site = False
+
+class StateAdmin(admin.ModelAdmin):
+ inlines = [CityInlineAdmin]
+
+class RestaurantInlineAdmin(admin.TabularInline):
+ model = Restaurant
+ view_on_site = True
+
+class CityAdmin(admin.ModelAdmin):
+ inlines = [RestaurantInlineAdmin]
+ view_on_site = True
+
+class WorkerAdmin(admin.ModelAdmin):
+ def view_on_site(self, obj):
+ return '/worker/%s/%s/' % (obj.surname, obj.name)
+
+class WorkerInlineAdmin(admin.TabularInline):
+ model = Worker
+
+ def view_on_site(self, obj):
+ return '/worker_inline/%s/%s/' % (obj.surname, obj.name)
+
+class RestaurantAdmin(admin.ModelAdmin):
+ inlines = [WorkerInlineAdmin]
+ view_on_site = False
+
site = admin.AdminSite(name="admin")
site.register(Article, ArticleAdmin)
site.register(CustomArticle, CustomArticleAdmin)
@@ -785,6 +815,10 @@ site.register(MainPrepopulated, MainPrepopulatedAdmin)
site.register(UnorderedObject, UnorderedObjectAdmin)
site.register(UndeletableObject, UndeletableObjectAdmin)
site.register(UnchangeableObject, UnchangeableObjectAdmin)
+site.register(State, StateAdmin)
+site.register(City, CityAdmin)
+site.register(Restaurant, RestaurantAdmin)
+site.register(Worker, WorkerAdmin)
# We intentionally register Promo and ChapterXtra1 but not Chapter nor ChapterXtra2.
# That way we cover all four cases:
diff --git a/tests/admin_views/fixtures/admin-views-restaurants.xml b/tests/admin_views/fixtures/admin-views-restaurants.xml
new file mode 100644
index 0000000000..81e67ee8d0
--- /dev/null
+++ b/tests/admin_views/fixtures/admin-views-restaurants.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="utf-8"?>
+<django-objects version="1.0">
+ <object pk="1" model="admin_views.state">
+ <field type="CharField" name="name">New York</field>
+ </object>
+ <object pk="2" model="admin_views.state">
+ <field type="CharField" name="name">Illinois</field>
+ </object>
+ <object pk="3" model="admin_views.state">
+ <field type="CharField" name="name">California</field>
+ </object>
+ <object pk="1" model="admin_views.city">
+ <field to="admin_views.state" name="state" rel="ManyToOneRel">1</field>
+ <field type="CharField" name="name">New York</field>
+ </object>
+ <object pk="2" model="admin_views.city">
+ <field to="admin_views.state" name="state" rel="ManyToOneRel">2</field>
+ <field type="CharField" name="name">Chicago</field>
+ </object>
+ <object pk="3" model="admin_views.city">
+ <field to="admin_views.state" name="state" rel="ManyToOneRel">3</field>
+ <field type="CharField" name="name">San Francisco</field>
+ </object>
+ <object pk="1" model="admin_views.restaurant">
+ <field to="admin_views.city" name="city" rel="ManyToOneRel">1</field>
+ <field type="CharField" name="name">Italian Pizza</field>
+ </object>
+ <object pk="2" model="admin_views.restaurant">
+ <field to="admin_views.city" name="city" rel="ManyToOneRel">1</field>
+ <field type="CharField" name="name">Boulevard</field>
+ </object>
+ <object pk="3" model="admin_views.restaurant">
+ <field to="admin_views.city" name="city" rel="ManyToOneRel">2</field>
+ <field type="CharField" name="name">Chinese Dinner</field>
+ </object>
+ <object pk="4" model="admin_views.restaurant">
+ <field to="admin_views.city" name="city" rel="ManyToOneRel">2</field>
+ <field type="CharField" name="name">Angels</field>
+ </object>
+ <object pk="5" model="admin_views.restaurant">
+ <field to="admin_views.city" name="city" rel="ManyToOneRel">2</field>
+ <field type="CharField" name="name">Take Away</field>
+ </object>
+ <object pk="6" model="admin_views.restaurant">
+ <field to="admin_views.city" name="city" rel="ManyToOneRel">3</field>
+ <field type="CharField" name="name">The Unknown Restaurant</field>
+ </object>
+ <object pk="1" model="admin_views.worker">
+ <field to="admin_views.restaurant" name="work_at" rel="ManyToOneRel">1</field>
+ <field type="CharField" name="name">Mario</field>
+ <field type="CharField" name="surname">Rossi</field>
+ </object>
+ <object pk="2" model="admin_views.worker">
+ <field to="admin_views.restaurant" name="work_at" rel="ManyToOneRel">1</field>
+ <field type="CharField" name="name">Antonio</field>
+ <field type="CharField" name="surname">Bianchi</field>
+ </object>
+ <object pk="3" model="admin_views.worker">
+ <field to="admin_views.restaurant" name="work_at" rel="ManyToOneRel">1</field>
+ <field type="CharField" name="name">John</field>
+ <field type="CharField" name="surname">Doe</field>
+ </object>
+</django-objects>
diff --git a/tests/admin_views/models.py b/tests/admin_views/models.py
index bab144e6b5..67f3b4216a 100644
--- a/tests/admin_views/models.py
+++ b/tests/admin_views/models.py
@@ -717,3 +717,19 @@ class EmptyModelHidden(models.Model):
class EmptyModelMixin(models.Model):
""" See ticket #11277. """
+
+class State(models.Model):
+ name = models.CharField(max_length=100)
+
+class City(models.Model):
+ state = models.ForeignKey(State)
+ name = models.CharField(max_length=100)
+
+class Restaurant(models.Model):
+ city = models.ForeignKey(City)
+ name = models.CharField(max_length=100)
+
+class Worker(models.Model):
+ work_at = models.ForeignKey(Restaurant)
+ name = models.CharField(max_length=50)
+ surname = models.CharField(max_length=50)
diff --git a/tests/admin_views/tests.py b/tests/admin_views/tests.py
index 16fea943f9..d5232fb8f2 100644
--- a/tests/admin_views/tests.py
+++ b/tests/admin_views/tests.py
@@ -9,6 +9,7 @@ import unittest
from django.conf import settings, global_settings
from django.core import mail
from django.core.files import temp as tempfile
+from django.core.exceptions import ImproperlyConfigured
from django.core.urlresolvers import reverse, NoReverseMatch
# Register auth models with the admin.
from django.contrib.auth import get_permission_codename
@@ -48,8 +49,8 @@ from .models import (Article, BarAccount, CustomArticle, EmptyModel, FooAccount,
AdminOrderedModelMethod, AdminOrderedAdminMethod, AdminOrderedCallable,
Report, MainPrepopulated, RelatedPrepopulated, UnorderedObject,
Simple, UndeletableObject, UnchangeableObject, Choice, ShortMessage,
- Telegram, Pizza, Topping, FilteredManager)
-from .admin import site, site2
+ Telegram, Pizza, Topping, FilteredManager, City, Restaurant, Worker)
+from .admin import site, site2, CityAdmin
ERROR_MESSAGE = "Please enter the correct username and password \
@@ -4597,3 +4598,87 @@ class TestLabelVisibility(TestCase):
def assert_fieldline_hidden(self, response):
self.assertContains(response, '<div class="form-row hidden')
+
+
+@override_settings(PASSWORD_HASHERS=('django.contrib.auth.hashers.SHA1PasswordHasher',))
+class AdminViewOnSiteTest(TestCase):
+ urls = "admin_views.urls"
+ fixtures = ['admin-views-users.xml', 'admin-views-restaurants.xml']
+
+ def setUp(self):
+ self.client.login(username='super', password='secret')
+
+ def tearDown(self):
+ self.client.logout()
+
+ def test_validate(self):
+ "Ensure that the view_on_site value is either a boolean or a callable"
+ CityAdmin.view_on_site = True
+ CityAdmin.validate(City)
+ CityAdmin.view_on_site = False
+ CityAdmin.validate(City)
+ CityAdmin.view_on_site = lambda obj: obj.get_absolute_url()
+ CityAdmin.validate(City)
+ CityAdmin.view_on_site = []
+ with self.assertRaisesMessage(ImproperlyConfigured, 'CityAdmin.view_on_site is not a callable or a boolean value.'):
+ CityAdmin.validate(City)
+
+ def test_false(self):
+ "Ensure that the 'View on site' button is not displayed if view_on_site is False"
+ response = self.client.get('/test_admin/admin/admin_views/restaurant/1/')
+ content_type_pk = ContentType.objects.get_for_model(Restaurant).pk
+ self.assertNotContains(response,
+ '"/test_admin/admin/r/%s/1/"' % content_type_pk,
+ )
+
+ def test_true(self):
+ "Ensure that the default behaviour is followed if view_on_site is True"
+ response = self.client.get('/test_admin/admin/admin_views/city/1/')
+ content_type_pk = ContentType.objects.get_for_model(City).pk
+ self.assertContains(response,
+ '"/test_admin/admin/r/%s/1/"' % content_type_pk,
+ )
+
+ def test_callable(self):
+ "Ensure that the right link is displayed if view_on_site is a callable"
+ response = self.client.get('/test_admin/admin/admin_views/worker/1/')
+ worker = Worker.objects.get(pk=1)
+ self.assertContains(response,
+ '"/worker/%s/%s/"' % (worker.surname, worker.name),
+ )
+
+
+@override_settings(PASSWORD_HASHERS=('django.contrib.auth.hashers.SHA1PasswordHasher',))
+class InlineAdminViewOnSiteTest(TestCase):
+ urls = "admin_views.urls"
+ fixtures = ['admin-views-users.xml', 'admin-views-restaurants.xml']
+
+ def setUp(self):
+ self.client.login(username='super', password='secret')
+
+ def tearDown(self):
+ self.client.logout()
+
+ def test_false(self):
+ "Ensure that the 'View on site' button is not displayed if view_on_site is False"
+ response = self.client.get('/test_admin/admin/admin_views/state/1/')
+ content_type_pk = ContentType.objects.get_for_model(City).pk
+ self.assertNotContains(response,
+ '/test_admin/admin/r/%s/1/' % content_type_pk,
+ )
+
+ def test_true(self):
+ "Ensure that the 'View on site' button is displayed if view_on_site is True"
+ response = self.client.get('/test_admin/admin/admin_views/city/1/')
+ content_type_pk = ContentType.objects.get_for_model(Restaurant).pk
+ self.assertContains(response,
+ '/test_admin/admin/r/%s/1/' % content_type_pk,
+ )
+
+ def test_callable(self):
+ "Ensure that the right link is displayed if view_on_site is a callable"
+ response = self.client.get('/test_admin/admin/admin_views/restaurant/1/')
+ worker = Worker.objects.get(pk=1)
+ self.assertContains(response,
+ '"/worker_inline/%s/%s/"' % (worker.surname, worker.name),
+ )