Ticket #15294: admin_tests_urls_fixes.diff
File admin_tests_urls_fixes.diff, 77.6 KB (added by , 13 years ago) |
---|
-
new file tests/regressiontests/admin_changelist/admin.py
diff --git a/tests/regressiontests/admin_changelist/admin.py b/tests/regressiontests/admin_changelist/admin.py new file mode 100644
- + 1 from django.core.paginator import Paginator 2 from django.contrib import admin 3 4 from models import (Child, Parent, Genre, Band, Musician, Group, Quartet, 5 Membership, ChordsMusician, ChordsBand, Invitation) 6 7 site = admin.AdminSite(name="admin") 8 9 class CustomPaginator(Paginator): 10 def __init__(self, queryset, page_size, orphans=0, allow_empty_first_page=True): 11 super(CustomPaginator, self).__init__(queryset, 5, orphans=2, 12 allow_empty_first_page=allow_empty_first_page) 13 14 15 class ParentAdmin(admin.ModelAdmin): 16 list_filter = ['child__name'] 17 search_fields = ['child__name'] 18 19 20 class ChildAdmin(admin.ModelAdmin): 21 list_display = ['name', 'parent'] 22 list_per_page = 10 23 24 def queryset(self, request): 25 return super(ChildAdmin, self).queryset(request).select_related("parent__name") 26 27 28 class CustomPaginationAdmin(ChildAdmin): 29 paginator = CustomPaginator 30 31 32 class FilteredChildAdmin(admin.ModelAdmin): 33 list_display = ['name', 'parent'] 34 list_per_page = 10 35 36 def queryset(self, request): 37 return super(FilteredChildAdmin, self).queryset(request).filter( 38 name__contains='filtered') 39 40 41 class BandAdmin(admin.ModelAdmin): 42 list_filter = ['genres'] 43 44 45 class GroupAdmin(admin.ModelAdmin): 46 list_filter = ['members'] 47 48 49 class QuartetAdmin(admin.ModelAdmin): 50 list_filter = ['members'] 51 52 53 class ChordsBandAdmin(admin.ModelAdmin): 54 list_filter = ['members'] 55 56 57 class DynamicListDisplayChildAdmin(admin.ModelAdmin): 58 list_display = ('name', 'parent') 59 60 def get_list_display(self, request): 61 my_list_display = list(self.list_display) 62 if request.user.username == 'noparents': 63 my_list_display.remove('parent') 64 65 return my_list_display 66 67 site.register(Child, DynamicListDisplayChildAdmin) -
tests/regressiontests/admin_changelist/tests.py
diff --git a/tests/regressiontests/admin_changelist/tests.py b/tests/regressiontests/admin_changelist/tests.py
a b 3 3 from django.contrib import admin 4 4 from django.contrib.admin.options import IncorrectLookupParameters 5 5 from django.contrib.admin.views.main import ChangeList, SEARCH_VAR, ALL_VAR 6 from django.core.paginator import Paginator7 6 from django.template import Context, Template 8 7 from django.test import TestCase 9 8 from django.test.client import RequestFactory … … 12 11 from models import (Child, Parent, Genre, Band, Musician, Group, Quartet, 13 12 Membership, ChordsMusician, ChordsBand, Invitation) 14 13 14 from admin import (ChildAdmin, QuartetAdmin, BandAdmin, ChordsBandAdmin, 15 GroupAdmin, ParentAdmin, DynamicListDisplayChildAdmin, CustomPaginationAdmin, 16 FilteredChildAdmin, CustomPaginator, site as custom_site) 17 15 18 16 19 class ChangeListTests(TestCase): 20 urls = "regressiontests.admin_changelist.urls" 21 17 22 def setUp(self): 18 23 self.factory = RequestFactory() 19 24 … … 129 134 new_child = Child.objects.create(name='name %s' % i, parent=new_parent) 130 135 131 136 request = self.factory.get('/child/') 132 m = ChildAdmin(Child, admin.site) 133 m.list_display = ['id', 'name', 'parent'] 134 m.list_display_links = ['id'] 135 m.list_editable = ['name'] 136 m.paginator = CustomPaginator 137 m = CustomPaginationAdmin(Child, admin.site) 137 138 138 139 cl = ChangeList(request, Child, m.list_display, m.list_display_links, 139 140 m.list_filter, m.date_hierarchy, m.search_fields, … … 331 332 return request 332 333 333 334 # Test with user 'noparents' 334 m = DynamicListDisplayChildAdmin(Child, admin.site)335 m = custom_site._registry[Child] 335 336 request = _mocked_authenticated_request(user_noparents) 336 337 response = m.changelist_view(request) 337 338 # XXX - Calling render here to avoid ContentNotRenderedError to be … … 347 348 response.render() 348 349 self.assertContains(response, 'Parent object') 349 350 351 custom_site.unregister(Child) 352 350 353 # Test default implementation 351 m = ChildAdmin(Child, admin.site) 354 custom_site.register(Child, ChildAdmin) 355 m = custom_site._registry[Child] 352 356 request = _mocked_authenticated_request(user_noparents) 353 357 response = m.changelist_view(request) 354 358 # XXX - #15826 … … 383 387 cl.get_results(request) 384 388 self.assertEqual(len(cl.result_list), 10) 385 389 386 387 class ParentAdmin(admin.ModelAdmin):388 list_filter = ['child__name']389 search_fields = ['child__name']390 391 392 class ChildAdmin(admin.ModelAdmin):393 list_display = ['name', 'parent']394 list_per_page = 10395 396 def queryset(self, request):397 return super(ChildAdmin, self).queryset(request).select_related("parent__name")398 399 400 class FilteredChildAdmin(admin.ModelAdmin):401 list_display = ['name', 'parent']402 list_per_page = 10403 404 def queryset(self, request):405 return super(FilteredChildAdmin, self).queryset(request).filter(406 name__contains='filtered')407 408 409 class CustomPaginator(Paginator):410 def __init__(self, queryset, page_size, orphans=0, allow_empty_first_page=True):411 super(CustomPaginator, self).__init__(queryset, 5, orphans=2,412 allow_empty_first_page=allow_empty_first_page)413 414 415 class BandAdmin(admin.ModelAdmin):416 list_filter = ['genres']417 418 419 class GroupAdmin(admin.ModelAdmin):420 list_filter = ['members']421 422 423 class QuartetAdmin(admin.ModelAdmin):424 list_filter = ['members']425 426 427 class ChordsBandAdmin(admin.ModelAdmin):428 list_filter = ['members']429 430 431 class DynamicListDisplayChildAdmin(admin.ModelAdmin):432 list_display = ('name', 'parent')433 434 def get_list_display(self, request):435 my_list_display = list(self.list_display)436 if request.user.username == 'noparents':437 my_list_display.remove('parent')438 439 return my_list_display -
new file tests/regressiontests/admin_changelist/urls.py
diff --git a/tests/regressiontests/admin_changelist/urls.py b/tests/regressiontests/admin_changelist/urls.py new file mode 100644
- + 1 from django.conf.urls import patterns, include 2 3 import admin 4 5 urlpatterns = patterns('', 6 (r'^admin/', include(admin.site.urls)), 7 ) -
new file tests/regressiontests/admin_inlines/admin.py
diff --git a/tests/regressiontests/admin_inlines/admin.py b/tests/regressiontests/admin_inlines/admin.py new file mode 100644
- + 1 from django.contrib import admin 2 from django import forms 3 4 from models import * 5 6 site = admin.AdminSite(name="admin") 7 8 9 class BookInline(admin.TabularInline): 10 model = Author.books.through 11 12 13 class AuthorAdmin(admin.ModelAdmin): 14 inlines = [BookInline] 15 16 17 class InnerInline(admin.StackedInline): 18 model = Inner 19 can_delete = False 20 readonly_fields = ('readonly',) # For bug #13174 tests. 21 22 23 class HolderAdmin(admin.ModelAdmin): 24 25 class Media: 26 js = ('my_awesome_admin_scripts.js',) 27 28 29 class InnerInline2(admin.StackedInline): 30 model = Inner2 31 32 class Media: 33 js = ('my_awesome_inline_scripts.js',) 34 35 36 class InnerInline3(admin.StackedInline): 37 model = Inner3 38 39 class Media: 40 js = ('my_awesome_inline_scripts.js',) 41 42 43 class TitleForm(forms.ModelForm): 44 45 def clean(self): 46 cleaned_data = self.cleaned_data 47 title1 = cleaned_data.get("title1") 48 title2 = cleaned_data.get("title2") 49 if title1 != title2: 50 raise forms.ValidationError("The two titles must be the same") 51 return cleaned_data 52 53 54 class TitleInline(admin.TabularInline): 55 model = Title 56 form = TitleForm 57 extra = 1 58 59 60 class Inner4StackedInline(admin.StackedInline): 61 model = Inner4Stacked 62 63 64 class Inner4TabularInline(admin.TabularInline): 65 model = Inner4Tabular 66 67 68 class Holder4Admin(admin.ModelAdmin): 69 inlines = [Inner4StackedInline, Inner4TabularInline] 70 71 72 class InlineWeakness(admin.TabularInline): 73 model = ShoppingWeakness 74 extra = 1 75 76 77 class QuestionInline(admin.TabularInline): 78 model = Question 79 readonly_fields=['call_me'] 80 81 def call_me(self, obj): 82 return 'Callable in QuestionInline' 83 84 85 class PollAdmin(admin.ModelAdmin): 86 inlines = [QuestionInline] 87 88 def call_me(self, obj): 89 return 'Callable in PollAdmin' 90 91 92 class ChapterInline(admin.TabularInline): 93 model = Chapter 94 readonly_fields=['call_me'] 95 96 def call_me(self, obj): 97 return 'Callable in ChapterInline' 98 99 100 class NovelAdmin(admin.ModelAdmin): 101 inlines = [ChapterInline] 102 103 104 site.register(TitleCollection, inlines=[TitleInline]) 105 # Test bug #12561 and #12778 106 # only ModelAdmin media 107 site.register(Holder, HolderAdmin, inlines=[InnerInline]) 108 # ModelAdmin and Inline media 109 site.register(Holder2, HolderAdmin, inlines=[InnerInline2]) 110 # only Inline media 111 site.register(Holder3, inlines=[InnerInline3]) 112 113 site.register(Poll, PollAdmin) 114 site.register(Novel, NovelAdmin) 115 site.register(Fashionista, inlines=[InlineWeakness]) 116 site.register(Holder4, Holder4Admin) 117 site.register(Author, AuthorAdmin) -
tests/regressiontests/admin_inlines/models.py
diff --git a/tests/regressiontests/admin_inlines/models.py b/tests/regressiontests/admin_inlines/models.py
a b 3 3 4 4 """ 5 5 from django.db import models 6 from django.contrib import admin7 6 from django.contrib.contenttypes.models import ContentType 8 7 from django.contrib.contenttypes import generic 9 from django import forms 8 10 9 11 10 class Parent(models.Model): 12 11 name = models.CharField(max_length=50) … … 14 13 def __unicode__(self): 15 14 return self.name 16 15 16 17 17 class Teacher(models.Model): 18 18 name = models.CharField(max_length=50) 19 19 20 20 def __unicode__(self): 21 21 return self.name 22 22 23 23 24 class Child(models.Model): 24 25 name = models.CharField(max_length=50) 25 26 teacher = models.ForeignKey(Teacher) … … 31 32 def __unicode__(self): 32 33 return u'I am %s, a child of %s' % (self.name, self.parent) 33 34 35 34 36 class Book(models.Model): 35 37 name = models.CharField(max_length=50) 36 38 39 37 40 class Author(models.Model): 38 41 name = models.CharField(max_length=50) 39 42 books = models.ManyToManyField(Book) 40 43 41 class BookInline(admin.TabularInline):42 model = Author.books.through43 44 class AuthorAdmin(admin.ModelAdmin):45 inlines = [BookInline]46 47 admin.site.register(Author, AuthorAdmin)48 44 49 45 class Holder(models.Model): 50 46 dummy = models.IntegerField() … … 56 52 readonly = models.CharField("Inner readonly label", max_length=1) 57 53 58 54 59 class InnerInline(admin.StackedInline):60 model = Inner61 can_delete = False62 readonly_fields = ('readonly',) # For bug #13174 tests.63 64 65 55 class Holder2(models.Model): 66 56 dummy = models.IntegerField() 67 57 … … 70 60 dummy = models.IntegerField() 71 61 holder = models.ForeignKey(Holder2) 72 62 73 class HolderAdmin(admin.ModelAdmin):74 75 class Media:76 js = ('my_awesome_admin_scripts.js',)77 78 class InnerInline2(admin.StackedInline):79 model = Inner280 81 class Media:82 js = ('my_awesome_inline_scripts.js',)83 84 63 class Holder3(models.Model): 85 64 dummy = models.IntegerField() 86 65 … … 89 68 dummy = models.IntegerField() 90 69 holder = models.ForeignKey(Holder3) 91 70 92 class InnerInline3(admin.StackedInline):93 model = Inner394 95 class Media:96 js = ('my_awesome_inline_scripts.js',)97 98 # Test bug #12561 and #1277899 # only ModelAdmin media100 admin.site.register(Holder, HolderAdmin, inlines=[InnerInline])101 # ModelAdmin and Inline media102 admin.site.register(Holder2, HolderAdmin, inlines=[InnerInline2])103 # only Inline media104 admin.site.register(Holder3, inlines=[InnerInline3])105 106 107 71 # Models for ticket #8190 108 72 109 73 class Holder4(models.Model): … … 117 81 dummy = models.IntegerField(help_text="Awesome tabular help text is awesome.") 118 82 holder = models.ForeignKey(Holder4) 119 83 120 class Inner4StackedInline(admin.StackedInline):121 model = Inner4Stacked122 123 class Inner4TabularInline(admin.TabularInline):124 model = Inner4Tabular125 126 class Holder4Admin(admin.ModelAdmin):127 inlines = [Inner4StackedInline, Inner4TabularInline]128 129 admin.site.register(Holder4, Holder4Admin)130 131 84 132 85 # Models for #12749 133 86 … … 145 98 fashionista = models.ForeignKey(Fashionista) 146 99 item = models.ForeignKey(OutfitItem) 147 100 148 class InlineWeakness(admin.TabularInline):149 model = ShoppingWeakness150 extra = 1151 152 admin.site.register(Fashionista, inlines=[InlineWeakness])153 154 101 # Models for #13510 155 102 156 103 class TitleCollection(models.Model): … … 161 108 title1 = models.CharField(max_length=100) 162 109 title2 = models.CharField(max_length=100) 163 110 164 class TitleForm(forms.ModelForm):165 166 def clean(self):167 cleaned_data = self.cleaned_data168 title1 = cleaned_data.get("title1")169 title2 = cleaned_data.get("title2")170 if title1 != title2:171 raise forms.ValidationError("The two titles must be the same")172 return cleaned_data173 174 class TitleInline(admin.TabularInline):175 model = Title176 form = TitleForm177 extra = 1178 179 admin.site.register(TitleCollection, inlines=[TitleInline])180 181 111 # Models for #15424 182 112 183 113 class Poll(models.Model): … … 186 116 class Question(models.Model): 187 117 poll = models.ForeignKey(Poll) 188 118 189 class QuestionInline(admin.TabularInline):190 model = Question191 readonly_fields=['call_me']192 193 def call_me(self, obj):194 return 'Callable in QuestionInline'195 196 class PollAdmin(admin.ModelAdmin):197 inlines = [QuestionInline]198 199 def call_me(self, obj):200 return 'Callable in PollAdmin'201 202 119 class Novel(models.Model): 203 120 name = models.CharField(max_length=40) 204 121 205 122 class Chapter(models.Model): 206 123 novel = models.ForeignKey(Novel) 207 124 208 class ChapterInline(admin.TabularInline):209 model = Chapter210 readonly_fields=['call_me']211 212 def call_me(self, obj):213 return 'Callable in ChapterInline'214 215 class NovelAdmin(admin.ModelAdmin):216 inlines = [ChapterInline]217 218 admin.site.register(Poll, PollAdmin)219 admin.site.register(Novel, NovelAdmin) -
tests/regressiontests/admin_inlines/tests.py
diff --git a/tests/regressiontests/admin_inlines/tests.py b/tests/regressiontests/admin_inlines/tests.py
a b 3 3 from django.test import TestCase 4 4 5 5 # local test models 6 from models import (Holder, Inner, InnerInline,Holder2, Inner2, Holder3,6 from models import (Holder, Inner, Holder2, Inner2, Holder3, 7 7 Inner3, Person, OutfitItem, Fashionista, Teacher, Parent, Child) 8 from admin import InnerInline 8 9 9 10 10 11 class TestInline(TestCase): 12 urls = "regressiontests.admin_inlines.urls" 11 13 fixtures = ['admin-views-users.xml'] 12 14 13 15 def setUp(self): 14 16 holder = Holder(dummy=13) 15 17 holder.save() 16 18 Inner(dummy=42, holder=holder).save() 17 self.change_url = '/ test_admin/admin/admin_inlines/holder/%i/' % holder.id19 self.change_url = '/admin/admin_inlines/holder/%i/' % holder.id 18 20 19 21 result = self.client.login(username='super', password='secret') 20 22 self.assertEqual(result, True) … … 36 38 """Bug #13174.""" 37 39 holder = Holder.objects.create(dummy=42) 38 40 inner = Inner.objects.create(holder=holder, dummy=42, readonly='') 39 response = self.client.get('/ test_admin/admin/admin_inlines/holder/%i/'41 response = self.client.get('/admin/admin_inlines/holder/%i/' 40 42 % holder.id) 41 43 self.assertContains(response, '<label>Inner readonly label:</label>') 42 44 43 45 def test_many_to_many_inlines(self): 44 46 "Autogenerated many-to-many inlines are displayed correctly (#13407)" 45 response = self.client.get('/ test_admin/admin/admin_inlines/author/add/')47 response = self.client.get('/admin/admin_inlines/author/add/') 46 48 # The heading for the m2m inline block uses the right text 47 49 self.assertContains(response, '<h2>Author-book relationships</h2>') 48 50 # The "add another" label is correct … … 63 65 'max_weight': 0, 64 66 'shoppingweakness_set-0-item': item.id, 65 67 } 66 response = self.client.post('/ test_admin/admin/admin_inlines/fashionista/add/', data)68 response = self.client.post('/admin/admin_inlines/fashionista/add/', data) 67 69 self.assertEqual(response.status_code, 302) 68 70 self.assertEqual(len(Fashionista.objects.filter(person__firstname='Imelda')), 1) 69 71 … … 80 82 'title_set-0-title1': 'a title', 81 83 'title_set-0-title2': 'a different title', 82 84 } 83 response = self.client.post('/ test_admin/admin/admin_inlines/titlecollection/add/', data)85 response = self.client.post('/admin/admin_inlines/titlecollection/add/', data) 84 86 # Here colspan is "4": two fields (title1 and title2), one hidden field and the delete checkbock. 85 87 self.assertContains(response, '<tr><td colspan="4"><ul class="errorlist"><li>The two titles must be the same</li></ul></td></tr>') 86 88 … … 88 90 """Admin inline `readonly_field` shouldn't invoke parent ModelAdmin callable""" 89 91 # Identically named callable isn't present in the parent ModelAdmin, 90 92 # rendering of the add view shouldn't explode 91 response = self.client.get('/ test_admin/admin/admin_inlines/novel/add/')93 response = self.client.get('/admin/admin_inlines/novel/add/') 92 94 self.assertEqual(response.status_code, 200) 93 95 # View should have the child inlines section 94 96 self.assertContains(response, '<div class="inline-group" id="chapter_set-group">') 95 97 96 98 def test_callable_lookup(self): 97 99 """Admin inline should invoke local callable when its name is listed in readonly_fields""" 98 response = self.client.get('/ test_admin/admin/admin_inlines/poll/add/')100 response = self.client.get('/admin/admin_inlines/poll/add/') 99 101 self.assertEqual(response.status_code, 200) 100 102 # Add parent object view should have the child inlines section 101 103 self.assertContains(response, '<div class="inline-group" id="question_set-group">') … … 109 111 using both the stacked and tabular layouts. 110 112 Ref #8190. 111 113 """ 112 response = self.client.get('/ test_admin/admin/admin_inlines/holder4/add/')114 response = self.client.get('/admin/admin_inlines/holder4/add/') 113 115 self.assertContains(response, '<p class="help">Awesome stacked help text is awesome.</p>', 4) 114 116 self.assertContains(response, '<img src="/static/admin/img/icon-unknown.gif" class="help help-tooltip" width="10" height="10" alt="(Awesome tabular help text is awesome.)" title="Awesome tabular help text is awesome." />', 1) 115 117 116 118 class TestInlineMedia(TestCase): 119 urls = "regressiontests.admin_inlines.urls" 117 120 fixtures = ['admin-views-users.xml'] 118 121 119 122 def setUp(self): … … 128 131 holder = Holder(dummy=13) 129 132 holder.save() 130 133 Inner(dummy=42, holder=holder).save() 131 change_url = '/ test_admin/admin/admin_inlines/holder/%i/' % holder.id134 change_url = '/admin/admin_inlines/holder/%i/' % holder.id 132 135 response = self.client.get(change_url) 133 136 self.assertContains(response, 'my_awesome_admin_scripts.js') 134 137 … … 136 139 holder = Holder3(dummy=13) 137 140 holder.save() 138 141 Inner3(dummy=42, holder=holder).save() 139 change_url = '/ test_admin/admin/admin_inlines/holder3/%i/' % holder.id142 change_url = '/admin/admin_inlines/holder3/%i/' % holder.id 140 143 response = self.client.get(change_url) 141 144 self.assertContains(response, 'my_awesome_inline_scripts.js') 142 145 … … 144 147 holder = Holder2(dummy=13) 145 148 holder.save() 146 149 Inner2(dummy=42, holder=holder).save() 147 change_url = '/ test_admin/admin/admin_inlines/holder2/%i/' % holder.id150 change_url = '/admin/admin_inlines/holder2/%i/' % holder.id 148 151 response = self.client.get(change_url) 149 152 self.assertContains(response, 'my_awesome_admin_scripts.js') 150 153 self.assertContains(response, 'my_awesome_inline_scripts.js') 151 154 152 155 class TestInlineAdminForm(TestCase): 156 urls = "regressiontests.admin_inlines.urls" 153 157 154 158 def test_immutable_content_type(self): 155 159 """Regression for #9362 -
new file tests/regressiontests/admin_inlines/urls.py
diff --git a/tests/regressiontests/admin_inlines/urls.py b/tests/regressiontests/admin_inlines/urls.py new file mode 100644
- + 1 from django.conf.urls import patterns, include 2 3 import admin 4 5 urlpatterns = patterns('', 6 (r'^admin/', include(admin.site.urls)), 7 ) -
new file tests/regressiontests/admin_views/admin.py
diff --git a/tests/regressiontests/admin_views/admin.py b/tests/regressiontests/admin_views/admin.py new file mode 100644
- + 1 # -*- coding: utf-8 -*- 2 import datetime 3 import tempfile 4 import os 5 6 from django.contrib import admin 7 from django.contrib.admin.views.main import ChangeList 8 from django.forms.models import BaseModelFormSet 9 from django.core.mail import EmailMessage 10 11 from models import * 12 13 14 def callable_year(dt_value): 15 return dt_value.year 16 callable_year.admin_order_field = 'date' 17 18 19 class ArticleInline(admin.TabularInline): 20 model = Article 21 22 23 class ChapterInline(admin.TabularInline): 24 model = Chapter 25 26 27 class ChapterXtra1Admin(admin.ModelAdmin): 28 list_filter = ('chap', 29 'chap__title', 30 'chap__book', 31 'chap__book__name', 32 'chap__book__promo', 33 'chap__book__promo__name',) 34 35 36 class ArticleAdmin(admin.ModelAdmin): 37 list_display = ('content', 'date', callable_year, 'model_year', 'modeladmin_year') 38 list_filter = ('date', 'section') 39 40 def changelist_view(self, request): 41 "Test that extra_context works" 42 return super(ArticleAdmin, self).changelist_view( 43 request, extra_context={ 44 'extra_var': 'Hello!' 45 } 46 ) 47 48 def modeladmin_year(self, obj): 49 return obj.date.year 50 modeladmin_year.admin_order_field = 'date' 51 modeladmin_year.short_description = None 52 53 def delete_model(self, request, obj): 54 EmailMessage( 55 'Greetings from a deleted object', 56 'I hereby inform you that some user deleted me', 57 'from@example.com', 58 ['to@example.com'] 59 ).send() 60 return super(ArticleAdmin, self).delete_model(request, obj) 61 62 def save_model(self, request, obj, form, change=True): 63 EmailMessage( 64 'Greetings from a created object', 65 'I hereby inform you that some user created me', 66 'from@example.com', 67 ['to@example.com'] 68 ).send() 69 return super(ArticleAdmin, self).save_model(request, obj, form, change) 70 71 72 class RowLevelChangePermissionModelAdmin(admin.ModelAdmin): 73 def has_change_permission(self, request, obj=None): 74 """ Only allow changing objects with even id number """ 75 return request.user.is_staff and (obj is not None) and (obj.id % 2 == 0) 76 77 78 class CustomArticleAdmin(admin.ModelAdmin): 79 """ 80 Tests various hooks for using custom templates and contexts. 81 """ 82 change_list_template = 'custom_admin/change_list.html' 83 change_form_template = 'custom_admin/change_form.html' 84 add_form_template = 'custom_admin/add_form.html' 85 object_history_template = 'custom_admin/object_history.html' 86 delete_confirmation_template = 'custom_admin/delete_confirmation.html' 87 delete_selected_confirmation_template = 'custom_admin/delete_selected_confirmation.html' 88 89 def changelist_view(self, request): 90 "Test that extra_context works" 91 return super(CustomArticleAdmin, self).changelist_view( 92 request, extra_context={ 93 'extra_var': 'Hello!' 94 } 95 ) 96 97 98 class ThingAdmin(admin.ModelAdmin): 99 list_filter = ('color__warm', 'color__value') 100 101 102 class InquisitionAdmin(admin.ModelAdmin): 103 list_display = ('leader', 'country', 'expected') 104 105 106 class SketchAdmin(admin.ModelAdmin): 107 raw_id_fields = ('inquisition',) 108 109 110 class FabricAdmin(admin.ModelAdmin): 111 list_display = ('surface',) 112 list_filter = ('surface',) 113 114 115 class BasePersonModelFormSet(BaseModelFormSet): 116 def clean(self): 117 for person_dict in self.cleaned_data: 118 person = person_dict.get('id') 119 alive = person_dict.get('alive') 120 if person and alive and person.name == "Grace Hopper": 121 raise forms.ValidationError("Grace is not a Zombie") 122 123 124 class PersonAdmin(admin.ModelAdmin): 125 list_display = ('name', 'gender', 'alive') 126 list_editable = ('gender', 'alive') 127 list_filter = ('gender',) 128 search_fields = ('^name',) 129 save_as = True 130 131 def get_changelist_formset(self, request, **kwargs): 132 return super(PersonAdmin, self).get_changelist_formset(request, 133 formset=BasePersonModelFormSet, **kwargs) 134 135 def queryset(self, request): 136 # Order by a field that isn't in list display, to be able to test 137 # whether ordering is preserved. 138 return super(PersonAdmin, self).queryset(request).order_by('age') 139 140 141 class FooAccount(Account): 142 """A service-specific account of type Foo.""" 143 servicename = u'foo' 144 145 146 class BarAccount(Account): 147 """A service-specific account of type Bar.""" 148 servicename = u'bar' 149 150 151 class FooAccountAdmin(admin.StackedInline): 152 model = FooAccount 153 extra = 1 154 155 156 class BarAccountAdmin(admin.StackedInline): 157 model = BarAccount 158 extra = 1 159 160 161 class PersonaAdmin(admin.ModelAdmin): 162 inlines = ( 163 FooAccountAdmin, 164 BarAccountAdmin 165 ) 166 167 168 class SubscriberAdmin(admin.ModelAdmin): 169 actions = ['mail_admin'] 170 171 def mail_admin(self, request, selected): 172 EmailMessage( 173 'Greetings from a ModelAdmin action', 174 'This is the test email from a admin action', 175 'from@example.com', 176 ['to@example.com'] 177 ).send() 178 179 180 def external_mail(modeladmin, request, selected): 181 EmailMessage( 182 'Greetings from a function action', 183 'This is the test email from a function action', 184 'from@example.com', 185 ['to@example.com'] 186 ).send() 187 external_mail.short_description = 'External mail (Another awesome action)' 188 189 190 def redirect_to(modeladmin, request, selected): 191 from django.http import HttpResponseRedirect 192 return HttpResponseRedirect('/some-where-else/') 193 redirect_to.short_description = 'Redirect to (Awesome action)' 194 195 196 class ExternalSubscriberAdmin(admin.ModelAdmin): 197 actions = [redirect_to, external_mail] 198 199 200 class Podcast(Media): 201 release_date = models.DateField() 202 203 class Meta: 204 ordering = ('release_date',) # overridden in PodcastAdmin 205 206 207 class PodcastAdmin(admin.ModelAdmin): 208 list_display = ('name', 'release_date') 209 list_editable = ('release_date',) 210 date_hierarchy = 'release_date' 211 ordering = ('name',) 212 213 214 class VodcastAdmin(admin.ModelAdmin): 215 list_display = ('name', 'released') 216 list_editable = ('released',) 217 218 ordering = ('name',) 219 220 221 class ChildInline(admin.StackedInline): 222 model = Child 223 224 225 class ParentAdmin(admin.ModelAdmin): 226 model = Parent 227 inlines = [ChildInline] 228 229 list_editable = ('name',) 230 231 def save_related(self, request, form, formsets, change): 232 super(ParentAdmin, self).save_related(request, form, formsets, change) 233 first_name, last_name = form.instance.name.split() 234 for child in form.instance.child_set.all(): 235 if len(child.name.split()) < 2: 236 child.name = child.name + ' ' + last_name 237 child.save() 238 239 240 class EmptyModelAdmin(admin.ModelAdmin): 241 def queryset(self, request): 242 return super(EmptyModelAdmin, self).queryset(request).filter(pk__gt=1) 243 244 245 class OldSubscriberAdmin(admin.ModelAdmin): 246 actions = None 247 248 249 temp_storage = FileSystemStorage(tempfile.mkdtemp()) 250 UPLOAD_TO = os.path.join(temp_storage.location, 'test_upload') 251 252 253 class PictureInline(admin.TabularInline): 254 model = Picture 255 extra = 1 256 257 258 class GalleryAdmin(admin.ModelAdmin): 259 inlines = [PictureInline] 260 261 262 class PictureAdmin(admin.ModelAdmin): 263 pass 264 265 266 class LanguageAdmin(admin.ModelAdmin): 267 list_display = ['iso', 'shortlist', 'english_name', 'name'] 268 list_editable = ['shortlist'] 269 270 271 class RecommendationAdmin(admin.ModelAdmin): 272 search_fields = ('=titletranslation__text', '=recommender__titletranslation__text',) 273 274 275 class WidgetInline(admin.StackedInline): 276 model = Widget 277 278 279 class DooHickeyInline(admin.StackedInline): 280 model = DooHickey 281 282 283 class GrommetInline(admin.StackedInline): 284 model = Grommet 285 286 287 class WhatsitInline(admin.StackedInline): 288 model = Whatsit 289 290 291 class FancyDoodadInline(admin.StackedInline): 292 model = FancyDoodad 293 294 295 class CategoryAdmin(admin.ModelAdmin): 296 list_display = ('id', 'collector', 'order') 297 list_editable = ('order',) 298 299 300 class CategoryInline(admin.StackedInline): 301 model = Category 302 303 304 class CollectorAdmin(admin.ModelAdmin): 305 inlines = [ 306 WidgetInline, DooHickeyInline, GrommetInline, WhatsitInline, 307 FancyDoodadInline, CategoryInline 308 ] 309 310 311 class LinkInline(admin.TabularInline): 312 model = Link 313 extra = 1 314 315 readonly_fields = ("posted",) 316 317 318 class SubPostInline(admin.TabularInline): 319 model = PrePopulatedSubPost 320 321 prepopulated_fields = { 322 'subslug' : ('subtitle',) 323 } 324 325 def get_readonly_fields(self, request, obj=None): 326 if obj and obj.published: 327 return ('subslug',) 328 return self.readonly_fields 329 330 def get_prepopulated_fields(self, request, obj=None): 331 if obj and obj.published: 332 return {} 333 return self.prepopulated_fields 334 335 336 class PrePopulatedPostAdmin(admin.ModelAdmin): 337 list_display = ['title', 'slug'] 338 prepopulated_fields = { 339 'slug' : ('title',) 340 } 341 342 inlines = [SubPostInline] 343 344 def get_readonly_fields(self, request, obj=None): 345 if obj and obj.published: 346 return ('slug',) 347 return self.readonly_fields 348 349 def get_prepopulated_fields(self, request, obj=None): 350 if obj and obj.published: 351 return {} 352 return self.prepopulated_fields 353 354 355 class PostAdmin(admin.ModelAdmin): 356 list_display = ['title', 'public'] 357 readonly_fields = ('posted', 'awesomeness_level', 'coolness', 'value', lambda obj: "foo") 358 359 inlines = [ 360 LinkInline 361 ] 362 363 def coolness(self, instance): 364 if instance.pk: 365 return "%d amount of cool." % instance.pk 366 else: 367 return "Unkown coolness." 368 369 def value(self, instance): 370 return 1000 371 value.short_description = 'Value in $US' 372 373 374 class CustomChangeList(ChangeList): 375 def get_query_set(self, request): 376 return self.root_query_set.filter(pk=9999) # Does not exist 377 378 379 class GadgetAdmin(admin.ModelAdmin): 380 def get_changelist(self, request, **kwargs): 381 return CustomChangeList 382 383 384 class PizzaAdmin(admin.ModelAdmin): 385 readonly_fields = ('toppings',) 386 387 388 class WorkHourAdmin(admin.ModelAdmin): 389 list_display = ('datum', 'employee') 390 list_filter = ('employee',) 391 392 393 class FoodDeliveryAdmin(admin.ModelAdmin): 394 list_display=('reference', 'driver', 'restaurant') 395 list_editable = ('driver', 'restaurant') 396 397 398 class PaperAdmin(admin.ModelAdmin): 399 """ 400 A ModelAdmin with a custom queryset() method that uses only(), to test 401 verbose_name display in messages shown after adding Paper instances. 402 """ 403 404 def queryset(self, request): 405 return super(PaperAdmin, self).queryset(request).only('title') 406 407 408 class CoverLetterAdmin(admin.ModelAdmin): 409 """ 410 A ModelAdmin with a custom queryset() method that uses only(), to test 411 verbose_name display in messages shown after adding CoverLetter instances. 412 Note that the CoverLetter model defines a __unicode__ method. 413 """ 414 415 def queryset(self, request): 416 return super(CoverLetterAdmin, self).queryset(request).defer('date_written') 417 418 419 class StoryForm(forms.ModelForm): 420 class Meta: 421 widgets = {'title': forms.HiddenInput} 422 423 424 class StoryAdmin(admin.ModelAdmin): 425 list_display = ('id', 'title', 'content') 426 list_display_links = ('title',) # 'id' not in list_display_links 427 list_editable = ('content', ) 428 form = StoryForm 429 ordering = ["-pk"] 430 431 432 class OtherStoryAdmin(admin.ModelAdmin): 433 list_display = ('id', 'title', 'content') 434 list_display_links = ('title', 'id') # 'id' in list_display_links 435 list_editable = ('content', ) 436 ordering = ["-pk"] 437 438 439 class ComplexSortedPersonAdmin(admin.ModelAdmin): 440 list_display = ('name', 'age', 'is_employee', 'colored_name') 441 ordering = ('name',) 442 443 def colored_name(self, obj): 444 return '<span style="color: #%s;">%s</span>' % ('ff00ff', obj.name) 445 colored_name.allow_tags = True 446 colored_name.admin_order_field = 'name' 447 448 449 class AlbumAdmin(admin.ModelAdmin): 450 list_filter = ['title'] 451 452 453 class WorkHourAdmin(admin.ModelAdmin): 454 list_display = ('datum', 'employee') 455 list_filter = ('employee',) 456 457 458 site = admin.AdminSite(name="admin") 459 site.register(Article, ArticleAdmin) 460 site.register(CustomArticle, CustomArticleAdmin) 461 site.register(Section, save_as=True, inlines=[ArticleInline]) 462 site.register(ModelWithStringPrimaryKey) 463 site.register(Color) 464 site.register(Thing, ThingAdmin) 465 site.register(Actor) 466 site.register(Inquisition, InquisitionAdmin) 467 site.register(Sketch, SketchAdmin) 468 site.register(Person, PersonAdmin) 469 site.register(Persona, PersonaAdmin) 470 site.register(Subscriber, SubscriberAdmin) 471 site.register(ExternalSubscriber, ExternalSubscriberAdmin) 472 site.register(OldSubscriber, OldSubscriberAdmin) 473 site.register(Podcast, PodcastAdmin) 474 site.register(Vodcast, VodcastAdmin) 475 site.register(Parent, ParentAdmin) 476 site.register(EmptyModel, EmptyModelAdmin) 477 site.register(Fabric, FabricAdmin) 478 site.register(Gallery, GalleryAdmin) 479 site.register(Picture, PictureAdmin) 480 site.register(Language, LanguageAdmin) 481 site.register(Recommendation, RecommendationAdmin) 482 site.register(Recommender) 483 site.register(Collector, CollectorAdmin) 484 site.register(Category, CategoryAdmin) 485 site.register(Post, PostAdmin) 486 site.register(Gadget, GadgetAdmin) 487 site.register(Villain) 488 site.register(SuperVillain) 489 site.register(Plot) 490 site.register(PlotDetails) 491 site.register(CyclicOne) 492 site.register(CyclicTwo) 493 site.register(WorkHour, WorkHourAdmin) 494 site.register(Reservation) 495 site.register(FoodDelivery, FoodDeliveryAdmin) 496 site.register(RowLevelChangePermissionModel, RowLevelChangePermissionModelAdmin) 497 site.register(Paper, PaperAdmin) 498 site.register(CoverLetter, CoverLetterAdmin) 499 site.register(Story, StoryAdmin) 500 site.register(OtherStory, OtherStoryAdmin) 501 502 # We intentionally register Promo and ChapterXtra1 but not Chapter nor ChapterXtra2. 503 # That way we cover all four cases: 504 # related ForeignKey object registered in admin 505 # related ForeignKey object not registered in admin 506 # related OneToOne object registered in admin 507 # related OneToOne object not registered in admin 508 # when deleting Book so as exercise all four troublesome (w.r.t escaping 509 # and calling force_unicode to avoid problems on Python 2.3) paths through 510 # contrib.admin.util's get_deleted_objects function. 511 site.register(Book, inlines=[ChapterInline]) 512 site.register(Promo) 513 site.register(ChapterXtra1, ChapterXtra1Admin) 514 site.register(Pizza, PizzaAdmin) 515 site.register(Topping) 516 site.register(Album, AlbumAdmin) 517 site.register(Question) 518 site.register(Answer) 519 site.register(PrePopulatedPost, PrePopulatedPostAdmin) 520 site.register(ComplexSortedPerson, ComplexSortedPersonAdmin) 521 522 # Register core models we need in our tests 523 from django.contrib.auth.models import User, Group 524 from django.contrib.auth.admin import UserAdmin, GroupAdmin 525 site.register(User, UserAdmin) 526 site.register(Group, GroupAdmin) -
tests/regressiontests/admin_views/customadmin.py
diff --git a/tests/regressiontests/admin_views/customadmin.py b/tests/regressiontests/admin_views/customadmin.py
a b 5 5 from django.contrib import admin 6 6 from django.http import HttpResponse 7 7 8 import models, forms 8 import models, forms, admin as base_admin 9 9 10 10 class Admin2(admin.AdminSite): 11 11 login_form = forms.CustomAdminAuthenticationForm … … 29 29 30 30 site = Admin2(name="admin2") 31 31 32 site.register(models.Article, models.ArticleAdmin)33 site.register(models.Section, inlines=[ models.ArticleInline])34 site.register(models.Thing, models.ThingAdmin)35 site.register(models.Fabric, models.FabricAdmin)36 site.register(models.ChapterXtra1, models.ChapterXtra1Admin)32 site.register(models.Article, base_admin.ArticleAdmin) 33 site.register(models.Section, inlines=[base_admin.ArticleInline]) 34 site.register(models.Thing, base_admin.ThingAdmin) 35 site.register(models.Fabric, base_admin.FabricAdmin) 36 site.register(models.ChapterXtra1, base_admin.ChapterXtra1Admin) -
tests/regressiontests/admin_views/models.py
diff --git a/tests/regressiontests/admin_views/models.py b/tests/regressiontests/admin_views/models.py
a b 3 3 import tempfile 4 4 import os 5 5 6 from django.contrib import admin7 6 from django.core.files.storage import FileSystemStorage 8 from django.contrib.admin.views.main import ChangeList9 from django.core.mail import EmailMessage10 7 from django.db import models 11 8 from django import forms 12 from django.forms.models import BaseModelFormSet13 9 from django.contrib.auth.models import User 14 10 from django.contrib.contenttypes import generic 15 11 from django.contrib.contenttypes.models import ContentType 16 12 13 17 14 class Section(models.Model): 18 15 """ 19 16 A simple section that links to articles, to test linking to related items … … 21 18 """ 22 19 name = models.CharField(max_length=100) 23 20 21 24 22 class Article(models.Model): 25 23 """ 26 24 A simple article to test admin views. Test backwards compatibility. … … 38 36 model_year.admin_order_field = 'date' 39 37 model_year.short_description = '' 40 38 39 41 40 class Book(models.Model): 42 41 """ 43 42 A simple book that has chapters. … … 47 46 def __unicode__(self): 48 47 return self.name 49 48 49 50 50 class Promo(models.Model): 51 51 name = models.CharField(max_length=100, verbose_name=u'¿Name?') 52 52 book = models.ForeignKey(Book) … … 54 54 def __unicode__(self): 55 55 return self.name 56 56 57 57 58 class Chapter(models.Model): 58 59 title = models.CharField(max_length=100, verbose_name=u'¿Title?') 59 60 content = models.TextField() … … 66 67 # Use a utf-8 bytestring to ensure it works (see #11710) 67 68 verbose_name = '¿Chapter?' 68 69 70 69 71 class ChapterXtra1(models.Model): 70 72 chap = models.OneToOneField(Chapter, verbose_name=u'¿Chap?') 71 73 xtra = models.CharField(max_length=100, verbose_name=u'¿Xtra?') … … 73 75 def __unicode__(self): 74 76 return u'¿Xtra1: %s' % self.xtra 75 77 78 76 79 class ChapterXtra2(models.Model): 77 80 chap = models.OneToOneField(Chapter, verbose_name=u'¿Chap?') 78 81 xtra = models.CharField(max_length=100, verbose_name=u'¿Xtra?') … … 80 83 def __unicode__(self): 81 84 return u'¿Xtra2: %s' % self.xtra 82 85 83 def callable_year(dt_value):84 return dt_value.year85 callable_year.admin_order_field = 'date'86 87 class ArticleInline(admin.TabularInline):88 model = Article89 90 class ChapterInline(admin.TabularInline):91 model = Chapter92 93 class ChapterXtra1Admin(admin.ModelAdmin):94 list_filter = ('chap',95 'chap__title',96 'chap__book',97 'chap__book__name',98 'chap__book__promo',99 'chap__book__promo__name',)100 101 class ArticleAdmin(admin.ModelAdmin):102 list_display = ('content', 'date', callable_year, 'model_year', 'modeladmin_year')103 list_filter = ('date', 'section')104 105 def changelist_view(self, request):106 "Test that extra_context works"107 return super(ArticleAdmin, self).changelist_view(108 request, extra_context={109 'extra_var': 'Hello!'110 }111 )112 113 def modeladmin_year(self, obj):114 return obj.date.year115 modeladmin_year.admin_order_field = 'date'116 modeladmin_year.short_description = None117 118 def delete_model(self, request, obj):119 EmailMessage(120 'Greetings from a deleted object',121 'I hereby inform you that some user deleted me',122 'from@example.com',123 ['to@example.com']124 ).send()125 return super(ArticleAdmin, self).delete_model(request, obj)126 127 def save_model(self, request, obj, form, change=True):128 EmailMessage(129 'Greetings from a created object',130 'I hereby inform you that some user created me',131 'from@example.com',132 ['to@example.com']133 ).send()134 return super(ArticleAdmin, self).save_model(request, obj, form, change)135 86 136 87 class RowLevelChangePermissionModel(models.Model): 137 88 name = models.CharField(max_length=100, blank=True) 138 89 139 class RowLevelChangePermissionModelAdmin(admin.ModelAdmin):140 def has_change_permission(self, request, obj=None):141 """ Only allow changing objects with even id number """142 return request.user.is_staff and (obj is not None) and (obj.id % 2 == 0)143 90 144 91 class CustomArticle(models.Model): 145 92 content = models.TextField() 146 93 date = models.DateTimeField() 147 94 148 class CustomArticleAdmin(admin.ModelAdmin):149 """150 Tests various hooks for using custom templates and contexts.151 """152 change_list_template = 'custom_admin/change_list.html'153 change_form_template = 'custom_admin/change_form.html'154 add_form_template = 'custom_admin/add_form.html'155 object_history_template = 'custom_admin/object_history.html'156 delete_confirmation_template = 'custom_admin/delete_confirmation.html'157 delete_selected_confirmation_template = 'custom_admin/delete_selected_confirmation.html'158 159 def changelist_view(self, request):160 "Test that extra_context works"161 return super(CustomArticleAdmin, self).changelist_view(162 request, extra_context={163 'extra_var': 'Hello!'164 }165 )166 95 167 96 class ModelWithStringPrimaryKey(models.Model): 168 97 id = models.CharField(max_length=255, primary_key=True) … … 170 99 def __unicode__(self): 171 100 return self.id 172 101 102 173 103 class Color(models.Model): 174 104 value = models.CharField(max_length=10) 175 105 warm = models.BooleanField() 176 106 def __unicode__(self): 177 107 return self.value 178 108 109 179 110 class Thing(models.Model): 180 111 title = models.CharField(max_length=20) 181 112 color = models.ForeignKey(Color, limit_choices_to={'warm': True}) 182 113 def __unicode__(self): 183 114 return self.title 184 115 185 class ThingAdmin(admin.ModelAdmin):186 list_filter = ('color__warm', 'color__value')187 116 188 117 class Actor(models.Model): 189 118 name = models.CharField(max_length=50) … … 191 120 def __unicode__(self): 192 121 return self.name 193 122 123 194 124 class Inquisition(models.Model): 195 125 expected = models.BooleanField() 196 126 leader = models.ForeignKey(Actor) … … 199 129 def __unicode__(self): 200 130 return u"by %s from %s" % (self.leader, self.country) 201 131 202 class InquisitionAdmin(admin.ModelAdmin):203 list_display = ('leader', 'country', 'expected')204 132 205 133 class Sketch(models.Model): 206 134 title = models.CharField(max_length=100) … … 212 140 def __unicode__(self): 213 141 return self.title 214 142 215 class SketchAdmin(admin.ModelAdmin):216 raw_id_fields = ('inquisition',)217 143 218 144 class Fabric(models.Model): 219 145 NG_CHOICES = ( … … 226 152 ) 227 153 surface = models.CharField(max_length=20, choices=NG_CHOICES) 228 154 229 class FabricAdmin(admin.ModelAdmin):230 list_display = ('surface',)231 list_filter = ('surface',)232 155 233 156 class Person(models.Model): 234 157 GENDER_CHOICES = ( … … 243 166 def __unicode__(self): 244 167 return self.name 245 168 246 class BasePersonModelFormSet(BaseModelFormSet):247 def clean(self):248 for person_dict in self.cleaned_data:249 person = person_dict.get('id')250 alive = person_dict.get('alive')251 if person and alive and person.name == "Grace Hopper":252 raise forms.ValidationError("Grace is not a Zombie")253 254 class PersonAdmin(admin.ModelAdmin):255 list_display = ('name', 'gender', 'alive')256 list_editable = ('gender', 'alive')257 list_filter = ('gender',)258 search_fields = ('^name',)259 save_as = True260 261 def get_changelist_formset(self, request, **kwargs):262 return super(PersonAdmin, self).get_changelist_formset(request,263 formset=BasePersonModelFormSet, **kwargs)264 265 def queryset(self, request):266 # Order by a field that isn't in list display, to be able to test267 # whether ordering is preserved.268 return super(PersonAdmin, self).queryset(request).order_by('age')269 270 169 271 170 class Persona(models.Model): 272 171 """ … … 277 176 def __unicode__(self): 278 177 return self.name 279 178 179 280 180 class Account(models.Model): 281 181 """ 282 182 A simple, generic account encapsulating the information shared by all … … 289 189 def __unicode__(self): 290 190 return "%s: %s" % (self.servicename, self.username) 291 191 192 292 193 class FooAccount(Account): 293 194 """A service-specific account of type Foo.""" 294 195 servicename = u'foo' 295 196 197 296 198 class BarAccount(Account): 297 199 """A service-specific account of type Bar.""" 298 200 servicename = u'bar' 299 201 300 class FooAccountAdmin(admin.StackedInline):301 model = FooAccount302 extra = 1303 304 class BarAccountAdmin(admin.StackedInline):305 model = BarAccount306 extra = 1307 308 class PersonaAdmin(admin.ModelAdmin):309 inlines = (310 FooAccountAdmin,311 BarAccountAdmin312 )313 202 314 203 class Subscriber(models.Model): 315 204 name = models.CharField(blank=False, max_length=80) … … 318 207 def __unicode__(self): 319 208 return "%s (%s)" % (self.name, self.email) 320 209 321 class SubscriberAdmin(admin.ModelAdmin):322 actions = ['mail_admin']323 324 def mail_admin(self, request, selected):325 EmailMessage(326 'Greetings from a ModelAdmin action',327 'This is the test email from a admin action',328 'from@example.com',329 ['to@example.com']330 ).send()331 210 332 211 class ExternalSubscriber(Subscriber): 333 212 pass 334 213 214 335 215 class OldSubscriber(Subscriber): 336 216 pass 337 217 338 def external_mail(modeladmin, request, selected):339 EmailMessage(340 'Greetings from a function action',341 'This is the test email from a function action',342 'from@example.com',343 ['to@example.com']344 ).send()345 external_mail.short_description = 'External mail (Another awesome action)'346 347 def redirect_to(modeladmin, request, selected):348 from django.http import HttpResponseRedirect349 return HttpResponseRedirect('/some-where-else/')350 redirect_to.short_description = 'Redirect to (Awesome action)'351 352 class ExternalSubscriberAdmin(admin.ModelAdmin):353 actions = [redirect_to, external_mail]354 218 355 219 class Media(models.Model): 356 220 name = models.CharField(max_length=60) 357 221 222 358 223 class Podcast(Media): 359 224 release_date = models.DateField() 360 225 361 226 class Meta: 362 227 ordering = ('release_date',) # overridden in PodcastAdmin 363 228 364 class PodcastAdmin(admin.ModelAdmin):365 list_display = ('name', 'release_date')366 list_editable = ('release_date',)367 date_hierarchy = 'release_date'368 ordering = ('name',)369 229 370 230 class Vodcast(Media): 371 231 media = models.OneToOneField(Media, primary_key=True, parent_link=True) 372 232 released = models.BooleanField(default=False) 373 233 374 class VodcastAdmin(admin.ModelAdmin):375 list_display = ('name', 'released')376 list_editable = ('released',)377 378 ordering = ('name',)379 234 380 235 class Parent(models.Model): 381 236 name = models.CharField(max_length=128) 382 237 238 383 239 class Child(models.Model): 384 240 parent = models.ForeignKey(Parent, editable=False) 385 241 name = models.CharField(max_length=30, blank=True) 386 242 387 class ChildInline(admin.StackedInline):388 model = Child389 390 class ParentAdmin(admin.ModelAdmin):391 model = Parent392 inlines = [ChildInline]393 394 list_editable = ('name',)395 396 def save_related(self, request, form, formsets, change):397 super(ParentAdmin, self).save_related(request, form, formsets, change)398 first_name, last_name = form.instance.name.split()399 for child in form.instance.child_set.all():400 if len(child.name.split()) < 2:401 child.name = child.name + ' ' + last_name402 child.save()403 243 404 244 class EmptyModel(models.Model): 405 245 def __unicode__(self): 406 246 return "Primary key = %s" % self.id 407 247 408 class EmptyModelAdmin(admin.ModelAdmin):409 def queryset(self, request):410 return super(EmptyModelAdmin, self).queryset(request).filter(pk__gt=1)411 412 class OldSubscriberAdmin(admin.ModelAdmin):413 actions = None414 248 415 249 temp_storage = FileSystemStorage(tempfile.mkdtemp()) 416 250 UPLOAD_TO = os.path.join(temp_storage.location, 'test_upload') 417 251 252 418 253 class Gallery(models.Model): 419 254 name = models.CharField(max_length=100) 420 255 256 421 257 class Picture(models.Model): 422 258 name = models.CharField(max_length=100) 423 259 image = models.FileField(storage=temp_storage, upload_to='test_upload') 424 260 gallery = models.ForeignKey(Gallery, related_name="pictures") 425 261 426 class PictureInline(admin.TabularInline):427 model = Picture428 extra = 1429 430 class GalleryAdmin(admin.ModelAdmin):431 inlines = [PictureInline]432 433 class PictureAdmin(admin.ModelAdmin):434 pass435 262 436 263 class Language(models.Model): 437 264 iso = models.CharField(max_length=5, primary_key=True) … … 442 269 class Meta: 443 270 ordering = ('iso',) 444 271 445 class LanguageAdmin(admin.ModelAdmin):446 list_display = ['iso', 'shortlist', 'english_name', 'name']447 list_editable = ['shortlist']448 272 449 273 # a base class for Recommender and Recommendation 450 274 class Title(models.Model): 451 275 pass 452 276 277 453 278 class TitleTranslation(models.Model): 454 279 title = models.ForeignKey(Title) 455 280 text = models.CharField(max_length=100) 456 281 282 457 283 class Recommender(Title): 458 284 pass 459 285 286 460 287 class Recommendation(Title): 461 288 recommender = models.ForeignKey(Recommender) 462 289 463 class RecommendationAdmin(admin.ModelAdmin):464 search_fields = ('=titletranslation__text', '=recommender__titletranslation__text',)465 290 466 291 class Collector(models.Model): 467 292 name = models.CharField(max_length=100) 468 293 294 469 295 class Widget(models.Model): 470 296 owner = models.ForeignKey(Collector) 471 297 name = models.CharField(max_length=100) 472 298 299 473 300 class DooHickey(models.Model): 474 301 code = models.CharField(max_length=10, primary_key=True) 475 302 owner = models.ForeignKey(Collector) 476 303 name = models.CharField(max_length=100) 477 304 305 478 306 class Grommet(models.Model): 479 307 code = models.AutoField(primary_key=True) 480 308 owner = models.ForeignKey(Collector) 481 309 name = models.CharField(max_length=100) 482 310 311 483 312 class Whatsit(models.Model): 484 313 index = models.IntegerField(primary_key=True) 485 314 owner = models.ForeignKey(Collector) 486 315 name = models.CharField(max_length=100) 487 316 317 488 318 class Doodad(models.Model): 489 319 name = models.CharField(max_length=100) 490 320 321 491 322 class FancyDoodad(Doodad): 492 323 owner = models.ForeignKey(Collector) 493 324 expensive = models.BooleanField(default=True) 494 325 495 class WidgetInline(admin.StackedInline):496 model = Widget497 498 class DooHickeyInline(admin.StackedInline):499 model = DooHickey500 501 class GrommetInline(admin.StackedInline):502 model = Grommet503 504 class WhatsitInline(admin.StackedInline):505 model = Whatsit506 507 class FancyDoodadInline(admin.StackedInline):508 model = FancyDoodad509 326 510 327 class Category(models.Model): 511 328 collector = models.ForeignKey(Collector) … … 517 334 def __unicode__(self): 518 335 return u'%s:o%s' % (self.id, self.order) 519 336 520 class CategoryAdmin(admin.ModelAdmin):521 list_display = ('id', 'collector', 'order')522 list_editable = ('order',)523 524 class CategoryInline(admin.StackedInline):525 model = Category526 527 class CollectorAdmin(admin.ModelAdmin):528 inlines = [529 WidgetInline, DooHickeyInline, GrommetInline, WhatsitInline,530 FancyDoodadInline, CategoryInline531 ]532 337 533 338 class Link(models.Model): 534 339 posted = models.DateField( … … 538 343 post = models.ForeignKey("Post") 539 344 540 345 541 class LinkInline(admin.TabularInline):542 model = Link543 extra = 1544 545 readonly_fields = ("posted",)546 547 548 346 class PrePopulatedPost(models.Model): 549 347 title = models.CharField(max_length=100) 550 348 published = models.BooleanField() 551 349 slug = models.SlugField() 552 350 351 553 352 class PrePopulatedSubPost(models.Model): 554 353 post = models.ForeignKey(PrePopulatedPost) 555 354 subtitle = models.CharField(max_length=100) 556 355 subslug = models.SlugField() 557 356 558 class SubPostInline(admin.TabularInline):559 model = PrePopulatedSubPost560 561 prepopulated_fields = {562 'subslug' : ('subtitle',)563 }564 565 def get_readonly_fields(self, request, obj=None):566 if obj and obj.published:567 return ('subslug',)568 return self.readonly_fields569 570 def get_prepopulated_fields(self, request, obj=None):571 if obj and obj.published:572 return {}573 return self.prepopulated_fields574 575 class PrePopulatedPostAdmin(admin.ModelAdmin):576 list_display = ['title', 'slug']577 prepopulated_fields = {578 'slug' : ('title',)579 }580 581 inlines = [SubPostInline]582 583 def get_readonly_fields(self, request, obj=None):584 if obj and obj.published:585 return ('slug',)586 return self.readonly_fields587 588 def get_prepopulated_fields(self, request, obj=None):589 if obj and obj.published:590 return {}591 return self.prepopulated_fields592 357 593 358 class Post(models.Model): 594 359 title = models.CharField(max_length=100, help_text="Some help text for the title (with unicode ŠĐĆŽćžšđ)") … … 602 367 def awesomeness_level(self): 603 368 return "Very awesome." 604 369 605 class PostAdmin(admin.ModelAdmin):606 list_display = ['title', 'public']607 readonly_fields = ('posted', 'awesomeness_level', 'coolness', 'value', lambda obj: "foo")608 609 inlines = [610 LinkInline611 ]612 613 def coolness(self, instance):614 if instance.pk:615 return "%d amount of cool." % instance.pk616 else:617 return "Unkown coolness."618 619 def value(self, instance):620 return 1000621 value.short_description = 'Value in $US'622 370 623 371 class Gadget(models.Model): 624 372 name = models.CharField(max_length=100) … … 626 374 def __unicode__(self): 627 375 return self.name 628 376 629 class CustomChangeList(ChangeList):630 def get_query_set(self, request):631 return self.root_query_set.filter(pk=9999) # Does not exist632 633 class GadgetAdmin(admin.ModelAdmin):634 def get_changelist(self, request, **kwargs):635 return CustomChangeList636 377 637 378 class Villain(models.Model): 638 379 name = models.CharField(max_length=100) … … 640 381 def __unicode__(self): 641 382 return self.name 642 383 384 643 385 class SuperVillain(Villain): 644 386 pass 645 387 388 646 389 class FunkyTag(models.Model): 647 390 "Because we all know there's only one real use case for GFKs." 648 391 name = models.CharField(max_length=25) … … 653 396 def __unicode__(self): 654 397 return self.name 655 398 399 656 400 class Plot(models.Model): 657 401 name = models.CharField(max_length=100) 658 402 team_leader = models.ForeignKey(Villain, related_name='lead_plots') … … 662 406 def __unicode__(self): 663 407 return self.name 664 408 409 665 410 class PlotDetails(models.Model): 666 411 details = models.CharField(max_length=100) 667 412 plot = models.OneToOneField(Plot) … … 669 414 def __unicode__(self): 670 415 return self.details 671 416 417 672 418 class SecretHideout(models.Model): 673 419 """ Secret! Not registered with the admin! """ 674 420 location = models.CharField(max_length=100) … … 677 423 def __unicode__(self): 678 424 return self.location 679 425 426 680 427 class SuperSecretHideout(models.Model): 681 428 """ Secret! Not registered with the admin! """ 682 429 location = models.CharField(max_length=100) … … 685 432 def __unicode__(self): 686 433 return self.location 687 434 435 688 436 class CyclicOne(models.Model): 689 437 name = models.CharField(max_length=25) 690 438 two = models.ForeignKey('CyclicTwo') … … 692 440 def __unicode__(self): 693 441 return self.name 694 442 443 695 444 class CyclicTwo(models.Model): 696 445 name = models.CharField(max_length=25) 697 446 one = models.ForeignKey(CyclicOne) … … 699 448 def __unicode__(self): 700 449 return self.name 701 450 451 702 452 class Topping(models.Model): 703 453 name = models.CharField(max_length=20) 704 454 455 705 456 class Pizza(models.Model): 706 457 name = models.CharField(max_length=20) 707 458 toppings = models.ManyToManyField('Topping') 708 459 709 class PizzaAdmin(admin.ModelAdmin):710 readonly_fields = ('toppings',)711 460 712 461 class Album(models.Model): 713 462 owner = models.ForeignKey(User) 714 463 title = models.CharField(max_length=30) 715 464 716 class AlbumAdmin(admin.ModelAdmin):717 list_filter = ['title']718 465 719 466 class Employee(Person): 720 467 code = models.CharField(max_length=20) 721 468 469 722 470 class WorkHour(models.Model): 723 471 datum = models.DateField() 724 472 employee = models.ForeignKey(Employee) 725 473 726 class WorkHourAdmin(admin.ModelAdmin):727 list_display = ('datum', 'employee')728 list_filter = ('employee',)729 474 730 475 class Question(models.Model): 731 476 question = models.CharField(max_length=20) 732 477 478 733 479 class Answer(models.Model): 734 480 question = models.ForeignKey(Question, on_delete=models.PROTECT) 735 481 answer = models.CharField(max_length=20) … … 737 483 def __unicode__(self): 738 484 return self.answer 739 485 486 740 487 class Reservation(models.Model): 741 488 start_date = models.DateTimeField() 742 489 price = models.IntegerField() … … 753 500 (u'pizza', u'Pizza Mama'), 754 501 ) 755 502 503 756 504 class FoodDelivery(models.Model): 757 505 reference = models.CharField(max_length=100) 758 506 driver = models.CharField(max_length=100, choices=DRIVER_CHOICES, blank=True) … … 761 509 class Meta: 762 510 unique_together = (("driver", "restaurant"),) 763 511 764 class FoodDeliveryAdmin(admin.ModelAdmin):765 list_display=('reference', 'driver', 'restaurant')766 list_editable = ('driver', 'restaurant')767 512 768 513 class Paper(models.Model): 769 514 title = models.CharField(max_length=30) 770 515 author = models.CharField(max_length=30, blank=True, null=True) 771 516 517 772 518 class CoverLetter(models.Model): 773 519 author = models.CharField(max_length=30) 774 520 date_written = models.DateField(null=True, blank=True) … … 776 522 def __unicode__(self): 777 523 return self.author 778 524 779 class PaperAdmin(admin.ModelAdmin):780 """781 A ModelAdin with a custom queryset() method that uses only(), to test782 verbose_name display in messages shown after adding Paper instances.783 """784 785 def queryset(self, request):786 return super(PaperAdmin, self).queryset(request).only('title')787 788 class CoverLetterAdmin(admin.ModelAdmin):789 """790 A ModelAdin with a custom queryset() method that uses only(), to test791 verbose_name display in messages shown after adding CoverLetter instances.792 Note that the CoverLetter model defines a __unicode__ method.793 """794 795 def queryset(self, request):796 return super(CoverLetterAdmin, self).queryset(request).defer('date_written')797 525 798 526 class Story(models.Model): 799 527 title = models.CharField(max_length=100) 800 528 content = models.TextField() 801 529 802 class StoryForm(forms.ModelForm):803 class Meta:804 widgets = {'title': forms.HiddenInput}805 806 class StoryAdmin(admin.ModelAdmin):807 list_display = ('id', 'title', 'content')808 list_display_links = ('title',) # 'id' not in list_display_links809 list_editable = ('content', )810 form = StoryForm811 ordering = ["-pk"]812 530 813 531 class OtherStory(models.Model): 814 532 title = models.CharField(max_length=100) 815 533 content = models.TextField() 816 534 817 class OtherStoryAdmin(admin.ModelAdmin):818 list_display = ('id', 'title', 'content')819 list_display_links = ('title', 'id') # 'id' in list_display_links820 list_editable = ('content', )821 ordering = ["-pk"]822 535 823 536 class ComplexSortedPerson(models.Model): 824 537 name = models.CharField(max_length=100) 825 538 age = models.PositiveIntegerField() 826 539 is_employee = models.NullBooleanField() 827 540 828 class ComplexSortedPersonAdmin(admin.ModelAdmin):829 list_display = ('name', 'age', 'is_employee', 'colored_name')830 ordering = ('name',)831 832 def colored_name(self, obj):833 return '<span style="color: #%s;">%s</span>' % ('ff00ff', obj.name)834 colored_name.allow_tags = True835 colored_name.admin_order_field = 'name'836 837 admin.site.register(Article, ArticleAdmin)838 admin.site.register(CustomArticle, CustomArticleAdmin)839 admin.site.register(Section, save_as=True, inlines=[ArticleInline])840 admin.site.register(ModelWithStringPrimaryKey)841 admin.site.register(Color)842 admin.site.register(Thing, ThingAdmin)843 admin.site.register(Actor)844 admin.site.register(Inquisition, InquisitionAdmin)845 admin.site.register(Sketch, SketchAdmin)846 admin.site.register(Person, PersonAdmin)847 admin.site.register(Persona, PersonaAdmin)848 admin.site.register(Subscriber, SubscriberAdmin)849 admin.site.register(ExternalSubscriber, ExternalSubscriberAdmin)850 admin.site.register(OldSubscriber, OldSubscriberAdmin)851 admin.site.register(Podcast, PodcastAdmin)852 admin.site.register(Vodcast, VodcastAdmin)853 admin.site.register(Parent, ParentAdmin)854 admin.site.register(EmptyModel, EmptyModelAdmin)855 admin.site.register(Fabric, FabricAdmin)856 admin.site.register(Gallery, GalleryAdmin)857 admin.site.register(Picture, PictureAdmin)858 admin.site.register(Language, LanguageAdmin)859 admin.site.register(Recommendation, RecommendationAdmin)860 admin.site.register(Recommender)861 admin.site.register(Collector, CollectorAdmin)862 admin.site.register(Category, CategoryAdmin)863 admin.site.register(Post, PostAdmin)864 admin.site.register(Gadget, GadgetAdmin)865 admin.site.register(Villain)866 admin.site.register(SuperVillain)867 admin.site.register(Plot)868 admin.site.register(PlotDetails)869 admin.site.register(CyclicOne)870 admin.site.register(CyclicTwo)871 admin.site.register(WorkHour, WorkHourAdmin)872 admin.site.register(Reservation)873 admin.site.register(FoodDelivery, FoodDeliveryAdmin)874 admin.site.register(RowLevelChangePermissionModel, RowLevelChangePermissionModelAdmin)875 admin.site.register(Paper, PaperAdmin)876 admin.site.register(CoverLetter, CoverLetterAdmin)877 admin.site.register(Story, StoryAdmin)878 admin.site.register(OtherStory, OtherStoryAdmin)879 880 # We intentionally register Promo and ChapterXtra1 but not Chapter nor ChapterXtra2.881 # That way we cover all four cases:882 # related ForeignKey object registered in admin883 # related ForeignKey object not registered in admin884 # related OneToOne object registered in admin885 # related OneToOne object not registered in admin886 # when deleting Book so as exercise all four troublesome (w.r.t escaping887 # and calling force_unicode to avoid problems on Python 2.3) paths through888 # contrib.admin.util's get_deleted_objects function.889 admin.site.register(Book, inlines=[ChapterInline])890 admin.site.register(Promo)891 admin.site.register(ChapterXtra1, ChapterXtra1Admin)892 admin.site.register(Pizza, PizzaAdmin)893 admin.site.register(Topping)894 admin.site.register(Album, AlbumAdmin)895 admin.site.register(Question)896 admin.site.register(Answer)897 admin.site.register(PrePopulatedPost, PrePopulatedPostAdmin)898 admin.site.register(ComplexSortedPerson, ComplexSortedPersonAdmin) -
tests/regressiontests/admin_views/tests.py
diff --git a/tests/regressiontests/admin_views/tests.py b/tests/regressiontests/admin_views/tests.py
a b 32 32 33 33 # local test models 34 34 from models import (Article, BarAccount, CustomArticle, EmptyModel, 35 FooAccount, Gallery, PersonAdmin,ModelWithStringPrimaryKey,35 FooAccount, Gallery, ModelWithStringPrimaryKey, 36 36 Person, Persona, Picture, Podcast, Section, Subscriber, Vodcast, 37 37 Language, Collector, Widget, Grommet, DooHickey, FancyDoodad, Whatsit, 38 38 Category, Post, Plot, FunkyTag, Chapter, Book, Promo, WorkHour, Employee, … … 50 50 # this test case and changing urlbit. 51 51 urlbit = 'admin' 52 52 53 urls = "regressiontests.admin_views.urls" 54 53 55 def setUp(self): 54 56 self.old_USE_I18N = settings.USE_I18N 55 57 self.old_USE_L10N = settings.USE_L10N … … 301 303 response.content.index(link % l1.pk) < response.content.index(link % l2.pk) 302 304 ) 303 305 304 def testChangeListSorting ModelAdmin(self):306 def testChangeListSortingOverrideModelAdmin(self): 305 307 # Test ordering on Model Admin is respected, and overrides Model Meta 306 308 dt = datetime.datetime.now() 307 309 p1 = Podcast.objects.create(name="A", release_date=dt) … … 542 544 self.fail("Filters should be allowed if they are defined on a ForeignKey pointing to this model") 543 545 544 546 class AdminJavaScriptTest(AdminViewBasicTest): 547 urls = "regressiontests.admin_views.urls" 548 545 549 def testSingleWidgetFirsFieldFocus(self): 546 550 """ 547 551 JavaScript-assisted auto-focus on first field. … … 565 569 566 570 567 571 class SaveAsTests(TestCase): 572 urls = "regressiontests.admin_views.urls" 568 573 fixtures = ['admin-views-users.xml','admin-views-person.xml'] 569 574 570 575 def setUp(self): … … 593 598 self.assertEqual(response.context['form_url'], '../add/') 594 599 595 600 class CustomModelAdminTest(AdminViewBasicTest): 601 urls = "regressiontests.admin_views.urls" 596 602 urlbit = "admin2" 597 603 598 604 def testCustomAdminSiteLoginForm(self): … … 654 660 class AdminViewPermissionsTest(TestCase): 655 661 """Tests for Admin Views Permissions.""" 656 662 663 urls = "regressiontests.admin_views.urls" 657 664 fixtures = ['admin-views-users.xml'] 658 665 659 666 def setUp(self): … … 1055 1062 1056 1063 1057 1064 class AdminViewDeletedObjectsTest(TestCase): 1065 urls = "regressiontests.admin_views.urls" 1058 1066 fixtures = ['admin-views-users.xml', 'deleted-objects.xml'] 1059 1067 1060 1068 def setUp(self): … … 1170 1178 self.assertContains(response, should_contain) 1171 1179 1172 1180 class AdminViewStringPrimaryKeyTest(TestCase): 1181 urls = "regressiontests.admin_views.urls" 1173 1182 fixtures = ['admin-views-users.xml', 'string-primary-key.xml'] 1174 1183 1175 1184 def __init__(self, *args): … … 1261 1270 1262 1271 1263 1272 class SecureViewTests(TestCase): 1273 urls = "regressiontests.admin_views.urls" 1264 1274 fixtures = ['admin-views-users.xml'] 1265 1275 1266 1276 def setUp(self): … … 1418 1428 self.assertEqual(response['Location'], 'http://example.com/users/super/') 1419 1429 1420 1430 class AdminViewUnicodeTest(TestCase): 1431 urls = "regressiontests.admin_views.urls" 1421 1432 fixtures = ['admin-views-unicode.xml'] 1422 1433 1423 1434 def setUp(self): … … 1471 1482 1472 1483 1473 1484 class AdminViewListEditable(TestCase): 1485 urls = "regressiontests.admin_views.urls" 1474 1486 fixtures = ['admin-views-users.xml', 'admin-views-person.xml'] 1475 1487 1476 1488 def setUp(self): … … 1827 1839 1828 1840 1829 1841 class AdminSearchTest(TestCase): 1842 urls = "regressiontests.admin_views.urls" 1830 1843 fixtures = ['admin-views-users', 'multiple-child-classes', 1831 1844 'admin-views-person'] 1832 1845 … … 1873 1886 1874 1887 1875 1888 class AdminInheritedInlinesTest(TestCase): 1889 urls = "regressiontests.admin_views.urls" 1876 1890 fixtures = ['admin-views-users.xml',] 1877 1891 1878 1892 def setUp(self): … … 1958 1972 self.assertEqual(Persona.objects.all()[0].accounts.count(), 2) 1959 1973 1960 1974 class AdminActionsTest(TestCase): 1975 urls = "regressiontests.admin_views.urls" 1961 1976 fixtures = ['admin-views-users.xml', 'admin-views-actions.xml'] 1962 1977 1963 1978 def setUp(self): … … 2179 2194 2180 2195 2181 2196 class TestCustomChangeList(TestCase): 2197 urls = "regressiontests.admin_views.urls" 2182 2198 fixtures = ['admin-views-users.xml'] 2183 2199 urlbit = 'admin' 2184 2200 … … 2206 2222 2207 2223 2208 2224 class TestInlineNotEditable(TestCase): 2225 urls = "regressiontests.admin_views.urls" 2209 2226 fixtures = ['admin-views-users.xml'] 2210 2227 2211 2228 def setUp(self): … … 2223 2240 self.assertEqual(response.status_code, 200) 2224 2241 2225 2242 class AdminCustomQuerysetTest(TestCase): 2243 urls = "regressiontests.admin_views.urls" 2226 2244 fixtures = ['admin-views-users.xml'] 2227 2245 2228 2246 def setUp(self): … … 2277 2295 self.assertContains(response, '<li class="info">The cover letter "John Doe II" was changed successfully.</li>') 2278 2296 2279 2297 class AdminInlineFileUploadTest(TestCase): 2298 urls = "regressiontests.admin_views.urls" 2280 2299 fixtures = ['admin-views-users.xml', 'admin-views-actions.xml'] 2281 2300 urlbit = 'admin' 2282 2301 … … 2322 2341 2323 2342 2324 2343 class AdminInlineTests(TestCase): 2344 urls = "regressiontests.admin_views.urls" 2325 2345 fixtures = ['admin-views-users.xml'] 2326 2346 2327 2347 def setUp(self): … … 2639 2659 2640 2660 2641 2661 class NeverCacheTests(TestCase): 2662 urls = "regressiontests.admin_views.urls" 2642 2663 fixtures = ['admin-views-users.xml', 'admin-views-colors.xml', 'admin-views-fabrics.xml'] 2643 2664 2644 2665 def setUp(self): … … 2711 2732 2712 2733 2713 2734 class PrePopulatedTest(TestCase): 2735 urls = "regressiontests.admin_views.urls" 2714 2736 fixtures = ['admin-views-users.xml'] 2715 2737 2716 2738 def setUp(self): … … 2735 2757 self.assertNotContains(response, "id: '#id_prepopulatedsubpost_set-0-subslug',") 2736 2758 2737 2759 class ReadonlyTest(TestCase): 2760 urls = "regressiontests.admin_views.urls" 2738 2761 fixtures = ['admin-views-users.xml'] 2739 2762 2740 2763 def setUp(self): … … 2802 2825 2803 2826 2804 2827 class RawIdFieldsTest(TestCase): 2828 urls = "regressiontests.admin_views.urls" 2805 2829 fixtures = ['admin-views-users.xml'] 2806 2830 2807 2831 def setUp(self): … … 2837 2861 """ 2838 2862 Tests user CRUD functionality. 2839 2863 """ 2864 urls = "regressiontests.admin_views.urls" 2840 2865 fixtures = ['admin-views-users.xml'] 2841 2866 2842 2867 def setUp(self): … … 2928 2953 """ 2929 2954 Tests group CRUD functionality. 2930 2955 """ 2956 urls = "regressiontests.admin_views.urls" 2931 2957 fixtures = ['admin-views-users.xml'] 2932 2958 2933 2959 def setUp(self): … … 2961 2987 2962 2988 #@unittest.skipUnless(docutils, "no docutils installed.") 2963 2989 class AdminDocsTest(TestCase): 2990 urls = "regressiontests.admin_views.urls" 2964 2991 fixtures = ['admin-views-users.xml'] 2965 2992 2966 2993 def setUp(self): … … 3003 3030 AdminDocsTest = unittest.skipUnless(docutils, "no docutils installed.")(AdminDocsTest) 3004 3031 3005 3032 class ValidXHTMLTests(TestCase): 3033 urls = "regressiontests.admin_views.urls" 3006 3034 fixtures = ['admin-views-users.xml'] 3007 3035 urlbit = 'admin' 3008 3036 … … 3033 3061 3034 3062 3035 3063 class DateHierarchyTests(TestCase): 3064 urls = "regressiontests.admin_views.urls" 3036 3065 fixtures = ['admin-views-users.xml'] 3037 3066 3038 3067 def setUp(self): … … 3162 3191 Ensure that one can easily customize the way related objects are saved. 3163 3192 Refs #16115. 3164 3193 """ 3194 urls = "regressiontests.admin_views.urls" 3165 3195 fixtures = ['admin-views-users.xml'] 3166 3196 3167 3197 def setUp(self): -
tests/regressiontests/admin_views/urls.py
diff --git a/tests/regressiontests/admin_views/urls.py b/tests/regressiontests/admin_views/urls.py
a b 1 1 from django.conf.urls import patterns, include 2 from django.contrib import admin3 2 import views 4 3 import customadmin 4 import admin 5 5 6 6 urlpatterns = patterns('', 7 (r'^ admin/doc/', include('django.contrib.admindocs.urls')),8 (r'^ admin/secure-view/$', views.secure_view),9 (r'^ admin/', include(admin.site.urls)),10 (r'^ admin2/', include(customadmin.site.urls)),7 (r'^test_admin/admin/doc/', include('django.contrib.admindocs.urls')), 8 (r'^test_admin/admin/secure-view/$', views.secure_view), 9 (r'^test_admin/admin/', include(admin.site.urls)), 10 (r'^test_admin/admin2/', include(customadmin.site.urls)), 11 11 ) -
tests/regressiontests/cache/tests.py
diff --git a/tests/regressiontests/cache/tests.py b/tests/regressiontests/cache/tests.py
a b 1591 1591 1592 1592 class TestEtagWithAdmin(TestCase): 1593 1593 # See https://code.djangoproject.com/ticket/16003 1594 urls = "regressiontests.admin_views.urls" 1595 1594 1596 def test_admin(self): 1595 1597 with self.settings(USE_ETAGS=False): 1596 1598 response = self.client.get('/test_admin/admin/') -
new file tests/regressiontests/generic_inline_admin/admin.py
diff --git a/tests/regressiontests/generic_inline_admin/admin.py b/tests/regressiontests/generic_inline_admin/admin.py new file mode 100644
- + 1 from django.contrib import admin 2 from django.contrib.contenttypes import generic 3 4 from models import (Media, PhoneNumber, Episode, EpisodeExtra, Contact, 5 Category, EpisodePermanent, EpisodeMaxNum) 6 7 site = admin.AdminSite(name="admin") 8 9 class MediaInline(generic.GenericTabularInline): 10 model = Media 11 12 13 class EpisodeAdmin(admin.ModelAdmin): 14 inlines = [ 15 MediaInline, 16 ] 17 18 19 class MediaExtraInline(generic.GenericTabularInline): 20 model = Media 21 extra = 0 22 23 24 class MediaMaxNumInline(generic.GenericTabularInline): 25 model = Media 26 extra = 5 27 max_num = 2 28 29 30 class PhoneNumberInline(generic.GenericTabularInline): 31 model = PhoneNumber 32 33 34 class MediaPermanentInline(generic.GenericTabularInline): 35 model = Media 36 can_delete = False 37 38 39 site.register(Episode, EpisodeAdmin) 40 site.register(EpisodeExtra, inlines=[MediaExtraInline]) 41 site.register(EpisodeMaxNum, inlines=[MediaMaxNumInline]) 42 site.register(Contact, inlines=[PhoneNumberInline]) 43 site.register(Category) 44 site.register(EpisodePermanent, inlines=[MediaPermanentInline]) -
tests/regressiontests/generic_inline_admin/models.py
diff --git a/tests/regressiontests/generic_inline_admin/models.py b/tests/regressiontests/generic_inline_admin/models.py
a b 1 1 from django.db import models 2 from django.contrib import admin3 2 from django.contrib.contenttypes import generic 4 3 from django.contrib.contenttypes.models import ContentType 5 4 5 6 6 class Episode(models.Model): 7 7 name = models.CharField(max_length=100) 8 8 length = models.CharField(max_length=100, blank=True) 9 9 author = models.CharField(max_length=100, blank=True) 10 10 11 11 12 class Media(models.Model): 12 13 """ 13 14 Media that can associated to any object. … … 22 23 def __unicode__(self): 23 24 return self.url 24 25 25 class MediaInline(generic.GenericTabularInline):26 model = Media27 28 class EpisodeAdmin(admin.ModelAdmin):29 inlines = [30 MediaInline,31 ]32 admin.site.register(Episode, EpisodeAdmin)33 34 26 # 35 27 # These models let us test the different GenericInline settings at 36 28 # different urls in the admin site. … … 43 35 class EpisodeExtra(Episode): 44 36 pass 45 37 46 class MediaExtraInline(generic.GenericTabularInline):47 model = Media48 extra = 049 50 admin.site.register(EpisodeExtra, inlines=[MediaExtraInline])51 38 52 39 # 53 40 # Generic inline with extra and max_num 54 41 # 55 56 42 class EpisodeMaxNum(Episode): 57 43 pass 58 44 59 class MediaMaxNumInline(generic.GenericTabularInline):60 model = Media61 extra = 562 max_num = 263 64 admin.site.register(EpisodeMaxNum, inlines=[MediaMaxNumInline])65 66 45 67 46 # 68 47 # Generic inline with unique_together 69 48 # 70 71 49 class Category(models.Model): 72 50 name = models.CharField(max_length=50) 73 51 52 74 53 class PhoneNumber(models.Model): 75 54 content_type = models.ForeignKey(ContentType) 76 55 object_id = models.PositiveIntegerField() … … 81 60 class Meta: 82 61 unique_together = (('content_type', 'object_id', 'phone_number',),) 83 62 63 84 64 class Contact(models.Model): 85 65 name = models.CharField(max_length=50) 86 66 phone_numbers = generic.GenericRelation(PhoneNumber) 87 67 88 class PhoneNumberInline(generic.GenericTabularInline):89 model = PhoneNumber90 91 admin.site.register(Contact, inlines=[PhoneNumberInline])92 admin.site.register(Category)93 94 68 # 95 69 # Generic inline with can_delete=False 96 70 # 97 98 71 class EpisodePermanent(Episode): 99 72 pass 100 73 101 class MediaPermanentInline(generic.GenericTabularInline):102 model = Media103 can_delete = False104 74 105 admin.site.register(EpisodePermanent, inlines=[MediaPermanentInline]) -
tests/regressiontests/generic_inline_admin/tests.py
diff --git a/tests/regressiontests/generic_inline_admin/tests.py b/tests/regressiontests/generic_inline_admin/tests.py
a b 10 10 11 11 # local test models 12 12 from models import (Episode, EpisodeExtra, EpisodeMaxNum, Media, 13 MediaInline, EpisodePermanent, MediaPermanentInline, Category) 13 EpisodePermanent, Category) 14 from admin import MediaInline, MediaPermanentInline 14 15 15 16 16 17 class GenericAdminViewTest(TestCase): 18 urls = "regressiontests.generic_inline_admin.urls" 17 19 fixtures = ['users.xml'] 18 20 19 21 def setUp(self): … … 125 127 self.assertTrue(formset.get_queryset().ordered) 126 128 127 129 class GenericInlineAdminParametersTest(TestCase): 130 urls = "regressiontests.generic_inline_admin.urls" 128 131 fixtures = ['users.xml'] 129 132 130 133 def setUp(self): … … 177 180 178 181 179 182 class GenericInlineAdminWithUniqueTogetherTest(TestCase): 183 urls = "regressiontests.generic_inline_admin.urls" 180 184 fixtures = ['users.xml'] 181 185 182 186 def setUp(self): … … 203 207 self.assertEqual(response.status_code, 302) # redirect somewhere 204 208 205 209 class NoInlineDeletionTest(TestCase): 210 urls = "regressiontests.generic_inline_admin.urls" 211 206 212 def test_no_deletion(self): 207 213 fake_site = object() 208 214 inline = MediaPermanentInline(EpisodePermanent, fake_site) … … 211 217 self.assertFalse(formset.can_delete) 212 218 213 219 class GenericInlineModelAdminTest(TestCase): 220 urls = "regressiontests.generic_inline_admin.urls" 214 221 215 222 def setUp(self): 216 223 self.site = AdminSite() -
tests/regressiontests/generic_inline_admin/urls.py
diff --git a/tests/regressiontests/generic_inline_admin/urls.py b/tests/regressiontests/generic_inline_admin/urls.py
a b 1 1 from django.conf.urls import patterns, include 2 from django.contrib import admin 2 3 import admin 3 4 4 5 urlpatterns = patterns('', 5 (r'^ admin/', include(admin.site.urls)),6 (r'^generic_inline_admin/admin/', include(admin.site.urls)), 6 7 ) -
tests/urls.py
diff --git a/tests/urls.py b/tests/urls.py
a b 22 22 # test urlconf for middleware tests 23 23 (r'^middleware/', include('regressiontests.middleware.urls')), 24 24 25 # admin view tests26 (r'^test_admin/', include('regressiontests.admin_views.urls')),27 (r'^generic_inline_admin/', include('regressiontests.generic_inline_admin.urls')),28 29 25 # admin widget tests 30 26 (r'widget_admin/', include('regressiontests.admin_widgets.urls')), 31 27