--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/parts/django/tests/regressiontests/admin_views/models.py Sat Jan 08 11:20:57 2011 +0530
@@ -0,0 +1,636 @@
+# -*- coding: utf-8 -*-
+import datetime
+import tempfile
+import os
+
+from django.contrib import admin
+from django.core.files.storage import FileSystemStorage
+from django.contrib.admin.views.main import ChangeList
+from django.core.mail import EmailMessage
+from django.db import models
+from django import forms
+from django.forms.models import BaseModelFormSet
+from django.contrib.auth.models import User
+from django.contrib.contenttypes import generic
+from django.contrib.contenttypes.models import ContentType
+
+class Section(models.Model):
+ """
+ A simple section that links to articles, to test linking to related items
+ in admin views.
+ """
+ name = models.CharField(max_length=100)
+
+class Article(models.Model):
+ """
+ A simple article to test admin views. Test backwards compatibility.
+ """
+ title = models.CharField(max_length=100)
+ content = models.TextField()
+ date = models.DateTimeField()
+ section = models.ForeignKey(Section, null=True, blank=True)
+
+ def __unicode__(self):
+ return self.title
+
+ def model_year(self):
+ return self.date.year
+ model_year.admin_order_field = 'date'
+ model_year.short_description = ''
+
+class Book(models.Model):
+ """
+ A simple book that has chapters.
+ """
+ name = models.CharField(max_length=100, verbose_name=u'¿Name?')
+
+ def __unicode__(self):
+ return self.name
+
+class Promo(models.Model):
+ name = models.CharField(max_length=100, verbose_name=u'¿Name?')
+ book = models.ForeignKey(Book)
+
+ def __unicode__(self):
+ return self.name
+
+class Chapter(models.Model):
+ title = models.CharField(max_length=100, verbose_name=u'¿Title?')
+ content = models.TextField()
+ book = models.ForeignKey(Book)
+
+ def __unicode__(self):
+ return self.title
+
+ class Meta:
+ # Use a utf-8 bytestring to ensure it works (see #11710)
+ verbose_name = '¿Chapter?'
+
+class ChapterXtra1(models.Model):
+ chap = models.OneToOneField(Chapter, verbose_name=u'¿Chap?')
+ xtra = models.CharField(max_length=100, verbose_name=u'¿Xtra?')
+
+ def __unicode__(self):
+ return u'¿Xtra1: %s' % self.xtra
+
+class ChapterXtra2(models.Model):
+ chap = models.OneToOneField(Chapter, verbose_name=u'¿Chap?')
+ xtra = models.CharField(max_length=100, verbose_name=u'¿Xtra?')
+
+ def __unicode__(self):
+ return u'¿Xtra2: %s' % self.xtra
+
+def callable_year(dt_value):
+ return dt_value.year
+callable_year.admin_order_field = 'date'
+
+class ArticleInline(admin.TabularInline):
+ model = Article
+
+class ChapterInline(admin.TabularInline):
+ model = Chapter
+
+class ArticleAdmin(admin.ModelAdmin):
+ list_display = ('content', 'date', callable_year, 'model_year', 'modeladmin_year')
+ list_filter = ('date', 'section')
+
+ def changelist_view(self, request):
+ "Test that extra_context works"
+ return super(ArticleAdmin, self).changelist_view(
+ request, extra_context={
+ 'extra_var': 'Hello!'
+ }
+ )
+
+ def modeladmin_year(self, obj):
+ return obj.date.year
+ modeladmin_year.admin_order_field = 'date'
+ modeladmin_year.short_description = None
+
+class CustomArticle(models.Model):
+ content = models.TextField()
+ date = models.DateTimeField()
+
+class CustomArticleAdmin(admin.ModelAdmin):
+ """
+ Tests various hooks for using custom templates and contexts.
+ """
+ change_list_template = 'custom_admin/change_list.html'
+ change_form_template = 'custom_admin/change_form.html'
+ add_form_template = 'custom_admin/add_form.html'
+ object_history_template = 'custom_admin/object_history.html'
+ delete_confirmation_template = 'custom_admin/delete_confirmation.html'
+ delete_selected_confirmation_template = 'custom_admin/delete_selected_confirmation.html'
+
+ def changelist_view(self, request):
+ "Test that extra_context works"
+ return super(CustomArticleAdmin, self).changelist_view(
+ request, extra_context={
+ 'extra_var': 'Hello!'
+ }
+ )
+
+class ModelWithStringPrimaryKey(models.Model):
+ id = models.CharField(max_length=255, primary_key=True)
+
+ def __unicode__(self):
+ return self.id
+
+class Color(models.Model):
+ value = models.CharField(max_length=10)
+ warm = models.BooleanField()
+ def __unicode__(self):
+ return self.value
+
+class Thing(models.Model):
+ title = models.CharField(max_length=20)
+ color = models.ForeignKey(Color, limit_choices_to={'warm': True})
+ def __unicode__(self):
+ return self.title
+
+class ThingAdmin(admin.ModelAdmin):
+ list_filter = ('color',)
+
+class Fabric(models.Model):
+ NG_CHOICES = (
+ ('Textured', (
+ ('x', 'Horizontal'),
+ ('y', 'Vertical'),
+ )
+ ),
+ ('plain', 'Smooth'),
+ )
+ surface = models.CharField(max_length=20, choices=NG_CHOICES)
+
+class FabricAdmin(admin.ModelAdmin):
+ list_display = ('surface',)
+ list_filter = ('surface',)
+
+class Person(models.Model):
+ GENDER_CHOICES = (
+ (1, "Male"),
+ (2, "Female"),
+ )
+ name = models.CharField(max_length=100)
+ gender = models.IntegerField(choices=GENDER_CHOICES)
+ alive = models.BooleanField()
+
+ def __unicode__(self):
+ return self.name
+
+ class Meta:
+ ordering = ["id"]
+
+class BasePersonModelFormSet(BaseModelFormSet):
+ def clean(self):
+ for person_dict in self.cleaned_data:
+ person = person_dict.get('id')
+ alive = person_dict.get('alive')
+ if person and alive and person.name == "Grace Hopper":
+ raise forms.ValidationError, "Grace is not a Zombie"
+
+class PersonAdmin(admin.ModelAdmin):
+ list_display = ('name', 'gender', 'alive')
+ list_editable = ('gender', 'alive')
+ list_filter = ('gender',)
+ search_fields = (u'name',)
+ ordering = ["id"]
+ save_as = True
+
+ def get_changelist_formset(self, request, **kwargs):
+ return super(PersonAdmin, self).get_changelist_formset(request,
+ formset=BasePersonModelFormSet, **kwargs)
+
+
+class Persona(models.Model):
+ """
+ A simple persona associated with accounts, to test inlining of related
+ accounts which inherit from a common accounts class.
+ """
+ name = models.CharField(blank=False, max_length=80)
+ def __unicode__(self):
+ return self.name
+
+class Account(models.Model):
+ """
+ A simple, generic account encapsulating the information shared by all
+ types of accounts.
+ """
+ username = models.CharField(blank=False, max_length=80)
+ persona = models.ForeignKey(Persona, related_name="accounts")
+ servicename = u'generic service'
+
+ def __unicode__(self):
+ return "%s: %s" % (self.servicename, self.username)
+
+class FooAccount(Account):
+ """A service-specific account of type Foo."""
+ servicename = u'foo'
+
+class BarAccount(Account):
+ """A service-specific account of type Bar."""
+ servicename = u'bar'
+
+class FooAccountAdmin(admin.StackedInline):
+ model = FooAccount
+ extra = 1
+
+class BarAccountAdmin(admin.StackedInline):
+ model = BarAccount
+ extra = 1
+
+class PersonaAdmin(admin.ModelAdmin):
+ inlines = (
+ FooAccountAdmin,
+ BarAccountAdmin
+ )
+
+class Subscriber(models.Model):
+ name = models.CharField(blank=False, max_length=80)
+ email = models.EmailField(blank=False, max_length=175)
+
+ def __unicode__(self):
+ return "%s (%s)" % (self.name, self.email)
+
+class SubscriberAdmin(admin.ModelAdmin):
+ actions = ['mail_admin']
+
+ def mail_admin(self, request, selected):
+ EmailMessage(
+ 'Greetings from a ModelAdmin action',
+ 'This is the test email from a admin action',
+ 'from@example.com',
+ ['to@example.com']
+ ).send()
+
+class ExternalSubscriber(Subscriber):
+ pass
+
+class OldSubscriber(Subscriber):
+ pass
+
+def external_mail(modeladmin, request, selected):
+ EmailMessage(
+ 'Greetings from a function action',
+ 'This is the test email from a function action',
+ 'from@example.com',
+ ['to@example.com']
+ ).send()
+
+def redirect_to(modeladmin, request, selected):
+ from django.http import HttpResponseRedirect
+ return HttpResponseRedirect('/some-where-else/')
+
+class ExternalSubscriberAdmin(admin.ModelAdmin):
+ actions = [external_mail, redirect_to]
+
+class Media(models.Model):
+ name = models.CharField(max_length=60)
+
+class Podcast(Media):
+ release_date = models.DateField()
+
+class PodcastAdmin(admin.ModelAdmin):
+ list_display = ('name', 'release_date')
+ list_editable = ('release_date',)
+
+ ordering = ('name',)
+
+class Vodcast(Media):
+ media = models.OneToOneField(Media, primary_key=True, parent_link=True)
+ released = models.BooleanField(default=False)
+
+class VodcastAdmin(admin.ModelAdmin):
+ list_display = ('name', 'released')
+ list_editable = ('released',)
+
+ ordering = ('name',)
+
+class Parent(models.Model):
+ name = models.CharField(max_length=128)
+
+class Child(models.Model):
+ parent = models.ForeignKey(Parent, editable=False)
+ name = models.CharField(max_length=30, blank=True)
+
+class ChildInline(admin.StackedInline):
+ model = Child
+
+class ParentAdmin(admin.ModelAdmin):
+ model = Parent
+ inlines = [ChildInline]
+
+class EmptyModel(models.Model):
+ def __unicode__(self):
+ return "Primary key = %s" % self.id
+
+class EmptyModelAdmin(admin.ModelAdmin):
+ def queryset(self, request):
+ return super(EmptyModelAdmin, self).queryset(request).filter(pk__gt=1)
+
+class OldSubscriberAdmin(admin.ModelAdmin):
+ actions = None
+
+temp_storage = FileSystemStorage(tempfile.mkdtemp())
+UPLOAD_TO = os.path.join(temp_storage.location, 'test_upload')
+
+class Gallery(models.Model):
+ name = models.CharField(max_length=100)
+
+class Picture(models.Model):
+ name = models.CharField(max_length=100)
+ image = models.FileField(storage=temp_storage, upload_to='test_upload')
+ gallery = models.ForeignKey(Gallery, related_name="pictures")
+
+class PictureInline(admin.TabularInline):
+ model = Picture
+ extra = 1
+
+class GalleryAdmin(admin.ModelAdmin):
+ inlines = [PictureInline]
+
+class PictureAdmin(admin.ModelAdmin):
+ pass
+
+class Language(models.Model):
+ iso = models.CharField(max_length=5, primary_key=True)
+ name = models.CharField(max_length=50)
+ english_name = models.CharField(max_length=50)
+ shortlist = models.BooleanField(default=False)
+
+ class Meta:
+ ordering = ('iso',)
+
+class LanguageAdmin(admin.ModelAdmin):
+ list_display = ['iso', 'shortlist', 'english_name', 'name']
+ list_editable = ['shortlist']
+
+# a base class for Recommender and Recommendation
+class Title(models.Model):
+ pass
+
+class TitleTranslation(models.Model):
+ title = models.ForeignKey(Title)
+ text = models.CharField(max_length=100)
+
+class Recommender(Title):
+ pass
+
+class Recommendation(Title):
+ recommender = models.ForeignKey(Recommender)
+
+class RecommendationAdmin(admin.ModelAdmin):
+ search_fields = ('titletranslation__text', 'recommender__titletranslation__text',)
+
+class Collector(models.Model):
+ name = models.CharField(max_length=100)
+
+class Widget(models.Model):
+ owner = models.ForeignKey(Collector)
+ name = models.CharField(max_length=100)
+
+class DooHickey(models.Model):
+ code = models.CharField(max_length=10, primary_key=True)
+ owner = models.ForeignKey(Collector)
+ name = models.CharField(max_length=100)
+
+class Grommet(models.Model):
+ code = models.AutoField(primary_key=True)
+ owner = models.ForeignKey(Collector)
+ name = models.CharField(max_length=100)
+
+class Whatsit(models.Model):
+ index = models.IntegerField(primary_key=True)
+ owner = models.ForeignKey(Collector)
+ name = models.CharField(max_length=100)
+
+class Doodad(models.Model):
+ name = models.CharField(max_length=100)
+
+class FancyDoodad(Doodad):
+ owner = models.ForeignKey(Collector)
+ expensive = models.BooleanField(default=True)
+
+class WidgetInline(admin.StackedInline):
+ model = Widget
+
+class DooHickeyInline(admin.StackedInline):
+ model = DooHickey
+
+class GrommetInline(admin.StackedInline):
+ model = Grommet
+
+class WhatsitInline(admin.StackedInline):
+ model = Whatsit
+
+class FancyDoodadInline(admin.StackedInline):
+ model = FancyDoodad
+
+class Category(models.Model):
+ collector = models.ForeignKey(Collector)
+ order = models.PositiveIntegerField()
+
+ class Meta:
+ ordering = ('order',)
+
+ def __unicode__(self):
+ return u'%s:o%s' % (self.id, self.order)
+
+class CategoryAdmin(admin.ModelAdmin):
+ list_display = ('id', 'collector', 'order')
+ list_editable = ('order',)
+
+class CategoryInline(admin.StackedInline):
+ model = Category
+
+class CollectorAdmin(admin.ModelAdmin):
+ inlines = [
+ WidgetInline, DooHickeyInline, GrommetInline, WhatsitInline,
+ FancyDoodadInline, CategoryInline
+ ]
+
+class Link(models.Model):
+ posted = models.DateField(
+ default=lambda: datetime.date.today() - datetime.timedelta(days=7)
+ )
+ url = models.URLField()
+ post = models.ForeignKey("Post")
+
+
+class LinkInline(admin.TabularInline):
+ model = Link
+ extra = 1
+
+ readonly_fields = ("posted",)
+
+
+class Post(models.Model):
+ title = models.CharField(max_length=100)
+ content = models.TextField()
+ posted = models.DateField(default=datetime.date.today)
+ public = models.NullBooleanField()
+
+ def awesomeness_level(self):
+ return "Very awesome."
+
+class PostAdmin(admin.ModelAdmin):
+ list_display = ['title', 'public']
+ readonly_fields = ('posted', 'awesomeness_level', 'coolness', 'value', lambda obj: "foo")
+
+ inlines = [
+ LinkInline
+ ]
+
+ def coolness(self, instance):
+ if instance.pk:
+ return "%d amount of cool." % instance.pk
+ else:
+ return "Unkown coolness."
+
+ def value(self, instance):
+ return 1000
+ value.short_description = 'Value in $US'
+
+class Gadget(models.Model):
+ name = models.CharField(max_length=100)
+
+ def __unicode__(self):
+ return self.name
+
+class CustomChangeList(ChangeList):
+ def get_query_set(self):
+ return self.root_query_set.filter(pk=9999) # Does not exist
+
+class GadgetAdmin(admin.ModelAdmin):
+ def get_changelist(self, request, **kwargs):
+ return CustomChangeList
+
+class Villain(models.Model):
+ name = models.CharField(max_length=100)
+
+ def __unicode__(self):
+ return self.name
+
+class SuperVillain(Villain):
+ pass
+
+class FunkyTag(models.Model):
+ "Because we all know there's only one real use case for GFKs."
+ name = models.CharField(max_length=25)
+ content_type = models.ForeignKey(ContentType)
+ object_id = models.PositiveIntegerField()
+ content_object = generic.GenericForeignKey('content_type', 'object_id')
+
+ def __unicode__(self):
+ return self.name
+
+class Plot(models.Model):
+ name = models.CharField(max_length=100)
+ team_leader = models.ForeignKey(Villain, related_name='lead_plots')
+ contact = models.ForeignKey(Villain, related_name='contact_plots')
+ tags = generic.GenericRelation(FunkyTag)
+
+ def __unicode__(self):
+ return self.name
+
+class PlotDetails(models.Model):
+ details = models.CharField(max_length=100)
+ plot = models.OneToOneField(Plot)
+
+ def __unicode__(self):
+ return self.details
+
+class SecretHideout(models.Model):
+ """ Secret! Not registered with the admin! """
+ location = models.CharField(max_length=100)
+ villain = models.ForeignKey(Villain)
+
+ def __unicode__(self):
+ return self.location
+
+class SuperSecretHideout(models.Model):
+ """ Secret! Not registered with the admin! """
+ location = models.CharField(max_length=100)
+ supervillain = models.ForeignKey(SuperVillain)
+
+ def __unicode__(self):
+ return self.location
+
+class CyclicOne(models.Model):
+ name = models.CharField(max_length=25)
+ two = models.ForeignKey('CyclicTwo')
+
+ def __unicode__(self):
+ return self.name
+
+class CyclicTwo(models.Model):
+ name = models.CharField(max_length=25)
+ one = models.ForeignKey(CyclicOne)
+
+ def __unicode__(self):
+ return self.name
+
+class Topping(models.Model):
+ name = models.CharField(max_length=20)
+
+class Pizza(models.Model):
+ name = models.CharField(max_length=20)
+ toppings = models.ManyToManyField('Topping')
+
+class PizzaAdmin(admin.ModelAdmin):
+ readonly_fields = ('toppings',)
+
+class Album(models.Model):
+ owner = models.ForeignKey(User)
+ title = models.CharField(max_length=30)
+
+class AlbumAdmin(admin.ModelAdmin):
+ list_filter = ['title']
+
+admin.site.register(Article, ArticleAdmin)
+admin.site.register(CustomArticle, CustomArticleAdmin)
+admin.site.register(Section, save_as=True, inlines=[ArticleInline])
+admin.site.register(ModelWithStringPrimaryKey)
+admin.site.register(Color)
+admin.site.register(Thing, ThingAdmin)
+admin.site.register(Person, PersonAdmin)
+admin.site.register(Persona, PersonaAdmin)
+admin.site.register(Subscriber, SubscriberAdmin)
+admin.site.register(ExternalSubscriber, ExternalSubscriberAdmin)
+admin.site.register(OldSubscriber, OldSubscriberAdmin)
+admin.site.register(Podcast, PodcastAdmin)
+admin.site.register(Vodcast, VodcastAdmin)
+admin.site.register(Parent, ParentAdmin)
+admin.site.register(EmptyModel, EmptyModelAdmin)
+admin.site.register(Fabric, FabricAdmin)
+admin.site.register(Gallery, GalleryAdmin)
+admin.site.register(Picture, PictureAdmin)
+admin.site.register(Language, LanguageAdmin)
+admin.site.register(Recommendation, RecommendationAdmin)
+admin.site.register(Recommender)
+admin.site.register(Collector, CollectorAdmin)
+admin.site.register(Category, CategoryAdmin)
+admin.site.register(Post, PostAdmin)
+admin.site.register(Gadget, GadgetAdmin)
+admin.site.register(Villain)
+admin.site.register(SuperVillain)
+admin.site.register(Plot)
+admin.site.register(PlotDetails)
+admin.site.register(CyclicOne)
+admin.site.register(CyclicTwo)
+
+# We intentionally register Promo and ChapterXtra1 but not Chapter nor ChapterXtra2.
+# That way we cover all four cases:
+# related ForeignKey object registered in admin
+# related ForeignKey object not registered in admin
+# related OneToOne object registered in admin
+# related OneToOne object not registered in admin
+# when deleting Book so as exercise all four troublesome (w.r.t escaping
+# and calling force_unicode to avoid problems on Python 2.3) paths through
+# contrib.admin.util's get_deleted_objects function.
+admin.site.register(Book, inlines=[ChapterInline])
+admin.site.register(Promo)
+admin.site.register(ChapterXtra1)
+admin.site.register(Pizza, PizzaAdmin)
+admin.site.register(Topping)
+admin.site.register(Album, AlbumAdmin)