Ticket #15294: admin_tests_urls_fixes.diff

File admin_tests_urls_fixes.diff, 77.6 KB (added by Ramiro Morales, 11 years ago)

URL setup clueanup in admin-related tests by Florian Apolloner, isolated from the v16 patch for easier reviewing

  • 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
    - +  
     1from django.core.paginator import Paginator
     2from django.contrib import admin
     3
     4from models import (Child, Parent, Genre, Band, Musician, Group, Quartet,
     5    Membership, ChordsMusician, ChordsBand, Invitation)
     6
     7site = admin.AdminSite(name="admin")
     8
     9class 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
     15class ParentAdmin(admin.ModelAdmin):
     16    list_filter = ['child__name']
     17    search_fields = ['child__name']
     18
     19
     20class 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
     28class CustomPaginationAdmin(ChildAdmin):
     29    paginator = CustomPaginator
     30
     31
     32class 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
     41class BandAdmin(admin.ModelAdmin):
     42    list_filter = ['genres']
     43
     44
     45class GroupAdmin(admin.ModelAdmin):
     46    list_filter = ['members']
     47
     48
     49class QuartetAdmin(admin.ModelAdmin):
     50    list_filter = ['members']
     51
     52
     53class ChordsBandAdmin(admin.ModelAdmin):
     54    list_filter = ['members']
     55
     56
     57class 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
     67site.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  
    33from django.contrib import admin
    44from django.contrib.admin.options import IncorrectLookupParameters
    55from django.contrib.admin.views.main import ChangeList, SEARCH_VAR, ALL_VAR
    6 from django.core.paginator import Paginator
    76from django.template import Context, Template
    87from django.test import TestCase
    98from django.test.client import RequestFactory
     
    1211from models import (Child, Parent, Genre, Band, Musician, Group, Quartet,
    1312    Membership, ChordsMusician, ChordsBand, Invitation)
    1413
     14from admin import (ChildAdmin, QuartetAdmin, BandAdmin, ChordsBandAdmin,
     15    GroupAdmin, ParentAdmin, DynamicListDisplayChildAdmin, CustomPaginationAdmin,
     16    FilteredChildAdmin, CustomPaginator, site as custom_site)
     17
    1518
    1619class ChangeListTests(TestCase):
     20    urls = "regressiontests.admin_changelist.urls"
     21
    1722    def setUp(self):
    1823        self.factory = RequestFactory()
    1924
     
    129134            new_child = Child.objects.create(name='name %s' % i, parent=new_parent)
    130135
    131136        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)
    137138
    138139        cl = ChangeList(request, Child, m.list_display, m.list_display_links,
    139140                m.list_filter, m.date_hierarchy, m.search_fields,
     
    331332            return request
    332333
    333334        # Test with user 'noparents'
    334         m = DynamicListDisplayChildAdmin(Child, admin.site)
     335        m = custom_site._registry[Child]
    335336        request = _mocked_authenticated_request(user_noparents)
    336337        response = m.changelist_view(request)
    337338        # XXX - Calling render here to avoid ContentNotRenderedError to be
     
    347348        response.render()
    348349        self.assertContains(response, 'Parent object')
    349350
     351        custom_site.unregister(Child)
     352
    350353        # Test default implementation
    351         m = ChildAdmin(Child, admin.site)
     354        custom_site.register(Child, ChildAdmin)
     355        m = custom_site._registry[Child]
    352356        request = _mocked_authenticated_request(user_noparents)
    353357        response = m.changelist_view(request)
    354358        # XXX - #15826
     
    383387        cl.get_results(request)
    384388        self.assertEqual(len(cl.result_list), 10)
    385389
    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 = 10
    395 
    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 = 10
    403 
    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
    - +  
     1from django.conf.urls import patterns, include
     2
     3import admin
     4
     5urlpatterns = 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
    - +  
     1from django.contrib import admin
     2from django import forms
     3
     4from models import *
     5
     6site = admin.AdminSite(name="admin")
     7
     8
     9class BookInline(admin.TabularInline):
     10    model = Author.books.through
     11
     12
     13class AuthorAdmin(admin.ModelAdmin):
     14    inlines = [BookInline]
     15
     16
     17class InnerInline(admin.StackedInline):
     18    model = Inner
     19    can_delete = False
     20    readonly_fields = ('readonly',) # For bug #13174 tests.
     21
     22
     23class HolderAdmin(admin.ModelAdmin):
     24
     25    class Media:
     26        js = ('my_awesome_admin_scripts.js',)
     27
     28
     29class InnerInline2(admin.StackedInline):
     30    model = Inner2
     31
     32    class Media:
     33        js = ('my_awesome_inline_scripts.js',)
     34
     35
     36class InnerInline3(admin.StackedInline):
     37    model = Inner3
     38
     39    class Media:
     40        js = ('my_awesome_inline_scripts.js',)
     41
     42
     43class 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
     54class TitleInline(admin.TabularInline):
     55    model = Title
     56    form = TitleForm
     57    extra = 1
     58
     59
     60class Inner4StackedInline(admin.StackedInline):
     61    model = Inner4Stacked
     62
     63
     64class Inner4TabularInline(admin.TabularInline):
     65    model = Inner4Tabular
     66
     67
     68class Holder4Admin(admin.ModelAdmin):
     69    inlines = [Inner4StackedInline, Inner4TabularInline]
     70
     71
     72class InlineWeakness(admin.TabularInline):
     73    model = ShoppingWeakness
     74    extra = 1
     75
     76
     77class 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
     85class PollAdmin(admin.ModelAdmin):
     86    inlines = [QuestionInline]
     87
     88    def call_me(self, obj):
     89        return 'Callable in PollAdmin'
     90
     91
     92class 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
     100class NovelAdmin(admin.ModelAdmin):
     101    inlines = [ChapterInline]
     102
     103
     104site.register(TitleCollection, inlines=[TitleInline])
     105# Test bug #12561 and #12778
     106# only ModelAdmin media
     107site.register(Holder, HolderAdmin, inlines=[InnerInline])
     108# ModelAdmin and Inline media
     109site.register(Holder2, HolderAdmin, inlines=[InnerInline2])
     110# only Inline media
     111site.register(Holder3, inlines=[InnerInline3])
     112
     113site.register(Poll, PollAdmin)
     114site.register(Novel, NovelAdmin)
     115site.register(Fashionista, inlines=[InlineWeakness])
     116site.register(Holder4, Holder4Admin)
     117site.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  
    33
    44"""
    55from django.db import models
    6 from django.contrib import admin
    76from django.contrib.contenttypes.models import ContentType
    87from django.contrib.contenttypes import generic
    9 from django import forms
     8
    109
    1110class Parent(models.Model):
    1211    name = models.CharField(max_length=50)
     
    1413    def __unicode__(self):
    1514        return self.name
    1615
     16
    1717class Teacher(models.Model):
    1818    name = models.CharField(max_length=50)
    1919
    2020    def __unicode__(self):
    2121        return self.name
    2222
     23
    2324class Child(models.Model):
    2425    name = models.CharField(max_length=50)
    2526    teacher = models.ForeignKey(Teacher)
     
    3132    def __unicode__(self):
    3233        return u'I am %s, a child of %s' % (self.name, self.parent)
    3334
     35
    3436class Book(models.Model):
    3537    name = models.CharField(max_length=50)
    3638
     39
    3740class Author(models.Model):
    3841    name = models.CharField(max_length=50)
    3942    books = models.ManyToManyField(Book)
    4043
    41 class BookInline(admin.TabularInline):
    42     model = Author.books.through
    43 
    44 class AuthorAdmin(admin.ModelAdmin):
    45     inlines = [BookInline]
    46 
    47 admin.site.register(Author, AuthorAdmin)
    4844
    4945class Holder(models.Model):
    5046    dummy = models.IntegerField()
     
    5652    readonly = models.CharField("Inner readonly label", max_length=1)
    5753
    5854
    59 class InnerInline(admin.StackedInline):
    60     model = Inner
    61     can_delete = False
    62     readonly_fields = ('readonly',) # For bug #13174 tests.
    63 
    64 
    6555class Holder2(models.Model):
    6656    dummy = models.IntegerField()
    6757
     
    7060    dummy = models.IntegerField()
    7161    holder = models.ForeignKey(Holder2)
    7262
    73 class HolderAdmin(admin.ModelAdmin):
    74 
    75     class Media:
    76         js = ('my_awesome_admin_scripts.js',)
    77 
    78 class InnerInline2(admin.StackedInline):
    79     model = Inner2
    80 
    81     class Media:
    82         js = ('my_awesome_inline_scripts.js',)
    83 
    8463class Holder3(models.Model):
    8564    dummy = models.IntegerField()
    8665
     
    8968    dummy = models.IntegerField()
    9069    holder = models.ForeignKey(Holder3)
    9170
    92 class InnerInline3(admin.StackedInline):
    93     model = Inner3
    94 
    95     class Media:
    96         js = ('my_awesome_inline_scripts.js',)
    97 
    98 # Test bug #12561 and #12778
    99 # only ModelAdmin media
    100 admin.site.register(Holder, HolderAdmin, inlines=[InnerInline])
    101 # ModelAdmin and Inline media
    102 admin.site.register(Holder2, HolderAdmin, inlines=[InnerInline2])
    103 # only Inline media
    104 admin.site.register(Holder3, inlines=[InnerInline3])
    105 
    106 
    10771# Models for ticket #8190
    10872
    10973class Holder4(models.Model):
     
    11781    dummy = models.IntegerField(help_text="Awesome tabular help text is awesome.")
    11882    holder = models.ForeignKey(Holder4)
    11983
    120 class Inner4StackedInline(admin.StackedInline):
    121     model = Inner4Stacked
    122 
    123 class Inner4TabularInline(admin.TabularInline):
    124     model = Inner4Tabular
    125 
    126 class Holder4Admin(admin.ModelAdmin):
    127     inlines = [Inner4StackedInline, Inner4TabularInline]
    128 
    129 admin.site.register(Holder4, Holder4Admin)
    130 
    13184
    13285# Models for #12749
    13386
     
    14598    fashionista = models.ForeignKey(Fashionista)
    14699    item = models.ForeignKey(OutfitItem)
    147100
    148 class InlineWeakness(admin.TabularInline):
    149     model = ShoppingWeakness
    150     extra = 1
    151 
    152 admin.site.register(Fashionista, inlines=[InlineWeakness])
    153 
    154101# Models for #13510
    155102
    156103class TitleCollection(models.Model):
     
    161108    title1 = models.CharField(max_length=100)
    162109    title2 = models.CharField(max_length=100)
    163110
    164 class TitleForm(forms.ModelForm):
    165 
    166     def clean(self):
    167         cleaned_data = self.cleaned_data
    168         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_data
    173 
    174 class TitleInline(admin.TabularInline):
    175     model = Title
    176     form = TitleForm
    177     extra = 1
    178 
    179 admin.site.register(TitleCollection, inlines=[TitleInline])
    180 
    181111# Models for #15424
    182112
    183113class Poll(models.Model):
     
    186116class Question(models.Model):
    187117    poll = models.ForeignKey(Poll)
    188118
    189 class QuestionInline(admin.TabularInline):
    190     model = Question
    191     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 
    202119class Novel(models.Model):
    203120    name = models.CharField(max_length=40)
    204121
    205122class Chapter(models.Model):
    206123    novel = models.ForeignKey(Novel)
    207124
    208 class ChapterInline(admin.TabularInline):
    209     model = Chapter
    210     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  
    33from django.test import TestCase
    44
    55# local test models
    6 from models import (Holder, Inner, InnerInline, Holder2, Inner2, Holder3,
     6from models import (Holder, Inner, Holder2, Inner2, Holder3,
    77    Inner3, Person, OutfitItem, Fashionista, Teacher, Parent, Child)
     8from admin import InnerInline
    89
    910
    1011class TestInline(TestCase):
     12    urls = "regressiontests.admin_inlines.urls"
    1113    fixtures = ['admin-views-users.xml']
    1214
    1315    def setUp(self):
    1416        holder = Holder(dummy=13)
    1517        holder.save()
    1618        Inner(dummy=42, holder=holder).save()
    17         self.change_url = '/test_admin/admin/admin_inlines/holder/%i/' % holder.id
     19        self.change_url = '/admin/admin_inlines/holder/%i/' % holder.id
    1820
    1921        result = self.client.login(username='super', password='secret')
    2022        self.assertEqual(result, True)
     
    3638        """Bug #13174."""
    3739        holder = Holder.objects.create(dummy=42)
    3840        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/'
    4042                                   % holder.id)
    4143        self.assertContains(response, '<label>Inner readonly label:</label>')
    4244
    4345    def test_many_to_many_inlines(self):
    4446        "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/')
    4648        # The heading for the m2m inline block uses the right text
    4749        self.assertContains(response, '<h2>Author-book relationships</h2>')
    4850        # The "add another" label is correct
     
    6365            'max_weight': 0,
    6466            'shoppingweakness_set-0-item': item.id,
    6567        }
    66         response = self.client.post('/test_admin/admin/admin_inlines/fashionista/add/', data)
     68        response = self.client.post('/admin/admin_inlines/fashionista/add/', data)
    6769        self.assertEqual(response.status_code, 302)
    6870        self.assertEqual(len(Fashionista.objects.filter(person__firstname='Imelda')), 1)
    6971
     
    8082            'title_set-0-title1': 'a title',
    8183            'title_set-0-title2': 'a different title',
    8284        }
    83         response = self.client.post('/test_admin/admin/admin_inlines/titlecollection/add/', data)
     85        response = self.client.post('/admin/admin_inlines/titlecollection/add/', data)
    8486        # Here colspan is "4": two fields (title1 and title2), one hidden field and the delete checkbock.
    8587        self.assertContains(response, '<tr><td colspan="4"><ul class="errorlist"><li>The two titles must be the same</li></ul></td></tr>')
    8688
     
    8890        """Admin inline `readonly_field` shouldn't invoke parent ModelAdmin callable"""
    8991        # Identically named callable isn't present in the parent ModelAdmin,
    9092        # 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/')
    9294        self.assertEqual(response.status_code, 200)
    9395        # View should have the child inlines section
    9496        self.assertContains(response, '<div class="inline-group" id="chapter_set-group">')
    9597
    9698    def test_callable_lookup(self):
    9799        """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/')
    99101        self.assertEqual(response.status_code, 200)
    100102        # Add parent object view should have the child inlines section
    101103        self.assertContains(response, '<div class="inline-group" id="question_set-group">')
     
    109111        using both the stacked and tabular layouts.
    110112        Ref #8190.
    111113        """
    112         response = self.client.get('/test_admin/admin/admin_inlines/holder4/add/')
     114        response = self.client.get('/admin/admin_inlines/holder4/add/')
    113115        self.assertContains(response, '<p class="help">Awesome stacked help text is awesome.</p>', 4)
    114116        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)
    115117
    116118class TestInlineMedia(TestCase):
     119    urls = "regressiontests.admin_inlines.urls"
    117120    fixtures = ['admin-views-users.xml']
    118121
    119122    def setUp(self):
     
    128131        holder = Holder(dummy=13)
    129132        holder.save()
    130133        Inner(dummy=42, holder=holder).save()
    131         change_url = '/test_admin/admin/admin_inlines/holder/%i/' % holder.id
     134        change_url = '/admin/admin_inlines/holder/%i/' % holder.id
    132135        response = self.client.get(change_url)
    133136        self.assertContains(response, 'my_awesome_admin_scripts.js')
    134137
     
    136139        holder = Holder3(dummy=13)
    137140        holder.save()
    138141        Inner3(dummy=42, holder=holder).save()
    139         change_url = '/test_admin/admin/admin_inlines/holder3/%i/' % holder.id
     142        change_url = '/admin/admin_inlines/holder3/%i/' % holder.id
    140143        response = self.client.get(change_url)
    141144        self.assertContains(response, 'my_awesome_inline_scripts.js')
    142145
     
    144147        holder = Holder2(dummy=13)
    145148        holder.save()
    146149        Inner2(dummy=42, holder=holder).save()
    147         change_url = '/test_admin/admin/admin_inlines/holder2/%i/' % holder.id
     150        change_url = '/admin/admin_inlines/holder2/%i/' % holder.id
    148151        response = self.client.get(change_url)
    149152        self.assertContains(response, 'my_awesome_admin_scripts.js')
    150153        self.assertContains(response, 'my_awesome_inline_scripts.js')
    151154
    152155class TestInlineAdminForm(TestCase):
     156    urls = "regressiontests.admin_inlines.urls"
    153157
    154158    def test_immutable_content_type(self):
    155159        """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
    - +  
     1from django.conf.urls import patterns, include
     2
     3import admin
     4
     5urlpatterns = 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 -*-
     2import datetime
     3import tempfile
     4import os
     5
     6from django.contrib import admin
     7from django.contrib.admin.views.main import ChangeList
     8from django.forms.models import BaseModelFormSet
     9from django.core.mail import EmailMessage
     10
     11from models import *
     12
     13
     14def callable_year(dt_value):
     15    return dt_value.year
     16callable_year.admin_order_field = 'date'
     17
     18
     19class ArticleInline(admin.TabularInline):
     20    model = Article
     21
     22
     23class ChapterInline(admin.TabularInline):
     24    model = Chapter
     25
     26
     27class 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
     36class 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
     72class 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
     78class 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
     98class ThingAdmin(admin.ModelAdmin):
     99    list_filter = ('color__warm', 'color__value')
     100
     101
     102class InquisitionAdmin(admin.ModelAdmin):
     103    list_display = ('leader', 'country', 'expected')
     104
     105
     106class SketchAdmin(admin.ModelAdmin):
     107    raw_id_fields = ('inquisition',)
     108
     109
     110class FabricAdmin(admin.ModelAdmin):
     111    list_display = ('surface',)
     112    list_filter = ('surface',)
     113
     114
     115class 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
     124class 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
     141class FooAccount(Account):
     142    """A service-specific account of type Foo."""
     143    servicename = u'foo'
     144
     145
     146class BarAccount(Account):
     147    """A service-specific account of type Bar."""
     148    servicename = u'bar'
     149
     150
     151class FooAccountAdmin(admin.StackedInline):
     152    model = FooAccount
     153    extra = 1
     154
     155
     156class BarAccountAdmin(admin.StackedInline):
     157    model = BarAccount
     158    extra = 1
     159
     160
     161class PersonaAdmin(admin.ModelAdmin):
     162    inlines = (
     163        FooAccountAdmin,
     164        BarAccountAdmin
     165    )
     166
     167
     168class 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
     180def 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()
     187external_mail.short_description = 'External mail (Another awesome action)'
     188
     189
     190def redirect_to(modeladmin, request, selected):
     191    from django.http import HttpResponseRedirect
     192    return HttpResponseRedirect('/some-where-else/')
     193redirect_to.short_description = 'Redirect to (Awesome action)'
     194
     195
     196class ExternalSubscriberAdmin(admin.ModelAdmin):
     197    actions = [redirect_to, external_mail]
     198
     199
     200class Podcast(Media):
     201    release_date = models.DateField()
     202
     203    class Meta:
     204        ordering = ('release_date',) # overridden in PodcastAdmin
     205
     206
     207class PodcastAdmin(admin.ModelAdmin):
     208    list_display = ('name', 'release_date')
     209    list_editable = ('release_date',)
     210    date_hierarchy = 'release_date'
     211    ordering = ('name',)
     212
     213
     214class VodcastAdmin(admin.ModelAdmin):
     215    list_display = ('name', 'released')
     216    list_editable = ('released',)
     217
     218    ordering = ('name',)
     219
     220
     221class ChildInline(admin.StackedInline):
     222    model = Child
     223
     224
     225class 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
     240class EmptyModelAdmin(admin.ModelAdmin):
     241    def queryset(self, request):
     242        return super(EmptyModelAdmin, self).queryset(request).filter(pk__gt=1)
     243
     244
     245class OldSubscriberAdmin(admin.ModelAdmin):
     246    actions = None
     247
     248
     249temp_storage = FileSystemStorage(tempfile.mkdtemp())
     250UPLOAD_TO = os.path.join(temp_storage.location, 'test_upload')
     251
     252
     253class PictureInline(admin.TabularInline):
     254    model = Picture
     255    extra = 1
     256
     257
     258class GalleryAdmin(admin.ModelAdmin):
     259    inlines = [PictureInline]
     260
     261
     262class PictureAdmin(admin.ModelAdmin):
     263    pass
     264
     265
     266class LanguageAdmin(admin.ModelAdmin):
     267    list_display = ['iso', 'shortlist', 'english_name', 'name']
     268    list_editable = ['shortlist']
     269
     270
     271class RecommendationAdmin(admin.ModelAdmin):
     272    search_fields = ('=titletranslation__text', '=recommender__titletranslation__text',)
     273
     274
     275class WidgetInline(admin.StackedInline):
     276    model = Widget
     277
     278
     279class DooHickeyInline(admin.StackedInline):
     280    model = DooHickey
     281
     282
     283class GrommetInline(admin.StackedInline):
     284    model = Grommet
     285
     286
     287class WhatsitInline(admin.StackedInline):
     288    model = Whatsit
     289
     290
     291class FancyDoodadInline(admin.StackedInline):
     292    model = FancyDoodad
     293
     294
     295class CategoryAdmin(admin.ModelAdmin):
     296    list_display = ('id', 'collector', 'order')
     297    list_editable = ('order',)
     298
     299
     300class CategoryInline(admin.StackedInline):
     301    model = Category
     302
     303
     304class CollectorAdmin(admin.ModelAdmin):
     305    inlines = [
     306        WidgetInline, DooHickeyInline, GrommetInline, WhatsitInline,
     307        FancyDoodadInline, CategoryInline
     308    ]
     309
     310
     311class LinkInline(admin.TabularInline):
     312    model = Link
     313    extra = 1
     314
     315    readonly_fields = ("posted",)
     316
     317
     318class 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
     336class 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
     355class 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
     374class CustomChangeList(ChangeList):
     375    def get_query_set(self, request):
     376        return self.root_query_set.filter(pk=9999) # Does not exist
     377
     378
     379class GadgetAdmin(admin.ModelAdmin):
     380    def get_changelist(self, request, **kwargs):
     381        return CustomChangeList
     382
     383
     384class PizzaAdmin(admin.ModelAdmin):
     385    readonly_fields = ('toppings',)
     386
     387
     388class WorkHourAdmin(admin.ModelAdmin):
     389    list_display = ('datum', 'employee')
     390    list_filter = ('employee',)
     391
     392
     393class FoodDeliveryAdmin(admin.ModelAdmin):
     394    list_display=('reference', 'driver', 'restaurant')
     395    list_editable = ('driver', 'restaurant')
     396
     397
     398class 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
     408class 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
     419class StoryForm(forms.ModelForm):
     420    class Meta:
     421        widgets = {'title': forms.HiddenInput}
     422
     423
     424class 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
     432class 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
     439class 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
     449class AlbumAdmin(admin.ModelAdmin):
     450    list_filter = ['title']
     451
     452
     453class WorkHourAdmin(admin.ModelAdmin):
     454    list_display = ('datum', 'employee')
     455    list_filter = ('employee',)
     456
     457
     458site = admin.AdminSite(name="admin")
     459site.register(Article, ArticleAdmin)
     460site.register(CustomArticle, CustomArticleAdmin)
     461site.register(Section, save_as=True, inlines=[ArticleInline])
     462site.register(ModelWithStringPrimaryKey)
     463site.register(Color)
     464site.register(Thing, ThingAdmin)
     465site.register(Actor)
     466site.register(Inquisition, InquisitionAdmin)
     467site.register(Sketch, SketchAdmin)
     468site.register(Person, PersonAdmin)
     469site.register(Persona, PersonaAdmin)
     470site.register(Subscriber, SubscriberAdmin)
     471site.register(ExternalSubscriber, ExternalSubscriberAdmin)
     472site.register(OldSubscriber, OldSubscriberAdmin)
     473site.register(Podcast, PodcastAdmin)
     474site.register(Vodcast, VodcastAdmin)
     475site.register(Parent, ParentAdmin)
     476site.register(EmptyModel, EmptyModelAdmin)
     477site.register(Fabric, FabricAdmin)
     478site.register(Gallery, GalleryAdmin)
     479site.register(Picture, PictureAdmin)
     480site.register(Language, LanguageAdmin)
     481site.register(Recommendation, RecommendationAdmin)
     482site.register(Recommender)
     483site.register(Collector, CollectorAdmin)
     484site.register(Category, CategoryAdmin)
     485site.register(Post, PostAdmin)
     486site.register(Gadget, GadgetAdmin)
     487site.register(Villain)
     488site.register(SuperVillain)
     489site.register(Plot)
     490site.register(PlotDetails)
     491site.register(CyclicOne)
     492site.register(CyclicTwo)
     493site.register(WorkHour, WorkHourAdmin)
     494site.register(Reservation)
     495site.register(FoodDelivery, FoodDeliveryAdmin)
     496site.register(RowLevelChangePermissionModel, RowLevelChangePermissionModelAdmin)
     497site.register(Paper, PaperAdmin)
     498site.register(CoverLetter, CoverLetterAdmin)
     499site.register(Story, StoryAdmin)
     500site.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.
     511site.register(Book, inlines=[ChapterInline])
     512site.register(Promo)
     513site.register(ChapterXtra1, ChapterXtra1Admin)
     514site.register(Pizza, PizzaAdmin)
     515site.register(Topping)
     516site.register(Album, AlbumAdmin)
     517site.register(Question)
     518site.register(Answer)
     519site.register(PrePopulatedPost, PrePopulatedPostAdmin)
     520site.register(ComplexSortedPerson, ComplexSortedPersonAdmin)
     521
     522# Register core models we need in our tests
     523from django.contrib.auth.models import User, Group
     524from django.contrib.auth.admin import UserAdmin, GroupAdmin
     525site.register(User, UserAdmin)
     526site.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  
    55from django.contrib import admin
    66from django.http import HttpResponse
    77
    8 import models, forms
     8import models, forms, admin as base_admin
    99
    1010class Admin2(admin.AdminSite):
    1111    login_form = forms.CustomAdminAuthenticationForm
     
    2929
    3030site = Admin2(name="admin2")
    3131
    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)
     32site.register(models.Article, base_admin.ArticleAdmin)
     33site.register(models.Section, inlines=[base_admin.ArticleInline])
     34site.register(models.Thing, base_admin.ThingAdmin)
     35site.register(models.Fabric, base_admin.FabricAdmin)
     36site.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  
    33import tempfile
    44import os
    55
    6 from django.contrib import admin
    76from django.core.files.storage import FileSystemStorage
    8 from django.contrib.admin.views.main import ChangeList
    9 from django.core.mail import EmailMessage
    107from django.db import models
    118from django import forms
    12 from django.forms.models import BaseModelFormSet
    139from django.contrib.auth.models import User
    1410from django.contrib.contenttypes import generic
    1511from django.contrib.contenttypes.models import ContentType
    1612
     13
    1714class Section(models.Model):
    1815    """
    1916    A simple section that links to articles, to test linking to related items
     
    2118    """
    2219    name = models.CharField(max_length=100)
    2320
     21
    2422class Article(models.Model):
    2523    """
    2624    A simple article to test admin views. Test backwards compatibility.
     
    3836    model_year.admin_order_field = 'date'
    3937    model_year.short_description = ''
    4038
     39
    4140class Book(models.Model):
    4241    """
    4342    A simple book that has chapters.
     
    4746    def __unicode__(self):
    4847        return self.name
    4948
     49
    5050class Promo(models.Model):
    5151    name = models.CharField(max_length=100, verbose_name=u'¿Name?')
    5252    book = models.ForeignKey(Book)
     
    5454    def __unicode__(self):
    5555        return self.name
    5656
     57
    5758class Chapter(models.Model):
    5859    title = models.CharField(max_length=100, verbose_name=u'¿Title?')
    5960    content = models.TextField()
     
    6667        # Use a utf-8 bytestring to ensure it works (see #11710)
    6768        verbose_name = '¿Chapter?'
    6869
     70
    6971class ChapterXtra1(models.Model):
    7072    chap = models.OneToOneField(Chapter, verbose_name=u'¿Chap?')
    7173    xtra = models.CharField(max_length=100, verbose_name=u'¿Xtra?')
     
    7375    def __unicode__(self):
    7476        return u'¿Xtra1: %s' % self.xtra
    7577
     78
    7679class ChapterXtra2(models.Model):
    7780    chap = models.OneToOneField(Chapter, verbose_name=u'¿Chap?')
    7881    xtra = models.CharField(max_length=100, verbose_name=u'¿Xtra?')
     
    8083    def __unicode__(self):
    8184        return u'¿Xtra2: %s' % self.xtra
    8285
    83 def callable_year(dt_value):
    84     return dt_value.year
    85 callable_year.admin_order_field = 'date'
    86 
    87 class ArticleInline(admin.TabularInline):
    88     model = Article
    89 
    90 class ChapterInline(admin.TabularInline):
    91     model = Chapter
    92 
    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.year
    115     modeladmin_year.admin_order_field = 'date'
    116     modeladmin_year.short_description = None
    117 
    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)
    13586
    13687class RowLevelChangePermissionModel(models.Model):
    13788    name = models.CharField(max_length=100, blank=True)
    13889
    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)
    14390
    14491class CustomArticle(models.Model):
    14592    content = models.TextField()
    14693    date = models.DateTimeField()
    14794
    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         )
    16695
    16796class ModelWithStringPrimaryKey(models.Model):
    16897    id = models.CharField(max_length=255, primary_key=True)
     
    17099    def __unicode__(self):
    171100        return self.id
    172101
     102
    173103class Color(models.Model):
    174104    value = models.CharField(max_length=10)
    175105    warm = models.BooleanField()
    176106    def __unicode__(self):
    177107        return self.value
    178108
     109
    179110class Thing(models.Model):
    180111    title = models.CharField(max_length=20)
    181112    color = models.ForeignKey(Color, limit_choices_to={'warm': True})
    182113    def __unicode__(self):
    183114        return self.title
    184115
    185 class ThingAdmin(admin.ModelAdmin):
    186     list_filter = ('color__warm', 'color__value')
    187116
    188117class Actor(models.Model):
    189118    name = models.CharField(max_length=50)
     
    191120    def __unicode__(self):
    192121        return self.name
    193122
     123
    194124class Inquisition(models.Model):
    195125    expected = models.BooleanField()
    196126    leader = models.ForeignKey(Actor)
     
    199129    def __unicode__(self):
    200130        return u"by %s from %s" % (self.leader, self.country)
    201131
    202 class InquisitionAdmin(admin.ModelAdmin):
    203     list_display = ('leader', 'country', 'expected')
    204132
    205133class Sketch(models.Model):
    206134    title = models.CharField(max_length=100)
     
    212140    def __unicode__(self):
    213141        return self.title
    214142
    215 class SketchAdmin(admin.ModelAdmin):
    216     raw_id_fields = ('inquisition',)
    217143
    218144class Fabric(models.Model):
    219145    NG_CHOICES = (
     
    226152    )
    227153    surface = models.CharField(max_length=20, choices=NG_CHOICES)
    228154
    229 class FabricAdmin(admin.ModelAdmin):
    230     list_display = ('surface',)
    231     list_filter = ('surface',)
    232155
    233156class Person(models.Model):
    234157    GENDER_CHOICES = (
     
    243166    def __unicode__(self):
    244167        return self.name
    245168
    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 = True
    260 
    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 test
    267         # whether ordering is preserved.
    268         return super(PersonAdmin, self).queryset(request).order_by('age')
    269 
    270169
    271170class Persona(models.Model):
    272171    """
     
    277176    def __unicode__(self):
    278177        return self.name
    279178
     179
    280180class Account(models.Model):
    281181    """
    282182    A simple, generic account encapsulating the information shared by all
     
    289189    def __unicode__(self):
    290190        return "%s: %s" % (self.servicename, self.username)
    291191
     192
    292193class FooAccount(Account):
    293194    """A service-specific account of type Foo."""
    294195    servicename = u'foo'
    295196
     197
    296198class BarAccount(Account):
    297199    """A service-specific account of type Bar."""
    298200    servicename = u'bar'
    299201
    300 class FooAccountAdmin(admin.StackedInline):
    301     model = FooAccount
    302     extra = 1
    303 
    304 class BarAccountAdmin(admin.StackedInline):
    305     model = BarAccount
    306     extra = 1
    307 
    308 class PersonaAdmin(admin.ModelAdmin):
    309     inlines = (
    310         FooAccountAdmin,
    311         BarAccountAdmin
    312     )
    313202
    314203class Subscriber(models.Model):
    315204    name = models.CharField(blank=False, max_length=80)
     
    318207    def __unicode__(self):
    319208        return "%s (%s)" % (self.name, self.email)
    320209
    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()
    331210
    332211class ExternalSubscriber(Subscriber):
    333212    pass
    334213
     214
    335215class OldSubscriber(Subscriber):
    336216    pass
    337217
    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 HttpResponseRedirect
    349     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]
    354218
    355219class Media(models.Model):
    356220    name = models.CharField(max_length=60)
    357221
     222
    358223class Podcast(Media):
    359224    release_date = models.DateField()
    360225
    361226    class Meta:
    362227        ordering = ('release_date',) # overridden in PodcastAdmin
    363228
    364 class PodcastAdmin(admin.ModelAdmin):
    365     list_display = ('name', 'release_date')
    366     list_editable = ('release_date',)
    367     date_hierarchy = 'release_date'
    368     ordering = ('name',)
    369229
    370230class Vodcast(Media):
    371231    media = models.OneToOneField(Media, primary_key=True, parent_link=True)
    372232    released = models.BooleanField(default=False)
    373233
    374 class VodcastAdmin(admin.ModelAdmin):
    375     list_display = ('name', 'released')
    376     list_editable = ('released',)
    377 
    378     ordering = ('name',)
    379234
    380235class Parent(models.Model):
    381236    name = models.CharField(max_length=128)
    382237
     238
    383239class Child(models.Model):
    384240    parent = models.ForeignKey(Parent, editable=False)
    385241    name = models.CharField(max_length=30, blank=True)
    386242
    387 class ChildInline(admin.StackedInline):
    388     model = Child
    389 
    390 class ParentAdmin(admin.ModelAdmin):
    391     model = Parent
    392     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_name
    402                 child.save()
    403243
    404244class EmptyModel(models.Model):
    405245    def __unicode__(self):
    406246        return "Primary key = %s" % self.id
    407247
    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 = None
    414248
    415249temp_storage = FileSystemStorage(tempfile.mkdtemp())
    416250UPLOAD_TO = os.path.join(temp_storage.location, 'test_upload')
    417251
     252
    418253class Gallery(models.Model):
    419254    name = models.CharField(max_length=100)
    420255
     256
    421257class Picture(models.Model):
    422258    name = models.CharField(max_length=100)
    423259    image = models.FileField(storage=temp_storage, upload_to='test_upload')
    424260    gallery = models.ForeignKey(Gallery, related_name="pictures")
    425261
    426 class PictureInline(admin.TabularInline):
    427     model = Picture
    428     extra = 1
    429 
    430 class GalleryAdmin(admin.ModelAdmin):
    431     inlines = [PictureInline]
    432 
    433 class PictureAdmin(admin.ModelAdmin):
    434     pass
    435262
    436263class Language(models.Model):
    437264    iso = models.CharField(max_length=5, primary_key=True)
     
    442269    class Meta:
    443270        ordering = ('iso',)
    444271
    445 class LanguageAdmin(admin.ModelAdmin):
    446     list_display = ['iso', 'shortlist', 'english_name', 'name']
    447     list_editable = ['shortlist']
    448272
    449273# a base class for Recommender and Recommendation
    450274class Title(models.Model):
    451275    pass
    452276
     277
    453278class TitleTranslation(models.Model):
    454279    title = models.ForeignKey(Title)
    455280    text = models.CharField(max_length=100)
    456281
     282
    457283class Recommender(Title):
    458284    pass
    459285
     286
    460287class Recommendation(Title):
    461288    recommender = models.ForeignKey(Recommender)
    462289
    463 class RecommendationAdmin(admin.ModelAdmin):
    464     search_fields = ('=titletranslation__text', '=recommender__titletranslation__text',)
    465290
    466291class Collector(models.Model):
    467292    name = models.CharField(max_length=100)
    468293
     294
    469295class Widget(models.Model):
    470296    owner = models.ForeignKey(Collector)
    471297    name = models.CharField(max_length=100)
    472298
     299
    473300class DooHickey(models.Model):
    474301    code = models.CharField(max_length=10, primary_key=True)
    475302    owner = models.ForeignKey(Collector)
    476303    name = models.CharField(max_length=100)
    477304
     305
    478306class Grommet(models.Model):
    479307    code = models.AutoField(primary_key=True)
    480308    owner = models.ForeignKey(Collector)
    481309    name = models.CharField(max_length=100)
    482310
     311
    483312class Whatsit(models.Model):
    484313    index = models.IntegerField(primary_key=True)
    485314    owner = models.ForeignKey(Collector)
    486315    name = models.CharField(max_length=100)
    487316
     317
    488318class Doodad(models.Model):
    489319    name = models.CharField(max_length=100)
    490320
     321
    491322class FancyDoodad(Doodad):
    492323    owner = models.ForeignKey(Collector)
    493324    expensive = models.BooleanField(default=True)
    494325
    495 class WidgetInline(admin.StackedInline):
    496     model = Widget
    497 
    498 class DooHickeyInline(admin.StackedInline):
    499     model = DooHickey
    500 
    501 class GrommetInline(admin.StackedInline):
    502     model = Grommet
    503 
    504 class WhatsitInline(admin.StackedInline):
    505     model = Whatsit
    506 
    507 class FancyDoodadInline(admin.StackedInline):
    508     model = FancyDoodad
    509326
    510327class Category(models.Model):
    511328    collector = models.ForeignKey(Collector)
     
    517334    def __unicode__(self):
    518335        return u'%s:o%s' % (self.id, self.order)
    519336
    520 class CategoryAdmin(admin.ModelAdmin):
    521     list_display = ('id', 'collector', 'order')
    522     list_editable = ('order',)
    523 
    524 class CategoryInline(admin.StackedInline):
    525     model = Category
    526 
    527 class CollectorAdmin(admin.ModelAdmin):
    528     inlines = [
    529         WidgetInline, DooHickeyInline, GrommetInline, WhatsitInline,
    530         FancyDoodadInline, CategoryInline
    531     ]
    532337
    533338class Link(models.Model):
    534339    posted = models.DateField(
     
    538343    post = models.ForeignKey("Post")
    539344
    540345
    541 class LinkInline(admin.TabularInline):
    542     model = Link
    543     extra = 1
    544 
    545     readonly_fields = ("posted",)
    546 
    547 
    548346class PrePopulatedPost(models.Model):
    549347    title = models.CharField(max_length=100)
    550348    published = models.BooleanField()
    551349    slug = models.SlugField()
    552350
     351
    553352class PrePopulatedSubPost(models.Model):
    554353    post = models.ForeignKey(PrePopulatedPost)
    555354    subtitle = models.CharField(max_length=100)
    556355    subslug = models.SlugField()
    557356
    558 class SubPostInline(admin.TabularInline):
    559     model = PrePopulatedSubPost
    560 
    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_fields
    569 
    570     def get_prepopulated_fields(self, request, obj=None):
    571         if obj and obj.published:
    572             return {}
    573         return self.prepopulated_fields
    574 
    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_fields
    587 
    588     def get_prepopulated_fields(self, request, obj=None):
    589         if obj and obj.published:
    590             return {}
    591         return self.prepopulated_fields
    592357
    593358class Post(models.Model):
    594359    title = models.CharField(max_length=100, help_text="Some help text for the title (with unicode ŠĐĆŽćžšđ)")
     
    602367    def awesomeness_level(self):
    603368        return "Very awesome."
    604369
    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         LinkInline
    611     ]
    612 
    613     def coolness(self, instance):
    614         if instance.pk:
    615             return "%d amount of cool." % instance.pk
    616         else:
    617             return "Unkown coolness."
    618 
    619     def value(self, instance):
    620         return 1000
    621     value.short_description = 'Value in $US'
    622370
    623371class Gadget(models.Model):
    624372    name = models.CharField(max_length=100)
     
    626374    def __unicode__(self):
    627375        return self.name
    628376
    629 class CustomChangeList(ChangeList):
    630     def get_query_set(self, request):
    631         return self.root_query_set.filter(pk=9999) # Does not exist
    632 
    633 class GadgetAdmin(admin.ModelAdmin):
    634     def get_changelist(self, request, **kwargs):
    635         return CustomChangeList
    636377
    637378class Villain(models.Model):
    638379    name = models.CharField(max_length=100)
     
    640381    def __unicode__(self):
    641382        return self.name
    642383
     384
    643385class SuperVillain(Villain):
    644386    pass
    645387
     388
    646389class FunkyTag(models.Model):
    647390    "Because we all know there's only one real use case for GFKs."
    648391    name = models.CharField(max_length=25)
     
    653396    def __unicode__(self):
    654397        return self.name
    655398
     399
    656400class Plot(models.Model):
    657401    name = models.CharField(max_length=100)
    658402    team_leader = models.ForeignKey(Villain, related_name='lead_plots')
     
    662406    def __unicode__(self):
    663407        return self.name
    664408
     409
    665410class PlotDetails(models.Model):
    666411    details = models.CharField(max_length=100)
    667412    plot = models.OneToOneField(Plot)
     
    669414    def __unicode__(self):
    670415        return self.details
    671416
     417
    672418class SecretHideout(models.Model):
    673419    """ Secret! Not registered with the admin! """
    674420    location = models.CharField(max_length=100)
     
    677423    def __unicode__(self):
    678424        return self.location
    679425
     426
    680427class SuperSecretHideout(models.Model):
    681428    """ Secret! Not registered with the admin! """
    682429    location = models.CharField(max_length=100)
     
    685432    def __unicode__(self):
    686433        return self.location
    687434
     435
    688436class CyclicOne(models.Model):
    689437    name = models.CharField(max_length=25)
    690438    two = models.ForeignKey('CyclicTwo')
     
    692440    def __unicode__(self):
    693441        return self.name
    694442
     443
    695444class CyclicTwo(models.Model):
    696445    name = models.CharField(max_length=25)
    697446    one = models.ForeignKey(CyclicOne)
     
    699448    def __unicode__(self):
    700449        return self.name
    701450
     451
    702452class Topping(models.Model):
    703453    name = models.CharField(max_length=20)
    704454
     455
    705456class Pizza(models.Model):
    706457    name = models.CharField(max_length=20)
    707458    toppings = models.ManyToManyField('Topping')
    708459
    709 class PizzaAdmin(admin.ModelAdmin):
    710     readonly_fields = ('toppings',)
    711460
    712461class Album(models.Model):
    713462    owner = models.ForeignKey(User)
    714463    title = models.CharField(max_length=30)
    715464
    716 class AlbumAdmin(admin.ModelAdmin):
    717     list_filter = ['title']
    718465
    719466class Employee(Person):
    720467    code = models.CharField(max_length=20)
    721468
     469
    722470class WorkHour(models.Model):
    723471    datum = models.DateField()
    724472    employee = models.ForeignKey(Employee)
    725473
    726 class WorkHourAdmin(admin.ModelAdmin):
    727     list_display = ('datum', 'employee')
    728     list_filter = ('employee',)
    729474
    730475class Question(models.Model):
    731476    question = models.CharField(max_length=20)
    732477
     478
    733479class Answer(models.Model):
    734480    question = models.ForeignKey(Question, on_delete=models.PROTECT)
    735481    answer = models.CharField(max_length=20)
     
    737483    def __unicode__(self):
    738484        return self.answer
    739485
     486
    740487class Reservation(models.Model):
    741488    start_date = models.DateTimeField()
    742489    price = models.IntegerField()
     
    753500    (u'pizza', u'Pizza Mama'),
    754501)
    755502
     503
    756504class FoodDelivery(models.Model):
    757505    reference = models.CharField(max_length=100)
    758506    driver = models.CharField(max_length=100, choices=DRIVER_CHOICES, blank=True)
     
    761509    class Meta:
    762510        unique_together = (("driver", "restaurant"),)
    763511
    764 class FoodDeliveryAdmin(admin.ModelAdmin):
    765     list_display=('reference', 'driver', 'restaurant')
    766     list_editable = ('driver', 'restaurant')
    767512
    768513class Paper(models.Model):
    769514    title = models.CharField(max_length=30)
    770515    author = models.CharField(max_length=30, blank=True, null=True)
    771516
     517
    772518class CoverLetter(models.Model):
    773519    author = models.CharField(max_length=30)
    774520    date_written = models.DateField(null=True, blank=True)
     
    776522    def __unicode__(self):
    777523        return self.author
    778524
    779 class PaperAdmin(admin.ModelAdmin):
    780     """
    781     A ModelAdin with a custom queryset() method that uses only(), to test
    782     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 test
    791     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')
    797525
    798526class Story(models.Model):
    799527    title = models.CharField(max_length=100)
    800528    content = models.TextField()
    801529
    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_links
    809     list_editable = ('content', )
    810     form = StoryForm
    811     ordering = ["-pk"]
    812530
    813531class OtherStory(models.Model):
    814532    title = models.CharField(max_length=100)
    815533    content = models.TextField()
    816534
    817 class OtherStoryAdmin(admin.ModelAdmin):
    818     list_display = ('id', 'title', 'content')
    819     list_display_links = ('title', 'id') # 'id' in list_display_links
    820     list_editable = ('content', )
    821     ordering = ["-pk"]
    822535
    823536class ComplexSortedPerson(models.Model):
    824537    name = models.CharField(max_length=100)
    825538    age = models.PositiveIntegerField()
    826539    is_employee = models.NullBooleanField()
    827540
    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 = True
    835     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 admin
    883 #     related ForeignKey object not registered in admin
    884 #     related OneToOne object registered in admin
    885 #     related OneToOne object not registered in admin
    886 # when deleting Book so as exercise all four troublesome (w.r.t escaping
    887 # and calling force_unicode to avoid problems on Python 2.3) paths through
    888 # 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  
    3232
    3333# local test models
    3434from models import (Article, BarAccount, CustomArticle, EmptyModel,
    35     FooAccount, Gallery, PersonAdmin, ModelWithStringPrimaryKey,
     35    FooAccount, Gallery, ModelWithStringPrimaryKey,
    3636    Person, Persona, Picture, Podcast, Section, Subscriber, Vodcast,
    3737    Language, Collector, Widget, Grommet, DooHickey, FancyDoodad, Whatsit,
    3838    Category, Post, Plot, FunkyTag, Chapter, Book, Promo, WorkHour, Employee,
     
    5050    # this test case and changing urlbit.
    5151    urlbit = 'admin'
    5252
     53    urls = "regressiontests.admin_views.urls"
     54
    5355    def setUp(self):
    5456        self.old_USE_I18N = settings.USE_I18N
    5557        self.old_USE_L10N = settings.USE_L10N
     
    301303            response.content.index(link % l1.pk) < response.content.index(link % l2.pk)
    302304        )
    303305
    304     def testChangeListSortingModelAdmin(self):
     306    def testChangeListSortingOverrideModelAdmin(self):
    305307        # Test ordering on Model Admin is respected, and overrides Model Meta
    306308        dt = datetime.datetime.now()
    307309        p1 = Podcast.objects.create(name="A", release_date=dt)
     
    542544            self.fail("Filters should be allowed if they are defined on a ForeignKey pointing to this model")
    543545
    544546class AdminJavaScriptTest(AdminViewBasicTest):
     547    urls = "regressiontests.admin_views.urls"
     548
    545549    def testSingleWidgetFirsFieldFocus(self):
    546550        """
    547551        JavaScript-assisted auto-focus on first field.
     
    565569
    566570
    567571class SaveAsTests(TestCase):
     572    urls = "regressiontests.admin_views.urls"
    568573    fixtures = ['admin-views-users.xml','admin-views-person.xml']
    569574
    570575    def setUp(self):
     
    593598        self.assertEqual(response.context['form_url'], '../add/')
    594599
    595600class CustomModelAdminTest(AdminViewBasicTest):
     601    urls = "regressiontests.admin_views.urls"
    596602    urlbit = "admin2"
    597603
    598604    def testCustomAdminSiteLoginForm(self):
     
    654660class AdminViewPermissionsTest(TestCase):
    655661    """Tests for Admin Views Permissions."""
    656662
     663    urls = "regressiontests.admin_views.urls"
    657664    fixtures = ['admin-views-users.xml']
    658665
    659666    def setUp(self):
     
    10551062
    10561063
    10571064class AdminViewDeletedObjectsTest(TestCase):
     1065    urls = "regressiontests.admin_views.urls"
    10581066    fixtures = ['admin-views-users.xml', 'deleted-objects.xml']
    10591067
    10601068    def setUp(self):
     
    11701178        self.assertContains(response, should_contain)
    11711179
    11721180class AdminViewStringPrimaryKeyTest(TestCase):
     1181    urls = "regressiontests.admin_views.urls"
    11731182    fixtures = ['admin-views-users.xml', 'string-primary-key.xml']
    11741183
    11751184    def __init__(self, *args):
     
    12611270
    12621271
    12631272class SecureViewTests(TestCase):
     1273    urls = "regressiontests.admin_views.urls"
    12641274    fixtures = ['admin-views-users.xml']
    12651275
    12661276    def setUp(self):
     
    14181428        self.assertEqual(response['Location'], 'http://example.com/users/super/')
    14191429
    14201430class AdminViewUnicodeTest(TestCase):
     1431    urls = "regressiontests.admin_views.urls"
    14211432    fixtures = ['admin-views-unicode.xml']
    14221433
    14231434    def setUp(self):
     
    14711482
    14721483
    14731484class AdminViewListEditable(TestCase):
     1485    urls = "regressiontests.admin_views.urls"
    14741486    fixtures = ['admin-views-users.xml', 'admin-views-person.xml']
    14751487
    14761488    def setUp(self):
     
    18271839
    18281840
    18291841class AdminSearchTest(TestCase):
     1842    urls = "regressiontests.admin_views.urls"
    18301843    fixtures = ['admin-views-users', 'multiple-child-classes',
    18311844                'admin-views-person']
    18321845
     
    18731886
    18741887
    18751888class AdminInheritedInlinesTest(TestCase):
     1889    urls = "regressiontests.admin_views.urls"
    18761890    fixtures = ['admin-views-users.xml',]
    18771891
    18781892    def setUp(self):
     
    19581972        self.assertEqual(Persona.objects.all()[0].accounts.count(), 2)
    19591973
    19601974class AdminActionsTest(TestCase):
     1975    urls = "regressiontests.admin_views.urls"
    19611976    fixtures = ['admin-views-users.xml', 'admin-views-actions.xml']
    19621977
    19631978    def setUp(self):
     
    21792194
    21802195
    21812196class TestCustomChangeList(TestCase):
     2197    urls = "regressiontests.admin_views.urls"
    21822198    fixtures = ['admin-views-users.xml']
    21832199    urlbit = 'admin'
    21842200
     
    22062222
    22072223
    22082224class TestInlineNotEditable(TestCase):
     2225    urls = "regressiontests.admin_views.urls"
    22092226    fixtures = ['admin-views-users.xml']
    22102227
    22112228    def setUp(self):
     
    22232240        self.assertEqual(response.status_code, 200)
    22242241
    22252242class AdminCustomQuerysetTest(TestCase):
     2243    urls = "regressiontests.admin_views.urls"
    22262244    fixtures = ['admin-views-users.xml']
    22272245
    22282246    def setUp(self):
     
    22772295        self.assertContains(response, '<li class="info">The cover letter &quot;John Doe II&quot; was changed successfully.</li>')
    22782296
    22792297class AdminInlineFileUploadTest(TestCase):
     2298    urls = "regressiontests.admin_views.urls"
    22802299    fixtures = ['admin-views-users.xml', 'admin-views-actions.xml']
    22812300    urlbit = 'admin'
    22822301
     
    23222341
    23232342
    23242343class AdminInlineTests(TestCase):
     2344    urls = "regressiontests.admin_views.urls"
    23252345    fixtures = ['admin-views-users.xml']
    23262346
    23272347    def setUp(self):
     
    26392659
    26402660
    26412661class NeverCacheTests(TestCase):
     2662    urls = "regressiontests.admin_views.urls"
    26422663    fixtures = ['admin-views-users.xml', 'admin-views-colors.xml', 'admin-views-fabrics.xml']
    26432664
    26442665    def setUp(self):
     
    27112732
    27122733
    27132734class PrePopulatedTest(TestCase):
     2735    urls = "regressiontests.admin_views.urls"
    27142736    fixtures = ['admin-views-users.xml']
    27152737
    27162738    def setUp(self):
     
    27352757        self.assertNotContains(response, "id: '#id_prepopulatedsubpost_set-0-subslug',")
    27362758
    27372759class ReadonlyTest(TestCase):
     2760    urls = "regressiontests.admin_views.urls"
    27382761    fixtures = ['admin-views-users.xml']
    27392762
    27402763    def setUp(self):
     
    28022825
    28032826
    28042827class RawIdFieldsTest(TestCase):
     2828    urls = "regressiontests.admin_views.urls"
    28052829    fixtures = ['admin-views-users.xml']
    28062830
    28072831    def setUp(self):
     
    28372861    """
    28382862    Tests user CRUD functionality.
    28392863    """
     2864    urls = "regressiontests.admin_views.urls"
    28402865    fixtures = ['admin-views-users.xml']
    28412866
    28422867    def setUp(self):
     
    29282953    """
    29292954    Tests group CRUD functionality.
    29302955    """
     2956    urls = "regressiontests.admin_views.urls"
    29312957    fixtures = ['admin-views-users.xml']
    29322958
    29332959    def setUp(self):
     
    29612987
    29622988#@unittest.skipUnless(docutils, "no docutils installed.")
    29632989class AdminDocsTest(TestCase):
     2990    urls = "regressiontests.admin_views.urls"
    29642991    fixtures = ['admin-views-users.xml']
    29652992
    29662993    def setUp(self):
     
    30033030AdminDocsTest = unittest.skipUnless(docutils, "no docutils installed.")(AdminDocsTest)
    30043031
    30053032class ValidXHTMLTests(TestCase):
     3033    urls = "regressiontests.admin_views.urls"
    30063034    fixtures = ['admin-views-users.xml']
    30073035    urlbit = 'admin'
    30083036
     
    30333061
    30343062
    30353063class DateHierarchyTests(TestCase):
     3064    urls = "regressiontests.admin_views.urls"
    30363065    fixtures = ['admin-views-users.xml']
    30373066
    30383067    def setUp(self):
     
    31623191    Ensure that one can easily customize the way related objects are saved.
    31633192    Refs #16115.
    31643193    """
     3194    urls = "regressiontests.admin_views.urls"
    31653195    fixtures = ['admin-views-users.xml']
    31663196
    31673197    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  
    11from django.conf.urls import patterns, include
    2 from django.contrib import admin
    32import views
    43import customadmin
     4import admin
    55
    66urlpatterns = 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)),
    1111)
  • tests/regressiontests/cache/tests.py

    diff --git a/tests/regressiontests/cache/tests.py b/tests/regressiontests/cache/tests.py
    a b  
    15911591
    15921592class TestEtagWithAdmin(TestCase):
    15931593    # See https://code.djangoproject.com/ticket/16003
     1594    urls = "regressiontests.admin_views.urls"
     1595
    15941596    def test_admin(self):
    15951597        with self.settings(USE_ETAGS=False):
    15961598            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
    - +  
     1from django.contrib import admin
     2from django.contrib.contenttypes import generic
     3
     4from models import (Media, PhoneNumber, Episode, EpisodeExtra, Contact,
     5    Category, EpisodePermanent, EpisodeMaxNum)
     6
     7site = admin.AdminSite(name="admin")
     8
     9class MediaInline(generic.GenericTabularInline):
     10    model = Media
     11
     12
     13class EpisodeAdmin(admin.ModelAdmin):
     14    inlines = [
     15        MediaInline,
     16    ]
     17
     18
     19class MediaExtraInline(generic.GenericTabularInline):
     20    model = Media
     21    extra = 0
     22
     23
     24class MediaMaxNumInline(generic.GenericTabularInline):
     25    model = Media
     26    extra = 5
     27    max_num = 2
     28
     29
     30class PhoneNumberInline(generic.GenericTabularInline):
     31    model = PhoneNumber
     32
     33
     34class MediaPermanentInline(generic.GenericTabularInline):
     35    model = Media
     36    can_delete = False
     37
     38
     39site.register(Episode, EpisodeAdmin)
     40site.register(EpisodeExtra, inlines=[MediaExtraInline])
     41site.register(EpisodeMaxNum, inlines=[MediaMaxNumInline])
     42site.register(Contact, inlines=[PhoneNumberInline])
     43site.register(Category)
     44site.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  
    11from django.db import models
    2 from django.contrib import admin
    32from django.contrib.contenttypes import generic
    43from django.contrib.contenttypes.models import ContentType
    54
     5
    66class Episode(models.Model):
    77    name = models.CharField(max_length=100)
    88    length = models.CharField(max_length=100, blank=True)
    99    author = models.CharField(max_length=100, blank=True)
    1010
     11
    1112class Media(models.Model):
    1213    """
    1314    Media that can associated to any object.
     
    2223    def __unicode__(self):
    2324        return self.url
    2425
    25 class MediaInline(generic.GenericTabularInline):
    26     model = Media
    27 
    28 class EpisodeAdmin(admin.ModelAdmin):
    29     inlines = [
    30         MediaInline,
    31     ]
    32 admin.site.register(Episode, EpisodeAdmin)
    33 
    3426#
    3527# These models let us test the different GenericInline settings at
    3628# different urls in the admin site.
     
    4335class EpisodeExtra(Episode):
    4436    pass
    4537
    46 class MediaExtraInline(generic.GenericTabularInline):
    47     model = Media
    48     extra = 0
    49 
    50 admin.site.register(EpisodeExtra, inlines=[MediaExtraInline])
    5138
    5239#
    5340# Generic inline with extra and max_num
    5441#
    55 
    5642class EpisodeMaxNum(Episode):
    5743    pass
    5844
    59 class MediaMaxNumInline(generic.GenericTabularInline):
    60     model = Media
    61     extra = 5
    62     max_num = 2
    63 
    64 admin.site.register(EpisodeMaxNum, inlines=[MediaMaxNumInline])
    65 
    6645
    6746#
    6847# Generic inline with unique_together
    6948#
    70 
    7149class Category(models.Model):
    7250    name = models.CharField(max_length=50)
    7351
     52
    7453class PhoneNumber(models.Model):
    7554    content_type = models.ForeignKey(ContentType)
    7655    object_id = models.PositiveIntegerField()
     
    8160    class Meta:
    8261        unique_together = (('content_type', 'object_id', 'phone_number',),)
    8362
     63
    8464class Contact(models.Model):
    8565    name = models.CharField(max_length=50)
    8666    phone_numbers = generic.GenericRelation(PhoneNumber)
    8767
    88 class PhoneNumberInline(generic.GenericTabularInline):
    89     model = PhoneNumber
    90 
    91 admin.site.register(Contact, inlines=[PhoneNumberInline])
    92 admin.site.register(Category)
    93 
    9468#
    9569# Generic inline with can_delete=False
    9670#
    97 
    9871class EpisodePermanent(Episode):
    9972    pass
    10073
    101 class MediaPermanentInline(generic.GenericTabularInline):
    102     model = Media
    103     can_delete = False
    10474
    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  
    1010
    1111# local test models
    1212from models import (Episode, EpisodeExtra, EpisodeMaxNum, Media,
    13     MediaInline, EpisodePermanent, MediaPermanentInline, Category)
     13    EpisodePermanent, Category)
     14from admin import MediaInline, MediaPermanentInline
    1415
    1516
    1617class GenericAdminViewTest(TestCase):
     18    urls = "regressiontests.generic_inline_admin.urls"
    1719    fixtures = ['users.xml']
    1820
    1921    def setUp(self):
     
    125127        self.assertTrue(formset.get_queryset().ordered)
    126128
    127129class GenericInlineAdminParametersTest(TestCase):
     130    urls = "regressiontests.generic_inline_admin.urls"
    128131    fixtures = ['users.xml']
    129132
    130133    def setUp(self):
     
    177180
    178181
    179182class GenericInlineAdminWithUniqueTogetherTest(TestCase):
     183    urls = "regressiontests.generic_inline_admin.urls"
    180184    fixtures = ['users.xml']
    181185
    182186    def setUp(self):
     
    203207        self.assertEqual(response.status_code, 302) # redirect somewhere
    204208
    205209class NoInlineDeletionTest(TestCase):
     210    urls = "regressiontests.generic_inline_admin.urls"
     211
    206212    def test_no_deletion(self):
    207213        fake_site = object()
    208214        inline = MediaPermanentInline(EpisodePermanent, fake_site)
     
    211217        self.assertFalse(formset.can_delete)
    212218
    213219class GenericInlineModelAdminTest(TestCase):
     220    urls = "regressiontests.generic_inline_admin.urls"
    214221
    215222    def setUp(self):
    216223        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  
    11from django.conf.urls import patterns, include
    2 from django.contrib import admin
     2
     3import admin
    34
    45urlpatterns = patterns('',
    5     (r'^admin/', include(admin.site.urls)),
     6    (r'^generic_inline_admin/admin/', include(admin.site.urls)),
    67)
  • tests/urls.py

    diff --git a/tests/urls.py b/tests/urls.py
    a b  
    2222    # test urlconf for middleware tests
    2323    (r'^middleware/', include('regressiontests.middleware.urls')),
    2424
    25     # admin view tests
    26     (r'^test_admin/', include('regressiontests.admin_views.urls')),
    27     (r'^generic_inline_admin/', include('regressiontests.generic_inline_admin.urls')),
    28 
    2925    # admin widget tests
    3026    (r'widget_admin/', include('regressiontests.admin_widgets.urls')),
    3127
Back to Top