App Engine Python SDK version 1.7.4 (2)
[gae.git] / python / lib / django_1_4 / tests / regressiontests / admin_views / admin.py
blob3369c557b7d5f411a4ae0b35d53153c0fee4bc8a
1 # -*- coding: utf-8 -*-
2 from __future__ import absolute_import
4 import tempfile
5 import os
7 from django import forms
8 from django.contrib import admin
9 from django.contrib.admin.views.main import ChangeList
10 from django.core.files.storage import FileSystemStorage
11 from django.core.mail import EmailMessage
12 from django.conf.urls import patterns, url
13 from django.db import models
14 from django.forms.models import BaseModelFormSet
15 from django.http import HttpResponse
16 from django.contrib.admin import BooleanFieldListFilter
18 from .models import (Article, Chapter, Account, Media, Child, Parent, Picture,
19 Widget, DooHickey, Grommet, Whatsit, FancyDoodad, Category, Link,
20 PrePopulatedPost, PrePopulatedSubPost, CustomArticle, Section,
21 ModelWithStringPrimaryKey, Color, Thing, Actor, Inquisition, Sketch, Person,
22 Persona, Subscriber, ExternalSubscriber, OldSubscriber, Vodcast, EmptyModel,
23 Fabric, Gallery, Language, Recommendation, Recommender, Collector, Post,
24 Gadget, Villain, SuperVillain, Plot, PlotDetails, CyclicOne, CyclicTwo,
25 WorkHour, Reservation, FoodDelivery, RowLevelChangePermissionModel, Paper,
26 CoverLetter, Story, OtherStory, Book, Promo, ChapterXtra1, Pizza, Topping,
27 Album, Question, Answer, ComplexSortedPerson, PrePopulatedPostLargeSlug,
28 AdminOrderedField, AdminOrderedModelMethod, AdminOrderedAdminMethod,
29 AdminOrderedCallable, Report, Color2, UnorderedObject, MainPrepopulated,
30 RelatedPrepopulated)
33 def callable_year(dt_value):
34 return dt_value.year
35 callable_year.admin_order_field = 'date'
38 class ArticleInline(admin.TabularInline):
39 model = Article
40 prepopulated_fields = {
41 'title' : ('content',)
43 fieldsets=(
44 ('Some fields', {
45 'classes': ('collapse',),
46 'fields': ('title', 'content')
47 }),
48 ('Some other fields', {
49 'classes': ('wide',),
50 'fields': ('date', 'section')
54 class ChapterInline(admin.TabularInline):
55 model = Chapter
58 class ChapterXtra1Admin(admin.ModelAdmin):
59 list_filter = ('chap',
60 'chap__title',
61 'chap__book',
62 'chap__book__name',
63 'chap__book__promo',
64 'chap__book__promo__name',)
67 class ArticleAdmin(admin.ModelAdmin):
68 list_display = ('content', 'date', callable_year, 'model_year', 'modeladmin_year')
69 list_filter = ('date', 'section')
71 def changelist_view(self, request):
72 "Test that extra_context works"
73 return super(ArticleAdmin, self).changelist_view(
74 request, extra_context={
75 'extra_var': 'Hello!'
79 def modeladmin_year(self, obj):
80 return obj.date.year
81 modeladmin_year.admin_order_field = 'date'
82 modeladmin_year.short_description = None
84 def delete_model(self, request, obj):
85 EmailMessage(
86 'Greetings from a deleted object',
87 'I hereby inform you that some user deleted me',
88 'from@example.com',
89 ['to@example.com']
90 ).send()
91 return super(ArticleAdmin, self).delete_model(request, obj)
93 def save_model(self, request, obj, form, change=True):
94 EmailMessage(
95 'Greetings from a created object',
96 'I hereby inform you that some user created me',
97 'from@example.com',
98 ['to@example.com']
99 ).send()
100 return super(ArticleAdmin, self).save_model(request, obj, form, change)
103 class RowLevelChangePermissionModelAdmin(admin.ModelAdmin):
104 def has_change_permission(self, request, obj=None):
105 """ Only allow changing objects with even id number """
106 return request.user.is_staff and (obj is not None) and (obj.id % 2 == 0)
109 class CustomArticleAdmin(admin.ModelAdmin):
111 Tests various hooks for using custom templates and contexts.
113 change_list_template = 'custom_admin/change_list.html'
114 change_form_template = 'custom_admin/change_form.html'
115 add_form_template = 'custom_admin/add_form.html'
116 object_history_template = 'custom_admin/object_history.html'
117 delete_confirmation_template = 'custom_admin/delete_confirmation.html'
118 delete_selected_confirmation_template = 'custom_admin/delete_selected_confirmation.html'
120 def changelist_view(self, request):
121 "Test that extra_context works"
122 return super(CustomArticleAdmin, self).changelist_view(
123 request, extra_context={
124 'extra_var': 'Hello!'
129 class ThingAdmin(admin.ModelAdmin):
130 list_filter = ('color__warm', 'color__value', 'pub_date',)
133 class InquisitionAdmin(admin.ModelAdmin):
134 list_display = ('leader', 'country', 'expected')
137 class SketchAdmin(admin.ModelAdmin):
138 raw_id_fields = ('inquisition',)
141 class FabricAdmin(admin.ModelAdmin):
142 list_display = ('surface',)
143 list_filter = ('surface',)
146 class BasePersonModelFormSet(BaseModelFormSet):
147 def clean(self):
148 for person_dict in self.cleaned_data:
149 person = person_dict.get('id')
150 alive = person_dict.get('alive')
151 if person and alive and person.name == "Grace Hopper":
152 raise forms.ValidationError("Grace is not a Zombie")
155 class PersonAdmin(admin.ModelAdmin):
156 list_display = ('name', 'gender', 'alive')
157 list_editable = ('gender', 'alive')
158 list_filter = ('gender',)
159 search_fields = ('^name',)
160 save_as = True
162 def get_changelist_formset(self, request, **kwargs):
163 return super(PersonAdmin, self).get_changelist_formset(request,
164 formset=BasePersonModelFormSet, **kwargs)
166 def queryset(self, request):
167 # Order by a field that isn't in list display, to be able to test
168 # whether ordering is preserved.
169 return super(PersonAdmin, self).queryset(request).order_by('age')
172 class FooAccount(Account):
173 """A service-specific account of type Foo."""
174 servicename = u'foo'
177 class BarAccount(Account):
178 """A service-specific account of type Bar."""
179 servicename = u'bar'
182 class FooAccountAdmin(admin.StackedInline):
183 model = FooAccount
184 extra = 1
187 class BarAccountAdmin(admin.StackedInline):
188 model = BarAccount
189 extra = 1
192 class PersonaAdmin(admin.ModelAdmin):
193 inlines = (
194 FooAccountAdmin,
195 BarAccountAdmin
199 class SubscriberAdmin(admin.ModelAdmin):
200 actions = ['mail_admin']
202 def mail_admin(self, request, selected):
203 EmailMessage(
204 'Greetings from a ModelAdmin action',
205 'This is the test email from a admin action',
206 'from@example.com',
207 ['to@example.com']
208 ).send()
211 def external_mail(modeladmin, request, selected):
212 EmailMessage(
213 'Greetings from a function action',
214 'This is the test email from a function action',
215 'from@example.com',
216 ['to@example.com']
217 ).send()
218 external_mail.short_description = 'External mail (Another awesome action)'
221 def redirect_to(modeladmin, request, selected):
222 from django.http import HttpResponseRedirect
223 return HttpResponseRedirect('/some-where-else/')
224 redirect_to.short_description = 'Redirect to (Awesome action)'
227 class ExternalSubscriberAdmin(admin.ModelAdmin):
228 actions = [redirect_to, external_mail]
231 class Podcast(Media):
232 release_date = models.DateField()
234 class Meta:
235 ordering = ('release_date',) # overridden in PodcastAdmin
238 class PodcastAdmin(admin.ModelAdmin):
239 list_display = ('name', 'release_date')
240 list_editable = ('release_date',)
241 date_hierarchy = 'release_date'
242 ordering = ('name',)
245 class VodcastAdmin(admin.ModelAdmin):
246 list_display = ('name', 'released')
247 list_editable = ('released',)
249 ordering = ('name',)
252 class ChildInline(admin.StackedInline):
253 model = Child
256 class ParentAdmin(admin.ModelAdmin):
257 model = Parent
258 inlines = [ChildInline]
260 list_editable = ('name',)
262 def save_related(self, request, form, formsets, change):
263 super(ParentAdmin, self).save_related(request, form, formsets, change)
264 first_name, last_name = form.instance.name.split()
265 for child in form.instance.child_set.all():
266 if len(child.name.split()) < 2:
267 child.name = child.name + ' ' + last_name
268 child.save()
271 class EmptyModelAdmin(admin.ModelAdmin):
272 def queryset(self, request):
273 return super(EmptyModelAdmin, self).queryset(request).filter(pk__gt=1)
276 class OldSubscriberAdmin(admin.ModelAdmin):
277 actions = None
280 temp_storage = FileSystemStorage(tempfile.mkdtemp(dir=os.environ['DJANGO_TEST_TEMP_DIR']))
281 UPLOAD_TO = os.path.join(temp_storage.location, 'test_upload')
284 class PictureInline(admin.TabularInline):
285 model = Picture
286 extra = 1
289 class GalleryAdmin(admin.ModelAdmin):
290 inlines = [PictureInline]
293 class PictureAdmin(admin.ModelAdmin):
294 pass
297 class LanguageAdmin(admin.ModelAdmin):
298 list_display = ['iso', 'shortlist', 'english_name', 'name']
299 list_editable = ['shortlist']
302 class RecommendationAdmin(admin.ModelAdmin):
303 search_fields = ('=titletranslation__text', '=recommender__titletranslation__text',)
306 class WidgetInline(admin.StackedInline):
307 model = Widget
310 class DooHickeyInline(admin.StackedInline):
311 model = DooHickey
314 class GrommetInline(admin.StackedInline):
315 model = Grommet
318 class WhatsitInline(admin.StackedInline):
319 model = Whatsit
322 class FancyDoodadInline(admin.StackedInline):
323 model = FancyDoodad
326 class CategoryAdmin(admin.ModelAdmin):
327 list_display = ('id', 'collector', 'order')
328 list_editable = ('order',)
331 class CategoryInline(admin.StackedInline):
332 model = Category
335 class CollectorAdmin(admin.ModelAdmin):
336 inlines = [
337 WidgetInline, DooHickeyInline, GrommetInline, WhatsitInline,
338 FancyDoodadInline, CategoryInline
342 class LinkInline(admin.TabularInline):
343 model = Link
344 extra = 1
346 readonly_fields = ("posted",)
349 class SubPostInline(admin.TabularInline):
350 model = PrePopulatedSubPost
352 prepopulated_fields = {
353 'subslug' : ('subtitle',)
356 def get_readonly_fields(self, request, obj=None):
357 if obj and obj.published:
358 return ('subslug',)
359 return self.readonly_fields
361 def get_prepopulated_fields(self, request, obj=None):
362 if obj and obj.published:
363 return {}
364 return self.prepopulated_fields
367 class PrePopulatedPostAdmin(admin.ModelAdmin):
368 list_display = ['title', 'slug']
369 prepopulated_fields = {
370 'slug' : ('title',)
373 inlines = [SubPostInline]
375 def get_readonly_fields(self, request, obj=None):
376 if obj and obj.published:
377 return ('slug',)
378 return self.readonly_fields
380 def get_prepopulated_fields(self, request, obj=None):
381 if obj and obj.published:
382 return {}
383 return self.prepopulated_fields
386 class PostAdmin(admin.ModelAdmin):
387 list_display = ['title', 'public']
388 readonly_fields = ('posted', 'awesomeness_level', 'coolness', 'value', lambda obj: "foo")
390 inlines = [
391 LinkInline
394 def coolness(self, instance):
395 if instance.pk:
396 return "%d amount of cool." % instance.pk
397 else:
398 return "Unkown coolness."
400 def value(self, instance):
401 return 1000
402 value.short_description = 'Value in $US'
405 class CustomChangeList(ChangeList):
406 def get_query_set(self, request):
407 return self.root_query_set.filter(pk=9999) # Does not exist
410 class GadgetAdmin(admin.ModelAdmin):
411 def get_changelist(self, request, **kwargs):
412 return CustomChangeList
415 class PizzaAdmin(admin.ModelAdmin):
416 readonly_fields = ('toppings',)
419 class WorkHourAdmin(admin.ModelAdmin):
420 list_display = ('datum', 'employee')
421 list_filter = ('employee',)
424 class FoodDeliveryAdmin(admin.ModelAdmin):
425 list_display=('reference', 'driver', 'restaurant')
426 list_editable = ('driver', 'restaurant')
429 class PaperAdmin(admin.ModelAdmin):
431 A ModelAdmin with a custom queryset() method that uses only(), to test
432 verbose_name display in messages shown after adding Paper instances.
435 def queryset(self, request):
436 return super(PaperAdmin, self).queryset(request).only('title')
439 class CoverLetterAdmin(admin.ModelAdmin):
441 A ModelAdmin with a custom queryset() method that uses only(), to test
442 verbose_name display in messages shown after adding CoverLetter instances.
443 Note that the CoverLetter model defines a __unicode__ method.
446 def queryset(self, request):
447 return super(CoverLetterAdmin, self).queryset(request).defer('date_written')
450 class StoryForm(forms.ModelForm):
451 class Meta:
452 widgets = {'title': forms.HiddenInput}
455 class StoryAdmin(admin.ModelAdmin):
456 list_display = ('id', 'title', 'content')
457 list_display_links = ('title',) # 'id' not in list_display_links
458 list_editable = ('content', )
459 form = StoryForm
460 ordering = ["-pk"]
463 class OtherStoryAdmin(admin.ModelAdmin):
464 list_display = ('id', 'title', 'content')
465 list_display_links = ('title', 'id') # 'id' in list_display_links
466 list_editable = ('content', )
467 ordering = ["-pk"]
470 class ComplexSortedPersonAdmin(admin.ModelAdmin):
471 list_display = ('name', 'age', 'is_employee', 'colored_name')
472 ordering = ('name',)
474 def colored_name(self, obj):
475 return '<span style="color: #%s;">%s</span>' % ('ff00ff', obj.name)
476 colored_name.allow_tags = True
477 colored_name.admin_order_field = 'name'
480 class AlbumAdmin(admin.ModelAdmin):
481 list_filter = ['title']
484 class WorkHourAdmin(admin.ModelAdmin):
485 list_display = ('datum', 'employee')
486 list_filter = ('employee',)
489 class PrePopulatedPostLargeSlugAdmin(admin.ModelAdmin):
490 prepopulated_fields = {
491 'slug' : ('title',)
495 class AdminOrderedFieldAdmin(admin.ModelAdmin):
496 ordering = ('order',)
497 list_display = ('stuff', 'order')
499 class AdminOrderedModelMethodAdmin(admin.ModelAdmin):
500 ordering = ('order',)
501 list_display = ('stuff', 'some_order')
503 class AdminOrderedAdminMethodAdmin(admin.ModelAdmin):
504 def some_admin_order(self, obj):
505 return obj.order
506 some_admin_order.admin_order_field = 'order'
507 ordering = ('order',)
508 list_display = ('stuff', 'some_admin_order')
510 def admin_ordered_callable(obj):
511 return obj.order
512 admin_ordered_callable.admin_order_field = 'order'
513 class AdminOrderedCallableAdmin(admin.ModelAdmin):
514 ordering = ('order',)
515 list_display = ('stuff', admin_ordered_callable)
517 class ReportAdmin(admin.ModelAdmin):
518 def extra(self, request):
519 return HttpResponse()
521 def get_urls(self):
522 # Corner case: Don't call parent implementation
523 return patterns('',
524 url(r'^extra/$',
525 self.extra,
526 name='cable_extra'),
530 class CustomTemplateBooleanFieldListFilter(BooleanFieldListFilter):
531 template = 'custom_filter_template.html'
533 class CustomTemplateFilterColorAdmin(admin.ModelAdmin):
534 list_filter = (('warm', CustomTemplateBooleanFieldListFilter),)
537 # For Selenium Prepopulated tests -------------------------------------
538 class RelatedPrepopulatedInline1(admin.StackedInline):
539 fieldsets = (
540 (None, {
541 'fields': (('pubdate', 'status'), ('name', 'slug1', 'slug2',),)
544 model = RelatedPrepopulated
545 extra = 1
546 prepopulated_fields = {'slug1': ['name', 'pubdate'],
547 'slug2': ['status', 'name']}
549 class RelatedPrepopulatedInline2(admin.TabularInline):
550 model = RelatedPrepopulated
551 extra = 1
552 prepopulated_fields = {'slug1': ['name', 'pubdate'],
553 'slug2': ['status', 'name']}
555 class MainPrepopulatedAdmin(admin.ModelAdmin):
556 inlines = [RelatedPrepopulatedInline1, RelatedPrepopulatedInline2]
557 fieldsets = (
558 (None, {
559 'fields': (('pubdate', 'status'), ('name', 'slug1', 'slug2',),)
562 prepopulated_fields = {'slug1': ['name', 'pubdate'],
563 'slug2': ['status', 'name']}
566 class UnorderedObjectAdmin(admin.ModelAdmin):
567 list_display = ['name']
568 list_editable = ['name']
569 list_per_page = 2
573 site = admin.AdminSite(name="admin")
574 site.register(Article, ArticleAdmin)
575 site.register(CustomArticle, CustomArticleAdmin)
576 site.register(Section, save_as=True, inlines=[ArticleInline])
577 site.register(ModelWithStringPrimaryKey)
578 site.register(Color)
579 site.register(Thing, ThingAdmin)
580 site.register(Actor)
581 site.register(Inquisition, InquisitionAdmin)
582 site.register(Sketch, SketchAdmin)
583 site.register(Person, PersonAdmin)
584 site.register(Persona, PersonaAdmin)
585 site.register(Subscriber, SubscriberAdmin)
586 site.register(ExternalSubscriber, ExternalSubscriberAdmin)
587 site.register(OldSubscriber, OldSubscriberAdmin)
588 site.register(Podcast, PodcastAdmin)
589 site.register(Vodcast, VodcastAdmin)
590 site.register(Parent, ParentAdmin)
591 site.register(EmptyModel, EmptyModelAdmin)
592 site.register(Fabric, FabricAdmin)
593 site.register(Gallery, GalleryAdmin)
594 site.register(Picture, PictureAdmin)
595 site.register(Language, LanguageAdmin)
596 site.register(Recommendation, RecommendationAdmin)
597 site.register(Recommender)
598 site.register(Collector, CollectorAdmin)
599 site.register(Category, CategoryAdmin)
600 site.register(Post, PostAdmin)
601 site.register(Gadget, GadgetAdmin)
602 site.register(Villain)
603 site.register(SuperVillain)
604 site.register(Plot)
605 site.register(PlotDetails)
606 site.register(CyclicOne)
607 site.register(CyclicTwo)
608 site.register(WorkHour, WorkHourAdmin)
609 site.register(Reservation)
610 site.register(FoodDelivery, FoodDeliveryAdmin)
611 site.register(RowLevelChangePermissionModel, RowLevelChangePermissionModelAdmin)
612 site.register(Paper, PaperAdmin)
613 site.register(CoverLetter, CoverLetterAdmin)
614 site.register(Story, StoryAdmin)
615 site.register(OtherStory, OtherStoryAdmin)
616 site.register(Report, ReportAdmin)
617 site.register(MainPrepopulated, MainPrepopulatedAdmin)
618 site.register(UnorderedObject, UnorderedObjectAdmin)
620 # We intentionally register Promo and ChapterXtra1 but not Chapter nor ChapterXtra2.
621 # That way we cover all four cases:
622 # related ForeignKey object registered in admin
623 # related ForeignKey object not registered in admin
624 # related OneToOne object registered in admin
625 # related OneToOne object not registered in admin
626 # when deleting Book so as exercise all four troublesome (w.r.t escaping
627 # and calling force_unicode to avoid problems on Python 2.3) paths through
628 # contrib.admin.util's get_deleted_objects function.
629 site.register(Book, inlines=[ChapterInline])
630 site.register(Promo)
631 site.register(ChapterXtra1, ChapterXtra1Admin)
632 site.register(Pizza, PizzaAdmin)
633 site.register(Topping)
634 site.register(Album, AlbumAdmin)
635 site.register(Question)
636 site.register(Answer)
637 site.register(PrePopulatedPost, PrePopulatedPostAdmin)
638 site.register(ComplexSortedPerson, ComplexSortedPersonAdmin)
639 site.register(PrePopulatedPostLargeSlug, PrePopulatedPostLargeSlugAdmin)
640 site.register(AdminOrderedField, AdminOrderedFieldAdmin)
641 site.register(AdminOrderedModelMethod, AdminOrderedModelMethodAdmin)
642 site.register(AdminOrderedAdminMethod, AdminOrderedAdminMethodAdmin)
643 site.register(AdminOrderedCallable, AdminOrderedCallableAdmin)
644 site.register(Color2, CustomTemplateFilterColorAdmin)
646 # Register core models we need in our tests
647 from django.contrib.auth.models import User, Group
648 from django.contrib.auth.admin import UserAdmin, GroupAdmin
649 site.register(User, UserAdmin)
650 site.register(Group, GroupAdmin)