')
def test_callable_lookup(self):
"""Admin inline should invoke local callable when its name is listed in readonly_fields"""
- response = self.client.get('/test_admin/admin/admin_inlines/poll/add/')
+ response = self.client.get('/admin/admin_inlines/poll/add/')
self.assertEqual(response.status_code, 200)
# Add parent object view should have the child inlines section
self.assertContains(response, '
')
@@ -109,11 +111,12 @@ class TestInline(TestCase):
using both the stacked and tabular layouts.
Ref #8190.
"""
- response = self.client.get('/test_admin/admin/admin_inlines/holder4/add/')
+ response = self.client.get('/admin/admin_inlines/holder4/add/')
self.assertContains(response, '
Awesome stacked help text is awesome.
', 4)
self.assertContains(response, '

', 1)
class TestInlineMedia(TestCase):
+ urls = "regressiontests.admin_inlines.urls"
fixtures = ['admin-views-users.xml']
def setUp(self):
@@ -128,7 +131,7 @@ class TestInlineMedia(TestCase):
holder = Holder(dummy=13)
holder.save()
Inner(dummy=42, holder=holder).save()
- change_url = '/test_admin/admin/admin_inlines/holder/%i/' % holder.id
+ change_url = '/admin/admin_inlines/holder/%i/' % holder.id
response = self.client.get(change_url)
self.assertContains(response, 'my_awesome_admin_scripts.js')
@@ -136,7 +139,7 @@ class TestInlineMedia(TestCase):
holder = Holder3(dummy=13)
holder.save()
Inner3(dummy=42, holder=holder).save()
- change_url = '/test_admin/admin/admin_inlines/holder3/%i/' % holder.id
+ change_url = '/admin/admin_inlines/holder3/%i/' % holder.id
response = self.client.get(change_url)
self.assertContains(response, 'my_awesome_inline_scripts.js')
@@ -144,12 +147,13 @@ class TestInlineMedia(TestCase):
holder = Holder2(dummy=13)
holder.save()
Inner2(dummy=42, holder=holder).save()
- change_url = '/test_admin/admin/admin_inlines/holder2/%i/' % holder.id
+ change_url = '/admin/admin_inlines/holder2/%i/' % holder.id
response = self.client.get(change_url)
self.assertContains(response, 'my_awesome_admin_scripts.js')
self.assertContains(response, 'my_awesome_inline_scripts.js')
class TestInlineAdminForm(TestCase):
+ urls = "regressiontests.admin_inlines.urls"
def test_immutable_content_type(self):
"""Regression for #9362
diff --git a/tests/regressiontests/admin_inlines/urls.py b/tests/regressiontests/admin_inlines/urls.py
new file mode 100644
index 0000000000..017a0010ae
--- /dev/null
+++ b/tests/regressiontests/admin_inlines/urls.py
@@ -0,0 +1,7 @@
+from django.conf.urls import patterns, include
+
+import admin
+
+urlpatterns = patterns('',
+ (r'^admin/', include(admin.site.urls)),
+)
diff --git a/tests/regressiontests/admin_views/admin.py b/tests/regressiontests/admin_views/admin.py
new file mode 100644
index 0000000000..e4aae4fed9
--- /dev/null
+++ b/tests/regressiontests/admin_views/admin.py
@@ -0,0 +1,526 @@
+# -*- coding: utf-8 -*-
+import datetime
+import tempfile
+import os
+
+from django.contrib import admin
+from django.contrib.admin.views.main import ChangeList
+from django.forms.models import BaseModelFormSet
+from django.core.mail import EmailMessage
+
+from models import *
+
+
+def callable_year(dt_value):
+ return dt_value.year
+callable_year.admin_order_field = 'date'
+
+
+class ArticleInline(admin.TabularInline):
+ model = Article
+
+
+class ChapterInline(admin.TabularInline):
+ model = Chapter
+
+
+class ChapterXtra1Admin(admin.ModelAdmin):
+ list_filter = ('chap',
+ 'chap__title',
+ 'chap__book',
+ 'chap__book__name',
+ 'chap__book__promo',
+ 'chap__book__promo__name',)
+
+
+class ArticleAdmin(admin.ModelAdmin):
+ list_display = ('content', 'date', callable_year, 'model_year', 'modeladmin_year')
+ list_filter = ('date', 'section')
+
+ def changelist_view(self, request):
+ "Test that extra_context works"
+ return super(ArticleAdmin, self).changelist_view(
+ request, extra_context={
+ 'extra_var': 'Hello!'
+ }
+ )
+
+ def modeladmin_year(self, obj):
+ return obj.date.year
+ modeladmin_year.admin_order_field = 'date'
+ modeladmin_year.short_description = None
+
+ def delete_model(self, request, obj):
+ EmailMessage(
+ 'Greetings from a deleted object',
+ 'I hereby inform you that some user deleted me',
+ 'from@example.com',
+ ['to@example.com']
+ ).send()
+ return super(ArticleAdmin, self).delete_model(request, obj)
+
+ def save_model(self, request, obj, form, change=True):
+ EmailMessage(
+ 'Greetings from a created object',
+ 'I hereby inform you that some user created me',
+ 'from@example.com',
+ ['to@example.com']
+ ).send()
+ return super(ArticleAdmin, self).save_model(request, obj, form, change)
+
+
+class RowLevelChangePermissionModelAdmin(admin.ModelAdmin):
+ def has_change_permission(self, request, obj=None):
+ """ Only allow changing objects with even id number """
+ return request.user.is_staff and (obj is not None) and (obj.id % 2 == 0)
+
+
+class CustomArticleAdmin(admin.ModelAdmin):
+ """
+ Tests various hooks for using custom templates and contexts.
+ """
+ change_list_template = 'custom_admin/change_list.html'
+ change_form_template = 'custom_admin/change_form.html'
+ add_form_template = 'custom_admin/add_form.html'
+ object_history_template = 'custom_admin/object_history.html'
+ delete_confirmation_template = 'custom_admin/delete_confirmation.html'
+ delete_selected_confirmation_template = 'custom_admin/delete_selected_confirmation.html'
+
+ def changelist_view(self, request):
+ "Test that extra_context works"
+ return super(CustomArticleAdmin, self).changelist_view(
+ request, extra_context={
+ 'extra_var': 'Hello!'
+ }
+ )
+
+
+class ThingAdmin(admin.ModelAdmin):
+ list_filter = ('color__warm', 'color__value')
+
+
+class InquisitionAdmin(admin.ModelAdmin):
+ list_display = ('leader', 'country', 'expected')
+
+
+class SketchAdmin(admin.ModelAdmin):
+ raw_id_fields = ('inquisition',)
+
+
+class FabricAdmin(admin.ModelAdmin):
+ list_display = ('surface',)
+ list_filter = ('surface',)
+
+
+class BasePersonModelFormSet(BaseModelFormSet):
+ def clean(self):
+ for person_dict in self.cleaned_data:
+ person = person_dict.get('id')
+ alive = person_dict.get('alive')
+ if person and alive and person.name == "Grace Hopper":
+ raise forms.ValidationError("Grace is not a Zombie")
+
+
+class PersonAdmin(admin.ModelAdmin):
+ list_display = ('name', 'gender', 'alive')
+ list_editable = ('gender', 'alive')
+ list_filter = ('gender',)
+ search_fields = ('^name',)
+ save_as = True
+
+ def get_changelist_formset(self, request, **kwargs):
+ return super(PersonAdmin, self).get_changelist_formset(request,
+ formset=BasePersonModelFormSet, **kwargs)
+
+ def queryset(self, request):
+ # Order by a field that isn't in list display, to be able to test
+ # whether ordering is preserved.
+ return super(PersonAdmin, self).queryset(request).order_by('age')
+
+
+class FooAccount(Account):
+ """A service-specific account of type Foo."""
+ servicename = u'foo'
+
+
+class BarAccount(Account):
+ """A service-specific account of type Bar."""
+ servicename = u'bar'
+
+
+class FooAccountAdmin(admin.StackedInline):
+ model = FooAccount
+ extra = 1
+
+
+class BarAccountAdmin(admin.StackedInline):
+ model = BarAccount
+ extra = 1
+
+
+class PersonaAdmin(admin.ModelAdmin):
+ inlines = (
+ FooAccountAdmin,
+ BarAccountAdmin
+ )
+
+
+class SubscriberAdmin(admin.ModelAdmin):
+ actions = ['mail_admin']
+
+ def mail_admin(self, request, selected):
+ EmailMessage(
+ 'Greetings from a ModelAdmin action',
+ 'This is the test email from a admin action',
+ 'from@example.com',
+ ['to@example.com']
+ ).send()
+
+
+def external_mail(modeladmin, request, selected):
+ EmailMessage(
+ 'Greetings from a function action',
+ 'This is the test email from a function action',
+ 'from@example.com',
+ ['to@example.com']
+ ).send()
+external_mail.short_description = 'External mail (Another awesome action)'
+
+
+def redirect_to(modeladmin, request, selected):
+ from django.http import HttpResponseRedirect
+ return HttpResponseRedirect('/some-where-else/')
+redirect_to.short_description = 'Redirect to (Awesome action)'
+
+
+class ExternalSubscriberAdmin(admin.ModelAdmin):
+ actions = [redirect_to, external_mail]
+
+
+class Podcast(Media):
+ release_date = models.DateField()
+
+ class Meta:
+ ordering = ('release_date',) # overridden in PodcastAdmin
+
+
+class PodcastAdmin(admin.ModelAdmin):
+ list_display = ('name', 'release_date')
+ list_editable = ('release_date',)
+ date_hierarchy = 'release_date'
+ ordering = ('name',)
+
+
+class VodcastAdmin(admin.ModelAdmin):
+ list_display = ('name', 'released')
+ list_editable = ('released',)
+
+ ordering = ('name',)
+
+
+class ChildInline(admin.StackedInline):
+ model = Child
+
+
+class ParentAdmin(admin.ModelAdmin):
+ model = Parent
+ inlines = [ChildInline]
+
+ list_editable = ('name',)
+
+ def save_related(self, request, form, formsets, change):
+ super(ParentAdmin, self).save_related(request, form, formsets, change)
+ first_name, last_name = form.instance.name.split()
+ for child in form.instance.child_set.all():
+ if len(child.name.split()) < 2:
+ child.name = child.name + ' ' + last_name
+ child.save()
+
+
+class EmptyModelAdmin(admin.ModelAdmin):
+ def queryset(self, request):
+ return super(EmptyModelAdmin, self).queryset(request).filter(pk__gt=1)
+
+
+class OldSubscriberAdmin(admin.ModelAdmin):
+ actions = None
+
+
+temp_storage = FileSystemStorage(tempfile.mkdtemp())
+UPLOAD_TO = os.path.join(temp_storage.location, 'test_upload')
+
+
+class PictureInline(admin.TabularInline):
+ model = Picture
+ extra = 1
+
+
+class GalleryAdmin(admin.ModelAdmin):
+ inlines = [PictureInline]
+
+
+class PictureAdmin(admin.ModelAdmin):
+ pass
+
+
+class LanguageAdmin(admin.ModelAdmin):
+ list_display = ['iso', 'shortlist', 'english_name', 'name']
+ list_editable = ['shortlist']
+
+
+class RecommendationAdmin(admin.ModelAdmin):
+ search_fields = ('=titletranslation__text', '=recommender__titletranslation__text',)
+
+
+class WidgetInline(admin.StackedInline):
+ model = Widget
+
+
+class DooHickeyInline(admin.StackedInline):
+ model = DooHickey
+
+
+class GrommetInline(admin.StackedInline):
+ model = Grommet
+
+
+class WhatsitInline(admin.StackedInline):
+ model = Whatsit
+
+
+class FancyDoodadInline(admin.StackedInline):
+ model = FancyDoodad
+
+
+class CategoryAdmin(admin.ModelAdmin):
+ list_display = ('id', 'collector', 'order')
+ list_editable = ('order',)
+
+
+class CategoryInline(admin.StackedInline):
+ model = Category
+
+
+class CollectorAdmin(admin.ModelAdmin):
+ inlines = [
+ WidgetInline, DooHickeyInline, GrommetInline, WhatsitInline,
+ FancyDoodadInline, CategoryInline
+ ]
+
+
+class LinkInline(admin.TabularInline):
+ model = Link
+ extra = 1
+
+ readonly_fields = ("posted",)
+
+
+class SubPostInline(admin.TabularInline):
+ model = PrePopulatedSubPost
+
+ prepopulated_fields = {
+ 'subslug' : ('subtitle',)
+ }
+
+ def get_readonly_fields(self, request, obj=None):
+ if obj and obj.published:
+ return ('subslug',)
+ return self.readonly_fields
+
+ def get_prepopulated_fields(self, request, obj=None):
+ if obj and obj.published:
+ return {}
+ return self.prepopulated_fields
+
+
+class PrePopulatedPostAdmin(admin.ModelAdmin):
+ list_display = ['title', 'slug']
+ prepopulated_fields = {
+ 'slug' : ('title',)
+ }
+
+ inlines = [SubPostInline]
+
+ def get_readonly_fields(self, request, obj=None):
+ if obj and obj.published:
+ return ('slug',)
+ return self.readonly_fields
+
+ def get_prepopulated_fields(self, request, obj=None):
+ if obj and obj.published:
+ return {}
+ return self.prepopulated_fields
+
+
+class PostAdmin(admin.ModelAdmin):
+ list_display = ['title', 'public']
+ readonly_fields = ('posted', 'awesomeness_level', 'coolness', 'value', lambda obj: "foo")
+
+ inlines = [
+ LinkInline
+ ]
+
+ def coolness(self, instance):
+ if instance.pk:
+ return "%d amount of cool." % instance.pk
+ else:
+ return "Unkown coolness."
+
+ def value(self, instance):
+ return 1000
+ value.short_description = 'Value in $US'
+
+
+class CustomChangeList(ChangeList):
+ def get_query_set(self, request):
+ return self.root_query_set.filter(pk=9999) # Does not exist
+
+
+class GadgetAdmin(admin.ModelAdmin):
+ def get_changelist(self, request, **kwargs):
+ return CustomChangeList
+
+
+class PizzaAdmin(admin.ModelAdmin):
+ readonly_fields = ('toppings',)
+
+
+class WorkHourAdmin(admin.ModelAdmin):
+ list_display = ('datum', 'employee')
+ list_filter = ('employee',)
+
+
+class FoodDeliveryAdmin(admin.ModelAdmin):
+ list_display=('reference', 'driver', 'restaurant')
+ list_editable = ('driver', 'restaurant')
+
+
+class PaperAdmin(admin.ModelAdmin):
+ """
+ A ModelAdmin with a custom queryset() method that uses only(), to test
+ verbose_name display in messages shown after adding Paper instances.
+ """
+
+ def queryset(self, request):
+ return super(PaperAdmin, self).queryset(request).only('title')
+
+
+class CoverLetterAdmin(admin.ModelAdmin):
+ """
+ A ModelAdmin with a custom queryset() method that uses only(), to test
+ verbose_name display in messages shown after adding CoverLetter instances.
+ Note that the CoverLetter model defines a __unicode__ method.
+ """
+
+ def queryset(self, request):
+ return super(CoverLetterAdmin, self).queryset(request).defer('date_written')
+
+
+class StoryForm(forms.ModelForm):
+ class Meta:
+ widgets = {'title': forms.HiddenInput}
+
+
+class StoryAdmin(admin.ModelAdmin):
+ list_display = ('id', 'title', 'content')
+ list_display_links = ('title',) # 'id' not in list_display_links
+ list_editable = ('content', )
+ form = StoryForm
+ ordering = ["-pk"]
+
+
+class OtherStoryAdmin(admin.ModelAdmin):
+ list_display = ('id', 'title', 'content')
+ list_display_links = ('title', 'id') # 'id' in list_display_links
+ list_editable = ('content', )
+ ordering = ["-pk"]
+
+
+class ComplexSortedPersonAdmin(admin.ModelAdmin):
+ list_display = ('name', 'age', 'is_employee', 'colored_name')
+ ordering = ('name',)
+
+ def colored_name(self, obj):
+ return '
%s' % ('ff00ff', obj.name)
+ colored_name.allow_tags = True
+ colored_name.admin_order_field = 'name'
+
+
+class AlbumAdmin(admin.ModelAdmin):
+ list_filter = ['title']
+
+
+class WorkHourAdmin(admin.ModelAdmin):
+ list_display = ('datum', 'employee')
+ list_filter = ('employee',)
+
+
+site = admin.AdminSite(name="admin")
+site.register(Article, ArticleAdmin)
+site.register(CustomArticle, CustomArticleAdmin)
+site.register(Section, save_as=True, inlines=[ArticleInline])
+site.register(ModelWithStringPrimaryKey)
+site.register(Color)
+site.register(Thing, ThingAdmin)
+site.register(Actor)
+site.register(Inquisition, InquisitionAdmin)
+site.register(Sketch, SketchAdmin)
+site.register(Person, PersonAdmin)
+site.register(Persona, PersonaAdmin)
+site.register(Subscriber, SubscriberAdmin)
+site.register(ExternalSubscriber, ExternalSubscriberAdmin)
+site.register(OldSubscriber, OldSubscriberAdmin)
+site.register(Podcast, PodcastAdmin)
+site.register(Vodcast, VodcastAdmin)
+site.register(Parent, ParentAdmin)
+site.register(EmptyModel, EmptyModelAdmin)
+site.register(Fabric, FabricAdmin)
+site.register(Gallery, GalleryAdmin)
+site.register(Picture, PictureAdmin)
+site.register(Language, LanguageAdmin)
+site.register(Recommendation, RecommendationAdmin)
+site.register(Recommender)
+site.register(Collector, CollectorAdmin)
+site.register(Category, CategoryAdmin)
+site.register(Post, PostAdmin)
+site.register(Gadget, GadgetAdmin)
+site.register(Villain)
+site.register(SuperVillain)
+site.register(Plot)
+site.register(PlotDetails)
+site.register(CyclicOne)
+site.register(CyclicTwo)
+site.register(WorkHour, WorkHourAdmin)
+site.register(Reservation)
+site.register(FoodDelivery, FoodDeliveryAdmin)
+site.register(RowLevelChangePermissionModel, RowLevelChangePermissionModelAdmin)
+site.register(Paper, PaperAdmin)
+site.register(CoverLetter, CoverLetterAdmin)
+site.register(Story, StoryAdmin)
+site.register(OtherStory, OtherStoryAdmin)
+
+# We intentionally register Promo and ChapterXtra1 but not Chapter nor ChapterXtra2.
+# That way we cover all four cases:
+# related ForeignKey object registered in admin
+# related ForeignKey object not registered in admin
+# related OneToOne object registered in admin
+# related OneToOne object not registered in admin
+# when deleting Book so as exercise all four troublesome (w.r.t escaping
+# and calling force_unicode to avoid problems on Python 2.3) paths through
+# contrib.admin.util's get_deleted_objects function.
+site.register(Book, inlines=[ChapterInline])
+site.register(Promo)
+site.register(ChapterXtra1, ChapterXtra1Admin)
+site.register(Pizza, PizzaAdmin)
+site.register(Topping)
+site.register(Album, AlbumAdmin)
+site.register(Question)
+site.register(Answer)
+site.register(PrePopulatedPost, PrePopulatedPostAdmin)
+site.register(ComplexSortedPerson, ComplexSortedPersonAdmin)
+
+# Register core models we need in our tests
+from django.contrib.auth.models import User, Group
+from django.contrib.auth.admin import UserAdmin, GroupAdmin
+site.register(User, UserAdmin)
+site.register(Group, GroupAdmin)
diff --git a/tests/regressiontests/admin_views/customadmin.py b/tests/regressiontests/admin_views/customadmin.py
index 760e93f0f8..a696e9f565 100644
--- a/tests/regressiontests/admin_views/customadmin.py
+++ b/tests/regressiontests/admin_views/customadmin.py
@@ -5,7 +5,7 @@ from django.conf.urls import patterns
from django.contrib import admin
from django.http import HttpResponse
-import models, forms
+import models, forms, admin as base_admin
class Admin2(admin.AdminSite):
login_form = forms.CustomAdminAuthenticationForm
@@ -29,8 +29,8 @@ class Admin2(admin.AdminSite):
site = Admin2(name="admin2")
-site.register(models.Article, models.ArticleAdmin)
-site.register(models.Section, inlines=[models.ArticleInline])
-site.register(models.Thing, models.ThingAdmin)
-site.register(models.Fabric, models.FabricAdmin)
-site.register(models.ChapterXtra1, models.ChapterXtra1Admin)
+site.register(models.Article, base_admin.ArticleAdmin)
+site.register(models.Section, inlines=[base_admin.ArticleInline])
+site.register(models.Thing, base_admin.ThingAdmin)
+site.register(models.Fabric, base_admin.FabricAdmin)
+site.register(models.ChapterXtra1, base_admin.ChapterXtra1Admin)
diff --git a/tests/regressiontests/admin_views/models.py b/tests/regressiontests/admin_views/models.py
index 8dc61e34e5..bb8d026e26 100644
--- a/tests/regressiontests/admin_views/models.py
+++ b/tests/regressiontests/admin_views/models.py
@@ -3,17 +3,14 @@ import datetime
import tempfile
import os
-from django.contrib import admin
from django.core.files.storage import FileSystemStorage
-from django.contrib.admin.views.main import ChangeList
-from django.core.mail import EmailMessage
from django.db import models
from django import forms
-from django.forms.models import BaseModelFormSet
from django.contrib.auth.models import User
from django.contrib.contenttypes import generic
from django.contrib.contenttypes.models import ContentType
+
class Section(models.Model):
"""
A simple section that links to articles, to test linking to related items
@@ -21,6 +18,7 @@ class Section(models.Model):
"""
name = models.CharField(max_length=100)
+
class Article(models.Model):
"""
A simple article to test admin views. Test backwards compatibility.
@@ -38,6 +36,7 @@ class Article(models.Model):
model_year.admin_order_field = 'date'
model_year.short_description = ''
+
class Book(models.Model):
"""
A simple book that has chapters.
@@ -47,6 +46,7 @@ class Book(models.Model):
def __unicode__(self):
return self.name
+
class Promo(models.Model):
name = models.CharField(max_length=100, verbose_name=u'¿Name?')
book = models.ForeignKey(Book)
@@ -54,6 +54,7 @@ class Promo(models.Model):
def __unicode__(self):
return self.name
+
class Chapter(models.Model):
title = models.CharField(max_length=100, verbose_name=u'¿Title?')
content = models.TextField()
@@ -66,6 +67,7 @@ class Chapter(models.Model):
# Use a utf-8 bytestring to ensure it works (see #11710)
verbose_name = '¿Chapter?'
+
class ChapterXtra1(models.Model):
chap = models.OneToOneField(Chapter, verbose_name=u'¿Chap?')
xtra = models.CharField(max_length=100, verbose_name=u'¿Xtra?')
@@ -73,6 +75,7 @@ class ChapterXtra1(models.Model):
def __unicode__(self):
return u'¿Xtra1: %s' % self.xtra
+
class ChapterXtra2(models.Model):
chap = models.OneToOneField(Chapter, verbose_name=u'¿Chap?')
xtra = models.CharField(max_length=100, verbose_name=u'¿Xtra?')
@@ -80,89 +83,15 @@ class ChapterXtra2(models.Model):
def __unicode__(self):
return u'¿Xtra2: %s' % self.xtra
-def callable_year(dt_value):
- return dt_value.year
-callable_year.admin_order_field = 'date'
-
-class ArticleInline(admin.TabularInline):
- model = Article
-
-class ChapterInline(admin.TabularInline):
- model = Chapter
-
-class ChapterXtra1Admin(admin.ModelAdmin):
- list_filter = ('chap',
- 'chap__title',
- 'chap__book',
- 'chap__book__name',
- 'chap__book__promo',
- 'chap__book__promo__name',)
-
-class ArticleAdmin(admin.ModelAdmin):
- list_display = ('content', 'date', callable_year, 'model_year', 'modeladmin_year')
- list_filter = ('date', 'section')
-
- def changelist_view(self, request):
- "Test that extra_context works"
- return super(ArticleAdmin, self).changelist_view(
- request, extra_context={
- 'extra_var': 'Hello!'
- }
- )
-
- def modeladmin_year(self, obj):
- return obj.date.year
- modeladmin_year.admin_order_field = 'date'
- modeladmin_year.short_description = None
-
- def delete_model(self, request, obj):
- EmailMessage(
- 'Greetings from a deleted object',
- 'I hereby inform you that some user deleted me',
- 'from@example.com',
- ['to@example.com']
- ).send()
- return super(ArticleAdmin, self).delete_model(request, obj)
-
- def save_model(self, request, obj, form, change=True):
- EmailMessage(
- 'Greetings from a created object',
- 'I hereby inform you that some user created me',
- 'from@example.com',
- ['to@example.com']
- ).send()
- return super(ArticleAdmin, self).save_model(request, obj, form, change)
class RowLevelChangePermissionModel(models.Model):
name = models.CharField(max_length=100, blank=True)
-class RowLevelChangePermissionModelAdmin(admin.ModelAdmin):
- def has_change_permission(self, request, obj=None):
- """ Only allow changing objects with even id number """
- return request.user.is_staff and (obj is not None) and (obj.id % 2 == 0)
class CustomArticle(models.Model):
content = models.TextField()
date = models.DateTimeField()
-class CustomArticleAdmin(admin.ModelAdmin):
- """
- Tests various hooks for using custom templates and contexts.
- """
- change_list_template = 'custom_admin/change_list.html'
- change_form_template = 'custom_admin/change_form.html'
- add_form_template = 'custom_admin/add_form.html'
- object_history_template = 'custom_admin/object_history.html'
- delete_confirmation_template = 'custom_admin/delete_confirmation.html'
- delete_selected_confirmation_template = 'custom_admin/delete_selected_confirmation.html'
-
- def changelist_view(self, request):
- "Test that extra_context works"
- return super(CustomArticleAdmin, self).changelist_view(
- request, extra_context={
- 'extra_var': 'Hello!'
- }
- )
class ModelWithStringPrimaryKey(models.Model):
id = models.CharField(max_length=255, primary_key=True)
@@ -170,20 +99,20 @@ class ModelWithStringPrimaryKey(models.Model):
def __unicode__(self):
return self.id
+
class Color(models.Model):
value = models.CharField(max_length=10)
warm = models.BooleanField()
def __unicode__(self):
return self.value
+
class Thing(models.Model):
title = models.CharField(max_length=20)
color = models.ForeignKey(Color, limit_choices_to={'warm': True})
def __unicode__(self):
return self.title
-class ThingAdmin(admin.ModelAdmin):
- list_filter = ('color__warm', 'color__value')
class Actor(models.Model):
name = models.CharField(max_length=50)
@@ -191,6 +120,7 @@ class Actor(models.Model):
def __unicode__(self):
return self.name
+
class Inquisition(models.Model):
expected = models.BooleanField()
leader = models.ForeignKey(Actor)
@@ -199,8 +129,6 @@ class Inquisition(models.Model):
def __unicode__(self):
return u"by %s from %s" % (self.leader, self.country)
-class InquisitionAdmin(admin.ModelAdmin):
- list_display = ('leader', 'country', 'expected')
class Sketch(models.Model):
title = models.CharField(max_length=100)
@@ -212,8 +140,6 @@ class Sketch(models.Model):
def __unicode__(self):
return self.title
-class SketchAdmin(admin.ModelAdmin):
- raw_id_fields = ('inquisition',)
class Fabric(models.Model):
NG_CHOICES = (
@@ -226,9 +152,6 @@ class Fabric(models.Model):
)
surface = models.CharField(max_length=20, choices=NG_CHOICES)
-class FabricAdmin(admin.ModelAdmin):
- list_display = ('surface',)
- list_filter = ('surface',)
class Person(models.Model):
GENDER_CHOICES = (
@@ -243,30 +166,6 @@ class Person(models.Model):
def __unicode__(self):
return self.name
-class BasePersonModelFormSet(BaseModelFormSet):
- def clean(self):
- for person_dict in self.cleaned_data:
- person = person_dict.get('id')
- alive = person_dict.get('alive')
- if person and alive and person.name == "Grace Hopper":
- raise forms.ValidationError("Grace is not a Zombie")
-
-class PersonAdmin(admin.ModelAdmin):
- list_display = ('name', 'gender', 'alive')
- list_editable = ('gender', 'alive')
- list_filter = ('gender',)
- search_fields = ('^name',)
- save_as = True
-
- def get_changelist_formset(self, request, **kwargs):
- return super(PersonAdmin, self).get_changelist_formset(request,
- formset=BasePersonModelFormSet, **kwargs)
-
- def queryset(self, request):
- # Order by a field that isn't in list display, to be able to test
- # whether ordering is preserved.
- return super(PersonAdmin, self).queryset(request).order_by('age')
-
class Persona(models.Model):
"""
@@ -277,6 +176,7 @@ class Persona(models.Model):
def __unicode__(self):
return self.name
+
class Account(models.Model):
"""
A simple, generic account encapsulating the information shared by all
@@ -289,27 +189,16 @@ class Account(models.Model):
def __unicode__(self):
return "%s: %s" % (self.servicename, self.username)
+
class FooAccount(Account):
"""A service-specific account of type Foo."""
servicename = u'foo'
+
class BarAccount(Account):
"""A service-specific account of type Bar."""
servicename = u'bar'
-class FooAccountAdmin(admin.StackedInline):
- model = FooAccount
- extra = 1
-
-class BarAccountAdmin(admin.StackedInline):
- model = BarAccount
- extra = 1
-
-class PersonaAdmin(admin.ModelAdmin):
- inlines = (
- FooAccountAdmin,
- BarAccountAdmin
- )
class Subscriber(models.Model):
name = models.CharField(blank=False, max_length=80)
@@ -318,120 +207,58 @@ class Subscriber(models.Model):
def __unicode__(self):
return "%s (%s)" % (self.name, self.email)
-class SubscriberAdmin(admin.ModelAdmin):
- actions = ['mail_admin']
-
- def mail_admin(self, request, selected):
- EmailMessage(
- 'Greetings from a ModelAdmin action',
- 'This is the test email from a admin action',
- 'from@example.com',
- ['to@example.com']
- ).send()
class ExternalSubscriber(Subscriber):
pass
+
class OldSubscriber(Subscriber):
pass
-def external_mail(modeladmin, request, selected):
- EmailMessage(
- 'Greetings from a function action',
- 'This is the test email from a function action',
- 'from@example.com',
- ['to@example.com']
- ).send()
-external_mail.short_description = 'External mail (Another awesome action)'
-
-def redirect_to(modeladmin, request, selected):
- from django.http import HttpResponseRedirect
- return HttpResponseRedirect('/some-where-else/')
-redirect_to.short_description = 'Redirect to (Awesome action)'
-
-class ExternalSubscriberAdmin(admin.ModelAdmin):
- actions = [redirect_to, external_mail]
class Media(models.Model):
name = models.CharField(max_length=60)
+
class Podcast(Media):
release_date = models.DateField()
class Meta:
ordering = ('release_date',) # overridden in PodcastAdmin
-class PodcastAdmin(admin.ModelAdmin):
- list_display = ('name', 'release_date')
- list_editable = ('release_date',)
- date_hierarchy = 'release_date'
- ordering = ('name',)
class Vodcast(Media):
media = models.OneToOneField(Media, primary_key=True, parent_link=True)
released = models.BooleanField(default=False)
-class VodcastAdmin(admin.ModelAdmin):
- list_display = ('name', 'released')
- list_editable = ('released',)
-
- ordering = ('name',)
class Parent(models.Model):
name = models.CharField(max_length=128)
+
class Child(models.Model):
parent = models.ForeignKey(Parent, editable=False)
name = models.CharField(max_length=30, blank=True)
-class ChildInline(admin.StackedInline):
- model = Child
-
-class ParentAdmin(admin.ModelAdmin):
- model = Parent
- inlines = [ChildInline]
-
- list_editable = ('name',)
-
- def save_related(self, request, form, formsets, change):
- super(ParentAdmin, self).save_related(request, form, formsets, change)
- first_name, last_name = form.instance.name.split()
- for child in form.instance.child_set.all():
- if len(child.name.split()) < 2:
- child.name = child.name + ' ' + last_name
- child.save()
class EmptyModel(models.Model):
def __unicode__(self):
return "Primary key = %s" % self.id
-class EmptyModelAdmin(admin.ModelAdmin):
- def queryset(self, request):
- return super(EmptyModelAdmin, self).queryset(request).filter(pk__gt=1)
-
-class OldSubscriberAdmin(admin.ModelAdmin):
- actions = None
temp_storage = FileSystemStorage(tempfile.mkdtemp())
UPLOAD_TO = os.path.join(temp_storage.location, 'test_upload')
+
class Gallery(models.Model):
name = models.CharField(max_length=100)
+
class Picture(models.Model):
name = models.CharField(max_length=100)
image = models.FileField(storage=temp_storage, upload_to='test_upload')
gallery = models.ForeignKey(Gallery, related_name="pictures")
-class PictureInline(admin.TabularInline):
- model = Picture
- extra = 1
-
-class GalleryAdmin(admin.ModelAdmin):
- inlines = [PictureInline]
-
-class PictureAdmin(admin.ModelAdmin):
- pass
class Language(models.Model):
iso = models.CharField(max_length=5, primary_key=True)
@@ -442,70 +269,60 @@ class Language(models.Model):
class Meta:
ordering = ('iso',)
-class LanguageAdmin(admin.ModelAdmin):
- list_display = ['iso', 'shortlist', 'english_name', 'name']
- list_editable = ['shortlist']
# a base class for Recommender and Recommendation
class Title(models.Model):
pass
+
class TitleTranslation(models.Model):
title = models.ForeignKey(Title)
text = models.CharField(max_length=100)
+
class Recommender(Title):
pass
+
class Recommendation(Title):
recommender = models.ForeignKey(Recommender)
-class RecommendationAdmin(admin.ModelAdmin):
- search_fields = ('=titletranslation__text', '=recommender__titletranslation__text',)
class Collector(models.Model):
name = models.CharField(max_length=100)
+
class Widget(models.Model):
owner = models.ForeignKey(Collector)
name = models.CharField(max_length=100)
+
class DooHickey(models.Model):
code = models.CharField(max_length=10, primary_key=True)
owner = models.ForeignKey(Collector)
name = models.CharField(max_length=100)
+
class Grommet(models.Model):
code = models.AutoField(primary_key=True)
owner = models.ForeignKey(Collector)
name = models.CharField(max_length=100)
+
class Whatsit(models.Model):
index = models.IntegerField(primary_key=True)
owner = models.ForeignKey(Collector)
name = models.CharField(max_length=100)
+
class Doodad(models.Model):
name = models.CharField(max_length=100)
+
class FancyDoodad(Doodad):
owner = models.ForeignKey(Collector)
expensive = models.BooleanField(default=True)
-class WidgetInline(admin.StackedInline):
- model = Widget
-
-class DooHickeyInline(admin.StackedInline):
- model = DooHickey
-
-class GrommetInline(admin.StackedInline):
- model = Grommet
-
-class WhatsitInline(admin.StackedInline):
- model = Whatsit
-
-class FancyDoodadInline(admin.StackedInline):
- model = FancyDoodad
class Category(models.Model):
collector = models.ForeignKey(Collector)
@@ -517,18 +334,6 @@ class Category(models.Model):
def __unicode__(self):
return u'%s:o%s' % (self.id, self.order)
-class CategoryAdmin(admin.ModelAdmin):
- list_display = ('id', 'collector', 'order')
- list_editable = ('order',)
-
-class CategoryInline(admin.StackedInline):
- model = Category
-
-class CollectorAdmin(admin.ModelAdmin):
- inlines = [
- WidgetInline, DooHickeyInline, GrommetInline, WhatsitInline,
- FancyDoodadInline, CategoryInline
- ]
class Link(models.Model):
posted = models.DateField(
@@ -538,57 +343,17 @@ class Link(models.Model):
post = models.ForeignKey("Post")
-class LinkInline(admin.TabularInline):
- model = Link
- extra = 1
-
- readonly_fields = ("posted",)
-
-
class PrePopulatedPost(models.Model):
title = models.CharField(max_length=100)
published = models.BooleanField()
slug = models.SlugField()
+
class PrePopulatedSubPost(models.Model):
post = models.ForeignKey(PrePopulatedPost)
subtitle = models.CharField(max_length=100)
subslug = models.SlugField()
-class SubPostInline(admin.TabularInline):
- model = PrePopulatedSubPost
-
- prepopulated_fields = {
- 'subslug' : ('subtitle',)
- }
-
- def get_readonly_fields(self, request, obj=None):
- if obj and obj.published:
- return ('subslug',)
- return self.readonly_fields
-
- def get_prepopulated_fields(self, request, obj=None):
- if obj and obj.published:
- return {}
- return self.prepopulated_fields
-
-class PrePopulatedPostAdmin(admin.ModelAdmin):
- list_display = ['title', 'slug']
- prepopulated_fields = {
- 'slug' : ('title',)
- }
-
- inlines = [SubPostInline]
-
- def get_readonly_fields(self, request, obj=None):
- if obj and obj.published:
- return ('slug',)
- return self.readonly_fields
-
- def get_prepopulated_fields(self, request, obj=None):
- if obj and obj.published:
- return {}
- return self.prepopulated_fields
class Post(models.Model):
title = models.CharField(max_length=100, help_text="Some help text for the title (with unicode ŠĐĆŽćžšđ)")
@@ -602,23 +367,6 @@ class Post(models.Model):
def awesomeness_level(self):
return "Very awesome."
-class PostAdmin(admin.ModelAdmin):
- list_display = ['title', 'public']
- readonly_fields = ('posted', 'awesomeness_level', 'coolness', 'value', lambda obj: "foo")
-
- inlines = [
- LinkInline
- ]
-
- def coolness(self, instance):
- if instance.pk:
- return "%d amount of cool." % instance.pk
- else:
- return "Unkown coolness."
-
- def value(self, instance):
- return 1000
- value.short_description = 'Value in $US'
class Gadget(models.Model):
name = models.CharField(max_length=100)
@@ -626,13 +374,6 @@ class Gadget(models.Model):
def __unicode__(self):
return self.name
-class CustomChangeList(ChangeList):
- def get_query_set(self, request):
- return self.root_query_set.filter(pk=9999) # Does not exist
-
-class GadgetAdmin(admin.ModelAdmin):
- def get_changelist(self, request, **kwargs):
- return CustomChangeList
class Villain(models.Model):
name = models.CharField(max_length=100)
@@ -640,9 +381,11 @@ class Villain(models.Model):
def __unicode__(self):
return self.name
+
class SuperVillain(Villain):
pass
+
class FunkyTag(models.Model):
"Because we all know there's only one real use case for GFKs."
name = models.CharField(max_length=25)
@@ -653,6 +396,7 @@ class FunkyTag(models.Model):
def __unicode__(self):
return self.name
+
class Plot(models.Model):
name = models.CharField(max_length=100)
team_leader = models.ForeignKey(Villain, related_name='lead_plots')
@@ -662,6 +406,7 @@ class Plot(models.Model):
def __unicode__(self):
return self.name
+
class PlotDetails(models.Model):
details = models.CharField(max_length=100)
plot = models.OneToOneField(Plot)
@@ -669,6 +414,7 @@ class PlotDetails(models.Model):
def __unicode__(self):
return self.details
+
class SecretHideout(models.Model):
""" Secret! Not registered with the admin! """
location = models.CharField(max_length=100)
@@ -677,6 +423,7 @@ class SecretHideout(models.Model):
def __unicode__(self):
return self.location
+
class SuperSecretHideout(models.Model):
""" Secret! Not registered with the admin! """
location = models.CharField(max_length=100)
@@ -685,6 +432,7 @@ class SuperSecretHideout(models.Model):
def __unicode__(self):
return self.location
+
class CyclicOne(models.Model):
name = models.CharField(max_length=25)
two = models.ForeignKey('CyclicTwo')
@@ -692,6 +440,7 @@ class CyclicOne(models.Model):
def __unicode__(self):
return self.name
+
class CyclicTwo(models.Model):
name = models.CharField(max_length=25)
one = models.ForeignKey(CyclicOne)
@@ -699,37 +448,34 @@ class CyclicTwo(models.Model):
def __unicode__(self):
return self.name
+
class Topping(models.Model):
name = models.CharField(max_length=20)
+
class Pizza(models.Model):
name = models.CharField(max_length=20)
toppings = models.ManyToManyField('Topping')
-class PizzaAdmin(admin.ModelAdmin):
- readonly_fields = ('toppings',)
class Album(models.Model):
owner = models.ForeignKey(User)
title = models.CharField(max_length=30)
-class AlbumAdmin(admin.ModelAdmin):
- list_filter = ['title']
class Employee(Person):
code = models.CharField(max_length=20)
+
class WorkHour(models.Model):
datum = models.DateField()
employee = models.ForeignKey(Employee)
-class WorkHourAdmin(admin.ModelAdmin):
- list_display = ('datum', 'employee')
- list_filter = ('employee',)
class Question(models.Model):
question = models.CharField(max_length=20)
+
class Answer(models.Model):
question = models.ForeignKey(Question, on_delete=models.PROTECT)
answer = models.CharField(max_length=20)
@@ -737,6 +483,7 @@ class Answer(models.Model):
def __unicode__(self):
return self.answer
+
class Reservation(models.Model):
start_date = models.DateTimeField()
price = models.IntegerField()
@@ -753,6 +500,7 @@ RESTAURANT_CHOICES = (
(u'pizza', u'Pizza Mama'),
)
+
class FoodDelivery(models.Model):
reference = models.CharField(max_length=100)
driver = models.CharField(max_length=100, choices=DRIVER_CHOICES, blank=True)
@@ -761,14 +509,12 @@ class FoodDelivery(models.Model):
class Meta:
unique_together = (("driver", "restaurant"),)
-class FoodDeliveryAdmin(admin.ModelAdmin):
- list_display=('reference', 'driver', 'restaurant')
- list_editable = ('driver', 'restaurant')
class Paper(models.Model):
title = models.CharField(max_length=30)
author = models.CharField(max_length=30, blank=True, null=True)
+
class CoverLetter(models.Model):
author = models.CharField(max_length=30)
date_written = models.DateField(null=True, blank=True)
@@ -776,123 +522,19 @@ class CoverLetter(models.Model):
def __unicode__(self):
return self.author
-class PaperAdmin(admin.ModelAdmin):
- """
- A ModelAdin with a custom queryset() method that uses only(), to test
- verbose_name display in messages shown after adding Paper instances.
- """
-
- def queryset(self, request):
- return super(PaperAdmin, self).queryset(request).only('title')
-
-class CoverLetterAdmin(admin.ModelAdmin):
- """
- A ModelAdin with a custom queryset() method that uses only(), to test
- verbose_name display in messages shown after adding CoverLetter instances.
- Note that the CoverLetter model defines a __unicode__ method.
- """
-
- def queryset(self, request):
- return super(CoverLetterAdmin, self).queryset(request).defer('date_written')
class Story(models.Model):
title = models.CharField(max_length=100)
content = models.TextField()
-class StoryForm(forms.ModelForm):
- class Meta:
- widgets = {'title': forms.HiddenInput}
-
-class StoryAdmin(admin.ModelAdmin):
- list_display = ('id', 'title', 'content')
- list_display_links = ('title',) # 'id' not in list_display_links
- list_editable = ('content', )
- form = StoryForm
- ordering = ["-pk"]
class OtherStory(models.Model):
title = models.CharField(max_length=100)
content = models.TextField()
-class OtherStoryAdmin(admin.ModelAdmin):
- list_display = ('id', 'title', 'content')
- list_display_links = ('title', 'id') # 'id' in list_display_links
- list_editable = ('content', )
- ordering = ["-pk"]
class ComplexSortedPerson(models.Model):
name = models.CharField(max_length=100)
age = models.PositiveIntegerField()
is_employee = models.NullBooleanField()
-class ComplexSortedPersonAdmin(admin.ModelAdmin):
- list_display = ('name', 'age', 'is_employee', 'colored_name')
- ordering = ('name',)
-
- def colored_name(self, obj):
- return '
%s' % ('ff00ff', obj.name)
- colored_name.allow_tags = True
- colored_name.admin_order_field = 'name'
-
-admin.site.register(Article, ArticleAdmin)
-admin.site.register(CustomArticle, CustomArticleAdmin)
-admin.site.register(Section, save_as=True, inlines=[ArticleInline])
-admin.site.register(ModelWithStringPrimaryKey)
-admin.site.register(Color)
-admin.site.register(Thing, ThingAdmin)
-admin.site.register(Actor)
-admin.site.register(Inquisition, InquisitionAdmin)
-admin.site.register(Sketch, SketchAdmin)
-admin.site.register(Person, PersonAdmin)
-admin.site.register(Persona, PersonaAdmin)
-admin.site.register(Subscriber, SubscriberAdmin)
-admin.site.register(ExternalSubscriber, ExternalSubscriberAdmin)
-admin.site.register(OldSubscriber, OldSubscriberAdmin)
-admin.site.register(Podcast, PodcastAdmin)
-admin.site.register(Vodcast, VodcastAdmin)
-admin.site.register(Parent, ParentAdmin)
-admin.site.register(EmptyModel, EmptyModelAdmin)
-admin.site.register(Fabric, FabricAdmin)
-admin.site.register(Gallery, GalleryAdmin)
-admin.site.register(Picture, PictureAdmin)
-admin.site.register(Language, LanguageAdmin)
-admin.site.register(Recommendation, RecommendationAdmin)
-admin.site.register(Recommender)
-admin.site.register(Collector, CollectorAdmin)
-admin.site.register(Category, CategoryAdmin)
-admin.site.register(Post, PostAdmin)
-admin.site.register(Gadget, GadgetAdmin)
-admin.site.register(Villain)
-admin.site.register(SuperVillain)
-admin.site.register(Plot)
-admin.site.register(PlotDetails)
-admin.site.register(CyclicOne)
-admin.site.register(CyclicTwo)
-admin.site.register(WorkHour, WorkHourAdmin)
-admin.site.register(Reservation)
-admin.site.register(FoodDelivery, FoodDeliveryAdmin)
-admin.site.register(RowLevelChangePermissionModel, RowLevelChangePermissionModelAdmin)
-admin.site.register(Paper, PaperAdmin)
-admin.site.register(CoverLetter, CoverLetterAdmin)
-admin.site.register(Story, StoryAdmin)
-admin.site.register(OtherStory, OtherStoryAdmin)
-
-# We intentionally register Promo and ChapterXtra1 but not Chapter nor ChapterXtra2.
-# That way we cover all four cases:
-# related ForeignKey object registered in admin
-# related ForeignKey object not registered in admin
-# related OneToOne object registered in admin
-# related OneToOne object not registered in admin
-# when deleting Book so as exercise all four troublesome (w.r.t escaping
-# and calling force_unicode to avoid problems on Python 2.3) paths through
-# contrib.admin.util's get_deleted_objects function.
-admin.site.register(Book, inlines=[ChapterInline])
-admin.site.register(Promo)
-admin.site.register(ChapterXtra1, ChapterXtra1Admin)
-admin.site.register(Pizza, PizzaAdmin)
-admin.site.register(Topping)
-admin.site.register(Album, AlbumAdmin)
-admin.site.register(Question)
-admin.site.register(Answer)
-admin.site.register(PrePopulatedPost, PrePopulatedPostAdmin)
-admin.site.register(ComplexSortedPerson, ComplexSortedPersonAdmin)
diff --git a/tests/regressiontests/admin_views/tests.py b/tests/regressiontests/admin_views/tests.py
index 22b65a6cb8..668c71076e 100644
--- a/tests/regressiontests/admin_views/tests.py
+++ b/tests/regressiontests/admin_views/tests.py
@@ -32,7 +32,7 @@ from django.utils import unittest
# local test models
from models import (Article, BarAccount, CustomArticle, EmptyModel,
- FooAccount, Gallery, PersonAdmin, ModelWithStringPrimaryKey,
+ FooAccount, Gallery, ModelWithStringPrimaryKey,
Person, Persona, Picture, Podcast, Section, Subscriber, Vodcast,
Language, Collector, Widget, Grommet, DooHickey, FancyDoodad, Whatsit,
Category, Post, Plot, FunkyTag, Chapter, Book, Promo, WorkHour, Employee,
@@ -50,6 +50,8 @@ class AdminViewBasicTest(TestCase):
# this test case and changing urlbit.
urlbit = 'admin'
+ urls = "regressiontests.admin_views.urls"
+
def setUp(self):
self.old_USE_I18N = settings.USE_I18N
self.old_USE_L10N = settings.USE_L10N
@@ -301,7 +303,7 @@ class AdminViewBasicTest(TestCase):
response.content.index(link % l1.pk) < response.content.index(link % l2.pk)
)
- def testChangeListSortingModelAdmin(self):
+ def testChangeListSortingOverrideModelAdmin(self):
# Test ordering on Model Admin is respected, and overrides Model Meta
dt = datetime.datetime.now()
p1 = Podcast.objects.create(name="A", release_date=dt)
@@ -542,6 +544,8 @@ class AdminViewBasicTest(TestCase):
self.fail("Filters should be allowed if they are defined on a ForeignKey pointing to this model")
class AdminJavaScriptTest(AdminViewBasicTest):
+ urls = "regressiontests.admin_views.urls"
+
def testSingleWidgetFirsFieldFocus(self):
"""
JavaScript-assisted auto-focus on first field.
@@ -565,6 +569,7 @@ class AdminJavaScriptTest(AdminViewBasicTest):
class SaveAsTests(TestCase):
+ urls = "regressiontests.admin_views.urls"
fixtures = ['admin-views-users.xml','admin-views-person.xml']
def setUp(self):
@@ -593,6 +598,7 @@ class SaveAsTests(TestCase):
self.assertEqual(response.context['form_url'], '../add/')
class CustomModelAdminTest(AdminViewBasicTest):
+ urls = "regressiontests.admin_views.urls"
urlbit = "admin2"
def testCustomAdminSiteLoginForm(self):
@@ -654,6 +660,7 @@ def get_perm(Model, perm):
class AdminViewPermissionsTest(TestCase):
"""Tests for Admin Views Permissions."""
+ urls = "regressiontests.admin_views.urls"
fixtures = ['admin-views-users.xml']
def setUp(self):
@@ -1055,6 +1062,7 @@ class AdminViewPermissionsTest(TestCase):
class AdminViewDeletedObjectsTest(TestCase):
+ urls = "regressiontests.admin_views.urls"
fixtures = ['admin-views-users.xml', 'deleted-objects.xml']
def setUp(self):
@@ -1170,6 +1178,7 @@ class AdminViewDeletedObjectsTest(TestCase):
self.assertContains(response, should_contain)
class AdminViewStringPrimaryKeyTest(TestCase):
+ urls = "regressiontests.admin_views.urls"
fixtures = ['admin-views-users.xml', 'string-primary-key.xml']
def __init__(self, *args):
@@ -1261,6 +1270,7 @@ class AdminViewStringPrimaryKeyTest(TestCase):
class SecureViewTests(TestCase):
+ urls = "regressiontests.admin_views.urls"
fixtures = ['admin-views-users.xml']
def setUp(self):
@@ -1418,6 +1428,7 @@ class SecureViewTests(TestCase):
self.assertEqual(response['Location'], 'http://example.com/users/super/')
class AdminViewUnicodeTest(TestCase):
+ urls = "regressiontests.admin_views.urls"
fixtures = ['admin-views-unicode.xml']
def setUp(self):
@@ -1471,6 +1482,7 @@ class AdminViewUnicodeTest(TestCase):
class AdminViewListEditable(TestCase):
+ urls = "regressiontests.admin_views.urls"
fixtures = ['admin-views-users.xml', 'admin-views-person.xml']
def setUp(self):
@@ -1827,6 +1839,7 @@ class AdminViewListEditable(TestCase):
class AdminSearchTest(TestCase):
+ urls = "regressiontests.admin_views.urls"
fixtures = ['admin-views-users', 'multiple-child-classes',
'admin-views-person']
@@ -1873,6 +1886,7 @@ class AdminSearchTest(TestCase):
class AdminInheritedInlinesTest(TestCase):
+ urls = "regressiontests.admin_views.urls"
fixtures = ['admin-views-users.xml',]
def setUp(self):
@@ -1958,6 +1972,7 @@ class AdminInheritedInlinesTest(TestCase):
self.assertEqual(Persona.objects.all()[0].accounts.count(), 2)
class AdminActionsTest(TestCase):
+ urls = "regressiontests.admin_views.urls"
fixtures = ['admin-views-users.xml', 'admin-views-actions.xml']
def setUp(self):
@@ -2179,6 +2194,7 @@ class AdminActionsTest(TestCase):
class TestCustomChangeList(TestCase):
+ urls = "regressiontests.admin_views.urls"
fixtures = ['admin-views-users.xml']
urlbit = 'admin'
@@ -2206,6 +2222,7 @@ class TestCustomChangeList(TestCase):
class TestInlineNotEditable(TestCase):
+ urls = "regressiontests.admin_views.urls"
fixtures = ['admin-views-users.xml']
def setUp(self):
@@ -2223,6 +2240,7 @@ class TestInlineNotEditable(TestCase):
self.assertEqual(response.status_code, 200)
class AdminCustomQuerysetTest(TestCase):
+ urls = "regressiontests.admin_views.urls"
fixtures = ['admin-views-users.xml']
def setUp(self):
@@ -2277,6 +2295,7 @@ class AdminCustomQuerysetTest(TestCase):
self.assertContains(response, '
The cover letter "John Doe II" was changed successfully.')
class AdminInlineFileUploadTest(TestCase):
+ urls = "regressiontests.admin_views.urls"
fixtures = ['admin-views-users.xml', 'admin-views-actions.xml']
urlbit = 'admin'
@@ -2322,6 +2341,7 @@ class AdminInlineFileUploadTest(TestCase):
class AdminInlineTests(TestCase):
+ urls = "regressiontests.admin_views.urls"
fixtures = ['admin-views-users.xml']
def setUp(self):
@@ -2639,6 +2659,7 @@ class AdminInlineTests(TestCase):
class NeverCacheTests(TestCase):
+ urls = "regressiontests.admin_views.urls"
fixtures = ['admin-views-users.xml', 'admin-views-colors.xml', 'admin-views-fabrics.xml']
def setUp(self):
@@ -2711,6 +2732,7 @@ class NeverCacheTests(TestCase):
class PrePopulatedTest(TestCase):
+ urls = "regressiontests.admin_views.urls"
fixtures = ['admin-views-users.xml']
def setUp(self):
@@ -2735,6 +2757,7 @@ class PrePopulatedTest(TestCase):
self.assertNotContains(response, "id: '#id_prepopulatedsubpost_set-0-subslug',")
class ReadonlyTest(TestCase):
+ urls = "regressiontests.admin_views.urls"
fixtures = ['admin-views-users.xml']
def setUp(self):
@@ -2802,6 +2825,7 @@ class ReadonlyTest(TestCase):
class RawIdFieldsTest(TestCase):
+ urls = "regressiontests.admin_views.urls"
fixtures = ['admin-views-users.xml']
def setUp(self):
@@ -2837,6 +2861,7 @@ class UserAdminTest(TestCase):
"""
Tests user CRUD functionality.
"""
+ urls = "regressiontests.admin_views.urls"
fixtures = ['admin-views-users.xml']
def setUp(self):
@@ -2928,6 +2953,7 @@ class GroupAdminTest(TestCase):
"""
Tests group CRUD functionality.
"""
+ urls = "regressiontests.admin_views.urls"
fixtures = ['admin-views-users.xml']
def setUp(self):
@@ -2961,6 +2987,7 @@ except ImportError:
#@unittest.skipUnless(docutils, "no docutils installed.")
class AdminDocsTest(TestCase):
+ urls = "regressiontests.admin_views.urls"
fixtures = ['admin-views-users.xml']
def setUp(self):
@@ -3003,6 +3030,7 @@ class AdminDocsTest(TestCase):
AdminDocsTest = unittest.skipUnless(docutils, "no docutils installed.")(AdminDocsTest)
class ValidXHTMLTests(TestCase):
+ urls = "regressiontests.admin_views.urls"
fixtures = ['admin-views-users.xml']
urlbit = 'admin'
@@ -3033,6 +3061,7 @@ class ValidXHTMLTests(TestCase):
class DateHierarchyTests(TestCase):
+ urls = "regressiontests.admin_views.urls"
fixtures = ['admin-views-users.xml']
def setUp(self):
@@ -3162,6 +3191,7 @@ class AdminCustomSaveRelatedTests(TestCase):
Ensure that one can easily customize the way related objects are saved.
Refs #16115.
"""
+ urls = "regressiontests.admin_views.urls"
fixtures = ['admin-views-users.xml']
def setUp(self):
diff --git a/tests/regressiontests/admin_views/urls.py b/tests/regressiontests/admin_views/urls.py
index 7320a3c7c8..e436665d6d 100644
--- a/tests/regressiontests/admin_views/urls.py
+++ b/tests/regressiontests/admin_views/urls.py
@@ -1,11 +1,11 @@
from django.conf.urls import patterns, include
-from django.contrib import admin
import views
import customadmin
+import admin
urlpatterns = patterns('',
- (r'^admin/doc/', include('django.contrib.admindocs.urls')),
- (r'^admin/secure-view/$', views.secure_view),
- (r'^admin/', include(admin.site.urls)),
- (r'^admin2/', include(customadmin.site.urls)),
+ (r'^test_admin/admin/doc/', include('django.contrib.admindocs.urls')),
+ (r'^test_admin/admin/secure-view/$', views.secure_view),
+ (r'^test_admin/admin/', include(admin.site.urls)),
+ (r'^test_admin/admin2/', include(customadmin.site.urls)),
)
diff --git a/tests/regressiontests/cache/tests.py b/tests/regressiontests/cache/tests.py
index d3070305cb..07bcab7fbc 100644
--- a/tests/regressiontests/cache/tests.py
+++ b/tests/regressiontests/cache/tests.py
@@ -1591,6 +1591,8 @@ TestWithTemplateResponse = override_settings(
class TestEtagWithAdmin(TestCase):
# See https://code.djangoproject.com/ticket/16003
+ urls = "regressiontests.admin_views.urls"
+
def test_admin(self):
with self.settings(USE_ETAGS=False):
response = self.client.get('/test_admin/admin/')
diff --git a/tests/regressiontests/generic_inline_admin/admin.py b/tests/regressiontests/generic_inline_admin/admin.py
new file mode 100644
index 0000000000..87224edab7
--- /dev/null
+++ b/tests/regressiontests/generic_inline_admin/admin.py
@@ -0,0 +1,44 @@
+from django.contrib import admin
+from django.contrib.contenttypes import generic
+
+from models import (Media, PhoneNumber, Episode, EpisodeExtra, Contact,
+ Category, EpisodePermanent, EpisodeMaxNum)
+
+site = admin.AdminSite(name="admin")
+
+class MediaInline(generic.GenericTabularInline):
+ model = Media
+
+
+class EpisodeAdmin(admin.ModelAdmin):
+ inlines = [
+ MediaInline,
+ ]
+
+
+class MediaExtraInline(generic.GenericTabularInline):
+ model = Media
+ extra = 0
+
+
+class MediaMaxNumInline(generic.GenericTabularInline):
+ model = Media
+ extra = 5
+ max_num = 2
+
+
+class PhoneNumberInline(generic.GenericTabularInline):
+ model = PhoneNumber
+
+
+class MediaPermanentInline(generic.GenericTabularInline):
+ model = Media
+ can_delete = False
+
+
+site.register(Episode, EpisodeAdmin)
+site.register(EpisodeExtra, inlines=[MediaExtraInline])
+site.register(EpisodeMaxNum, inlines=[MediaMaxNumInline])
+site.register(Contact, inlines=[PhoneNumberInline])
+site.register(Category)
+site.register(EpisodePermanent, inlines=[MediaPermanentInline])
diff --git a/tests/regressiontests/generic_inline_admin/models.py b/tests/regressiontests/generic_inline_admin/models.py
index 32ecd3b889..e78f110416 100644
--- a/tests/regressiontests/generic_inline_admin/models.py
+++ b/tests/regressiontests/generic_inline_admin/models.py
@@ -1,13 +1,14 @@
from django.db import models
-from django.contrib import admin
from django.contrib.contenttypes import generic
from django.contrib.contenttypes.models import ContentType
+
class Episode(models.Model):
name = models.CharField(max_length=100)
length = models.CharField(max_length=100, blank=True)
author = models.CharField(max_length=100, blank=True)
+
class Media(models.Model):
"""
Media that can associated to any object.
@@ -22,15 +23,6 @@ class Media(models.Model):
def __unicode__(self):
return self.url
-class MediaInline(generic.GenericTabularInline):
- model = Media
-
-class EpisodeAdmin(admin.ModelAdmin):
- inlines = [
- MediaInline,
- ]
-admin.site.register(Episode, EpisodeAdmin)
-
#
# These models let us test the different GenericInline settings at
# different urls in the admin site.
@@ -43,34 +35,21 @@ admin.site.register(Episode, EpisodeAdmin)
class EpisodeExtra(Episode):
pass
-class MediaExtraInline(generic.GenericTabularInline):
- model = Media
- extra = 0
-
-admin.site.register(EpisodeExtra, inlines=[MediaExtraInline])
#
# Generic inline with extra and max_num
#
-
class EpisodeMaxNum(Episode):
pass
-class MediaMaxNumInline(generic.GenericTabularInline):
- model = Media
- extra = 5
- max_num = 2
-
-admin.site.register(EpisodeMaxNum, inlines=[MediaMaxNumInline])
-
#
# Generic inline with unique_together
#
-
class Category(models.Model):
name = models.CharField(max_length=50)
+
class PhoneNumber(models.Model):
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
@@ -81,25 +60,15 @@ class PhoneNumber(models.Model):
class Meta:
unique_together = (('content_type', 'object_id', 'phone_number',),)
+
class Contact(models.Model):
name = models.CharField(max_length=50)
phone_numbers = generic.GenericRelation(PhoneNumber)
-class PhoneNumberInline(generic.GenericTabularInline):
- model = PhoneNumber
-
-admin.site.register(Contact, inlines=[PhoneNumberInline])
-admin.site.register(Category)
-
#
# Generic inline with can_delete=False
#
-
class EpisodePermanent(Episode):
pass
-class MediaPermanentInline(generic.GenericTabularInline):
- model = Media
- can_delete = False
-admin.site.register(EpisodePermanent, inlines=[MediaPermanentInline])
diff --git a/tests/regressiontests/generic_inline_admin/tests.py b/tests/regressiontests/generic_inline_admin/tests.py
index da59922fe5..858d6a5f3b 100644
--- a/tests/regressiontests/generic_inline_admin/tests.py
+++ b/tests/regressiontests/generic_inline_admin/tests.py
@@ -10,10 +10,12 @@ from django.test import TestCase
# local test models
from models import (Episode, EpisodeExtra, EpisodeMaxNum, Media,
- MediaInline, EpisodePermanent, MediaPermanentInline, Category)
+ EpisodePermanent, Category)
+from admin import MediaInline, MediaPermanentInline
class GenericAdminViewTest(TestCase):
+ urls = "regressiontests.generic_inline_admin.urls"
fixtures = ['users.xml']
def setUp(self):
@@ -125,6 +127,7 @@ class GenericAdminViewTest(TestCase):
self.assertTrue(formset.get_queryset().ordered)
class GenericInlineAdminParametersTest(TestCase):
+ urls = "regressiontests.generic_inline_admin.urls"
fixtures = ['users.xml']
def setUp(self):
@@ -177,6 +180,7 @@ class GenericInlineAdminParametersTest(TestCase):
class GenericInlineAdminWithUniqueTogetherTest(TestCase):
+ urls = "regressiontests.generic_inline_admin.urls"
fixtures = ['users.xml']
def setUp(self):
@@ -203,6 +207,8 @@ class GenericInlineAdminWithUniqueTogetherTest(TestCase):
self.assertEqual(response.status_code, 302) # redirect somewhere
class NoInlineDeletionTest(TestCase):
+ urls = "regressiontests.generic_inline_admin.urls"
+
def test_no_deletion(self):
fake_site = object()
inline = MediaPermanentInline(EpisodePermanent, fake_site)
@@ -211,6 +217,7 @@ class NoInlineDeletionTest(TestCase):
self.assertFalse(formset.can_delete)
class GenericInlineModelAdminTest(TestCase):
+ urls = "regressiontests.generic_inline_admin.urls"
def setUp(self):
self.site = AdminSite()
diff --git a/tests/regressiontests/generic_inline_admin/urls.py b/tests/regressiontests/generic_inline_admin/urls.py
index f41587280d..03431d3226 100644
--- a/tests/regressiontests/generic_inline_admin/urls.py
+++ b/tests/regressiontests/generic_inline_admin/urls.py
@@ -1,6 +1,7 @@
from django.conf.urls import patterns, include
-from django.contrib import admin
+
+import admin
urlpatterns = patterns('',
- (r'^admin/', include(admin.site.urls)),
+ (r'^generic_inline_admin/admin/', include(admin.site.urls)),
)
diff --git a/tests/urls.py b/tests/urls.py
index 654111de60..044395039d 100644
--- a/tests/urls.py
+++ b/tests/urls.py
@@ -22,10 +22,6 @@ urlpatterns = patterns('',
# test urlconf for middleware tests
(r'^middleware/', include('regressiontests.middleware.urls')),
- # admin view tests
- (r'^test_admin/', include('regressiontests.admin_views.urls')),
- (r'^generic_inline_admin/', include('regressiontests.generic_inline_admin.urls')),
-
# admin widget tests
(r'widget_admin/', include('regressiontests.admin_widgets.urls')),