/tests/regressiontests/admin_views/models.py
Python | 820 lines | 807 code | 5 blank | 8 comment | 2 complexity | 3fe9c9c214bf9db04ae571402182bb73 MD5 | raw file
1# -*- coding: utf-8 -*- 2import datetime 3import tempfile 4import os 5 6from django.contrib import admin 7from django.core.files.storage import FileSystemStorage 8from django.contrib.admin.views.main import ChangeList 9from django.core.mail import EmailMessage 10from django.db import models 11from django import forms 12from django.forms.models import BaseModelFormSet 13from django.contrib.auth.models import User 14from django.contrib.contenttypes import generic 15from django.contrib.contenttypes.models import ContentType 16 17class Section(models.Model): 18 """ 19 A simple section that links to articles, to test linking to related items 20 in admin views. 21 """ 22 name = models.CharField(max_length=100) 23 24class Article(models.Model): 25 """ 26 A simple article to test admin views. Test backwards compatibility. 27 """ 28 title = models.CharField(max_length=100) 29 content = models.TextField() 30 date = models.DateTimeField() 31 section = models.ForeignKey(Section, null=True, blank=True) 32 33 def __unicode__(self): 34 return self.title 35 36 def model_year(self): 37 return self.date.year 38 model_year.admin_order_field = 'date' 39 model_year.short_description = '' 40 41class Book(models.Model): 42 """ 43 A simple book that has chapters. 44 """ 45 name = models.CharField(max_length=100, verbose_name=u'żName?') 46 47 def __unicode__(self): 48 return self.name 49 50class Promo(models.Model): 51 name = models.CharField(max_length=100, verbose_name=u'żName?') 52 book = models.ForeignKey(Book) 53 54 def __unicode__(self): 55 return self.name 56 57class Chapter(models.Model): 58 title = models.CharField(max_length=100, verbose_name=u'żTitle?') 59 content = models.TextField() 60 book = models.ForeignKey(Book) 61 62 def __unicode__(self): 63 return self.title 64 65 class Meta: 66 # Use a utf-8 bytestring to ensure it works (see #11710) 67 verbose_name = 'żChapter?' 68 69class ChapterXtra1(models.Model): 70 chap = models.OneToOneField(Chapter, verbose_name=u'żChap?') 71 xtra = models.CharField(max_length=100, verbose_name=u'żXtra?') 72 73 def __unicode__(self): 74 return u'żXtra1: %s' % self.xtra 75 76class ChapterXtra2(models.Model): 77 chap = models.OneToOneField(Chapter, verbose_name=u'żChap?') 78 xtra = models.CharField(max_length=100, verbose_name=u'żXtra?') 79 80 def __unicode__(self): 81 return u'żXtra2: %s' % self.xtra 82 83def callable_year(dt_value): 84 return dt_value.year 85callable_year.admin_order_field = 'date' 86 87class ArticleInline(admin.TabularInline): 88 model = Article 89 90class ChapterInline(admin.TabularInline): 91 model = Chapter 92 93class 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 101class 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) 135 136class RowLevelChangePermissionModel(models.Model): 137 name = models.CharField(max_length=100, blank=True) 138 139class RowLevelChangePermissionModelAdmin(admin.ModelAdmin): 140 def has_change_permission(self, request, obj=None): 141 """ Only allow changing objects with even id number """ 142 return request.user.is_staff and (obj is not None) and (obj.id % 2 == 0) 143 144class CustomArticle(models.Model): 145 content = models.TextField() 146 date = models.DateTimeField() 147 148class CustomArticleAdmin(admin.ModelAdmin): 149 """ 150 Tests various hooks for using custom templates and contexts. 151 """ 152 change_list_template = 'custom_admin/change_list.html' 153 change_form_template = 'custom_admin/change_form.html' 154 add_form_template = 'custom_admin/add_form.html' 155 object_history_template = 'custom_admin/object_history.html' 156 delete_confirmation_template = 'custom_admin/delete_confirmation.html' 157 delete_selected_confirmation_template = 'custom_admin/delete_selected_confirmation.html' 158 159 def changelist_view(self, request): 160 "Test that extra_context works" 161 return super(CustomArticleAdmin, self).changelist_view( 162 request, extra_context={ 163 'extra_var': 'Hello!' 164 } 165 ) 166 167class ModelWithStringPrimaryKey(models.Model): 168 id = models.CharField(max_length=255, primary_key=True) 169 170 def __unicode__(self): 171 return self.id 172 173class Color(models.Model): 174 value = models.CharField(max_length=10) 175 warm = models.BooleanField() 176 def __unicode__(self): 177 return self.value 178 179class Thing(models.Model): 180 title = models.CharField(max_length=20) 181 color = models.ForeignKey(Color, limit_choices_to={'warm': True}) 182 def __unicode__(self): 183 return self.title 184 185class ThingAdmin(admin.ModelAdmin): 186 list_filter = ('color__warm', 'color__value') 187 188class Actor(models.Model): 189 name = models.CharField(max_length=50) 190 age = models.IntegerField() 191 def __unicode__(self): 192 return self.name 193 194class Inquisition(models.Model): 195 expected = models.BooleanField() 196 leader = models.ForeignKey(Actor) 197 country = models.CharField(max_length=20) 198 199 def __unicode__(self): 200 return u"by %s from %s" % (self.leader, self.country) 201 202class InquisitionAdmin(admin.ModelAdmin): 203 list_display = ('leader', 'country', 'expected') 204 205class Sketch(models.Model): 206 title = models.CharField(max_length=100) 207 inquisition = models.ForeignKey(Inquisition, limit_choices_to={'leader__name': 'Palin', 208 'leader__age': 27, 209 'expected': False, 210 }) 211 212 def __unicode__(self): 213 return self.title 214 215class SketchAdmin(admin.ModelAdmin): 216 raw_id_fields = ('inquisition',) 217 218class Fabric(models.Model): 219 NG_CHOICES = ( 220 ('Textured', ( 221 ('x', 'Horizontal'), 222 ('y', 'Vertical'), 223 ) 224 ), 225 ('plain', 'Smooth'), 226 ) 227 surface = models.CharField(max_length=20, choices=NG_CHOICES) 228 229class FabricAdmin(admin.ModelAdmin): 230 list_display = ('surface',) 231 list_filter = ('surface',) 232 233class Person(models.Model): 234 GENDER_CHOICES = ( 235 (1, "Male"), 236 (2, "Female"), 237 ) 238 name = models.CharField(max_length=100) 239 gender = models.IntegerField(choices=GENDER_CHOICES) 240 age = models.IntegerField(default=21) 241 alive = models.BooleanField() 242 243 def __unicode__(self): 244 return self.name 245 246 class Meta: 247 ordering = ["id"] 248 249class BasePersonModelFormSet(BaseModelFormSet): 250 def clean(self): 251 for person_dict in self.cleaned_data: 252 person = person_dict.get('id') 253 alive = person_dict.get('alive') 254 if person and alive and person.name == "Grace Hopper": 255 raise forms.ValidationError("Grace is not a Zombie") 256 257class PersonAdmin(admin.ModelAdmin): 258 list_display = ('name', 'gender', 'alive') 259 list_editable = ('gender', 'alive') 260 list_filter = ('gender',) 261 search_fields = ('^name',) 262 ordering = ["id"] 263 save_as = True 264 265 def get_changelist_formset(self, request, **kwargs): 266 return super(PersonAdmin, self).get_changelist_formset(request, 267 formset=BasePersonModelFormSet, **kwargs) 268 269 270class Persona(models.Model): 271 """ 272 A simple persona associated with accounts, to test inlining of related 273 accounts which inherit from a common accounts class. 274 """ 275 name = models.CharField(blank=False, max_length=80) 276 def __unicode__(self): 277 return self.name 278 279class Account(models.Model): 280 """ 281 A simple, generic account encapsulating the information shared by all 282 types of accounts. 283 """ 284 username = models.CharField(blank=False, max_length=80) 285 persona = models.ForeignKey(Persona, related_name="accounts") 286 servicename = u'generic service' 287 288 def __unicode__(self): 289 return "%s: %s" % (self.servicename, self.username) 290 291class FooAccount(Account): 292 """A service-specific account of type Foo.""" 293 servicename = u'foo' 294 295class BarAccount(Account): 296 """A service-specific account of type Bar.""" 297 servicename = u'bar' 298 299class FooAccountAdmin(admin.StackedInline): 300 model = FooAccount 301 extra = 1 302 303class BarAccountAdmin(admin.StackedInline): 304 model = BarAccount 305 extra = 1 306 307class PersonaAdmin(admin.ModelAdmin): 308 inlines = ( 309 FooAccountAdmin, 310 BarAccountAdmin 311 ) 312 313class Subscriber(models.Model): 314 name = models.CharField(blank=False, max_length=80) 315 email = models.EmailField(blank=False, max_length=175) 316 317 def __unicode__(self): 318 return "%s (%s)" % (self.name, self.email) 319 320class SubscriberAdmin(admin.ModelAdmin): 321 actions = ['mail_admin'] 322 323 def mail_admin(self, request, selected): 324 EmailMessage( 325 'Greetings from a ModelAdmin action', 326 'This is the test email from a admin action', 327 'from@example.com', 328 ['to@example.com'] 329 ).send() 330 331class ExternalSubscriber(Subscriber): 332 pass 333 334class OldSubscriber(Subscriber): 335 pass 336 337def external_mail(modeladmin, request, selected): 338 EmailMessage( 339 'Greetings from a function action', 340 'This is the test email from a function action', 341 'from@example.com', 342 ['to@example.com'] 343 ).send() 344 345def redirect_to(modeladmin, request, selected): 346 from django.http import HttpResponseRedirect 347 return HttpResponseRedirect('/some-where-else/') 348 349class ExternalSubscriberAdmin(admin.ModelAdmin): 350 actions = [external_mail, redirect_to] 351 352class Media(models.Model): 353 name = models.CharField(max_length=60) 354 355class Podcast(Media): 356 release_date = models.DateField() 357 358class PodcastAdmin(admin.ModelAdmin): 359 list_display = ('name', 'release_date') 360 list_editable = ('release_date',) 361 date_hierarchy = 'release_date' 362 ordering = ('name',) 363 364class Vodcast(Media): 365 media = models.OneToOneField(Media, primary_key=True, parent_link=True) 366 released = models.BooleanField(default=False) 367 368class VodcastAdmin(admin.ModelAdmin): 369 list_display = ('name', 'released') 370 list_editable = ('released',) 371 372 ordering = ('name',) 373 374class Parent(models.Model): 375 name = models.CharField(max_length=128) 376 377class Child(models.Model): 378 parent = models.ForeignKey(Parent, editable=False) 379 name = models.CharField(max_length=30, blank=True) 380 381class ChildInline(admin.StackedInline): 382 model = Child 383 384class ParentAdmin(admin.ModelAdmin): 385 model = Parent 386 inlines = [ChildInline] 387 388class EmptyModel(models.Model): 389 def __unicode__(self): 390 return "Primary key = %s" % self.id 391 392class EmptyModelAdmin(admin.ModelAdmin): 393 def queryset(self, request): 394 return super(EmptyModelAdmin, self).queryset(request).filter(pk__gt=1) 395 396class OldSubscriberAdmin(admin.ModelAdmin): 397 actions = None 398 399temp_storage = FileSystemStorage(tempfile.mkdtemp()) 400UPLOAD_TO = os.path.join(temp_storage.location, 'test_upload') 401 402class Gallery(models.Model): 403 name = models.CharField(max_length=100) 404 405class Picture(models.Model): 406 name = models.CharField(max_length=100) 407 image = models.FileField(storage=temp_storage, upload_to='test_upload') 408 gallery = models.ForeignKey(Gallery, related_name="pictures") 409 410class PictureInline(admin.TabularInline): 411 model = Picture 412 extra = 1 413 414class GalleryAdmin(admin.ModelAdmin): 415 inlines = [PictureInline] 416 417class PictureAdmin(admin.ModelAdmin): 418 pass 419 420class Language(models.Model): 421 iso = models.CharField(max_length=5, primary_key=True) 422 name = models.CharField(max_length=50) 423 english_name = models.CharField(max_length=50) 424 shortlist = models.BooleanField(default=False) 425 426 class Meta: 427 ordering = ('iso',) 428 429class LanguageAdmin(admin.ModelAdmin): 430 list_display = ['iso', 'shortlist', 'english_name', 'name'] 431 list_editable = ['shortlist'] 432 433# a base class for Recommender and Recommendation 434class Title(models.Model): 435 pass 436 437class TitleTranslation(models.Model): 438 title = models.ForeignKey(Title) 439 text = models.CharField(max_length=100) 440 441class Recommender(Title): 442 pass 443 444class Recommendation(Title): 445 recommender = models.ForeignKey(Recommender) 446 447class RecommendationAdmin(admin.ModelAdmin): 448 search_fields = ('=titletranslation__text', '=recommender__titletranslation__text',) 449 450class Collector(models.Model): 451 name = models.CharField(max_length=100) 452 453class Widget(models.Model): 454 owner = models.ForeignKey(Collector) 455 name = models.CharField(max_length=100) 456 457class DooHickey(models.Model): 458 code = models.CharField(max_length=10, primary_key=True) 459 owner = models.ForeignKey(Collector) 460 name = models.CharField(max_length=100) 461 462class Grommet(models.Model): 463 code = models.AutoField(primary_key=True) 464 owner = models.ForeignKey(Collector) 465 name = models.CharField(max_length=100) 466 467class Whatsit(models.Model): 468 index = models.IntegerField(primary_key=True) 469 owner = models.ForeignKey(Collector) 470 name = models.CharField(max_length=100) 471 472class Doodad(models.Model): 473 name = models.CharField(max_length=100) 474 475class FancyDoodad(Doodad): 476 owner = models.ForeignKey(Collector) 477 expensive = models.BooleanField(default=True) 478 479class WidgetInline(admin.StackedInline): 480 model = Widget 481 482class DooHickeyInline(admin.StackedInline): 483 model = DooHickey 484 485class GrommetInline(admin.StackedInline): 486 model = Grommet 487 488class WhatsitInline(admin.StackedInline): 489 model = Whatsit 490 491class FancyDoodadInline(admin.StackedInline): 492 model = FancyDoodad 493 494class Category(models.Model): 495 collector = models.ForeignKey(Collector) 496 order = models.PositiveIntegerField() 497 498 class Meta: 499 ordering = ('order',) 500 501 def __unicode__(self): 502 return u'%s:o%s' % (self.id, self.order) 503 504class CategoryAdmin(admin.ModelAdmin): 505 list_display = ('id', 'collector', 'order') 506 list_editable = ('order',) 507 508class CategoryInline(admin.StackedInline): 509 model = Category 510 511class CollectorAdmin(admin.ModelAdmin): 512 inlines = [ 513 WidgetInline, DooHickeyInline, GrommetInline, WhatsitInline, 514 FancyDoodadInline, CategoryInline 515 ] 516 517class Link(models.Model): 518 posted = models.DateField( 519 default=lambda: datetime.date.today() - datetime.timedelta(days=7) 520 ) 521 url = models.URLField() 522 post = models.ForeignKey("Post") 523 524 525class LinkInline(admin.TabularInline): 526 model = Link 527 extra = 1 528 529 readonly_fields = ("posted",) 530 531 532class Post(models.Model): 533 title = models.CharField(max_length=100, help_text="Some help text for the title (with unicode ????)") 534 content = models.TextField(help_text="Some help text for the content (with unicode ????)") 535 posted = models.DateField( 536 default=datetime.date.today, 537 help_text="Some help text for the date (with unicode ????)" 538 ) 539 public = models.NullBooleanField() 540 541 def awesomeness_level(self): 542 return "Very awesome." 543 544class PostAdmin(admin.ModelAdmin): 545 list_display = ['title', 'public'] 546 readonly_fields = ('posted', 'awesomeness_level', 'coolness', 'value', lambda obj: "foo") 547 548 inlines = [ 549 LinkInline 550 ] 551 552 def coolness(self, instance): 553 if instance.pk: 554 return "%d amount of cool." % instance.pk 555 else: 556 return "Unkown coolness." 557 558 def value(self, instance): 559 return 1000 560 value.short_description = 'Value in $US' 561 562class Gadget(models.Model): 563 name = models.CharField(max_length=100) 564 565 def __unicode__(self): 566 return self.name 567 568class CustomChangeList(ChangeList): 569 def get_query_set(self): 570 return self.root_query_set.filter(pk=9999) # Does not exist 571 572class GadgetAdmin(admin.ModelAdmin): 573 def get_changelist(self, request, **kwargs): 574 return CustomChangeList 575 576class Villain(models.Model): 577 name = models.CharField(max_length=100) 578 579 def __unicode__(self): 580 return self.name 581 582class SuperVillain(Villain): 583 pass 584 585class FunkyTag(models.Model): 586 "Because we all know there's only one real use case for GFKs." 587 name = models.CharField(max_length=25) 588 content_type = models.ForeignKey(ContentType) 589 object_id = models.PositiveIntegerField() 590 content_object = generic.GenericForeignKey('content_type', 'object_id') 591 592 def __unicode__(self): 593 return self.name 594 595class Plot(models.Model): 596 name = models.CharField(max_length=100) 597 team_leader = models.ForeignKey(Villain, related_name='lead_plots') 598 contact = models.ForeignKey(Villain, related_name='contact_plots') 599 tags = generic.GenericRelation(FunkyTag) 600 601 def __unicode__(self): 602 return self.name 603 604class PlotDetails(models.Model): 605 details = models.CharField(max_length=100) 606 plot = models.OneToOneField(Plot) 607 608 def __unicode__(self): 609 return self.details 610 611class SecretHideout(models.Model): 612 """ Secret! Not registered with the admin! """ 613 location = models.CharField(max_length=100) 614 villain = models.ForeignKey(Villain) 615 616 def __unicode__(self): 617 return self.location 618 619class SuperSecretHideout(models.Model): 620 """ Secret! Not registered with the admin! """ 621 location = models.CharField(max_length=100) 622 supervillain = models.ForeignKey(SuperVillain) 623 624 def __unicode__(self): 625 return self.location 626 627class CyclicOne(models.Model): 628 name = models.CharField(max_length=25) 629 two = models.ForeignKey('CyclicTwo') 630 631 def __unicode__(self): 632 return self.name 633 634class CyclicTwo(models.Model): 635 name = models.CharField(max_length=25) 636 one = models.ForeignKey(CyclicOne) 637 638 def __unicode__(self): 639 return self.name 640 641class Topping(models.Model): 642 name = models.CharField(max_length=20) 643 644class Pizza(models.Model): 645 name = models.CharField(max_length=20) 646 toppings = models.ManyToManyField('Topping') 647 648class PizzaAdmin(admin.ModelAdmin): 649 readonly_fields = ('toppings',) 650 651class Album(models.Model): 652 owner = models.ForeignKey(User) 653 title = models.CharField(max_length=30) 654 655class AlbumAdmin(admin.ModelAdmin): 656 list_filter = ['title'] 657 658class Employee(Person): 659 code = models.CharField(max_length=20) 660 661class WorkHour(models.Model): 662 datum = models.DateField() 663 employee = models.ForeignKey(Employee) 664 665class WorkHourAdmin(admin.ModelAdmin): 666 list_display = ('datum', 'employee') 667 list_filter = ('employee',) 668 669class Question(models.Model): 670 question = models.CharField(max_length=20) 671 672class Answer(models.Model): 673 question = models.ForeignKey(Question, on_delete=models.PROTECT) 674 answer = models.CharField(max_length=20) 675 676 def __unicode__(self): 677 return self.answer 678 679class Reservation(models.Model): 680 start_date = models.DateTimeField() 681 price = models.IntegerField() 682 683 684DRIVER_CHOICES = ( 685 (u'bill', 'Bill G'), 686 (u'steve', 'Steve J'), 687) 688 689RESTAURANT_CHOICES = ( 690 (u'indian', u'A Taste of India'), 691 (u'thai', u'Thai Pography'), 692 (u'pizza', u'Pizza Mama'), 693) 694 695class FoodDelivery(models.Model): 696 reference = models.CharField(max_length=100) 697 driver = models.CharField(max_length=100, choices=DRIVER_CHOICES, blank=True) 698 restaurant = models.CharField(max_length=100, choices=RESTAURANT_CHOICES, blank=True) 699 700 class Meta: 701 unique_together = (("driver", "restaurant"),) 702 703class FoodDeliveryAdmin(admin.ModelAdmin): 704 list_display=('reference', 'driver', 'restaurant') 705 list_editable = ('driver', 'restaurant') 706 707class Paper(models.Model): 708 title = models.CharField(max_length=30) 709 author = models.CharField(max_length=30, blank=True, null=True) 710 711class CoverLetter(models.Model): 712 author = models.CharField(max_length=30) 713 date_written = models.DateField(null=True, blank=True) 714 715 def __unicode__(self): 716 return self.author 717 718class PaperAdmin(admin.ModelAdmin): 719 """ 720 A ModelAdin with a custom queryset() method that uses only(), to test 721 verbose_name display in messages shown after adding Paper instances. 722 """ 723 724 def queryset(self, request): 725 return super(PaperAdmin, self).queryset(request).only('title') 726 727class CoverLetterAdmin(admin.ModelAdmin): 728 """ 729 A ModelAdin with a custom queryset() method that uses only(), to test 730 verbose_name display in messages shown after adding CoverLetter instances. 731 Note that the CoverLetter model defines a __unicode__ method. 732 """ 733 734 def queryset(self, request): 735 #return super(CoverLetterAdmin, self).queryset(request).only('author') 736 return super(CoverLetterAdmin, self).queryset(request).defer('date_written') 737 738class Story(models.Model): 739 title = models.CharField(max_length=100) 740 content = models.TextField() 741 742class StoryForm(forms.ModelForm): 743 class Meta: 744 widgets = {'title': forms.HiddenInput} 745 746class StoryAdmin(admin.ModelAdmin): 747 list_display = ('id', 'title', 'content') 748 list_display_links = ('title',) # 'id' not in list_display_links 749 list_editable = ('content', ) 750 form = StoryForm 751 752class OtherStory(models.Model): 753 title = models.CharField(max_length=100) 754 content = models.TextField() 755 756class OtherStoryAdmin(admin.ModelAdmin): 757 list_display = ('id', 'title', 'content') 758 list_display_links = ('title', 'id') # 'id' in list_display_links 759 list_editable = ('content', ) 760 761admin.site.register(Article, ArticleAdmin) 762admin.site.register(CustomArticle, CustomArticleAdmin) 763admin.site.register(Section, save_as=True, inlines=[ArticleInline]) 764admin.site.register(ModelWithStringPrimaryKey) 765admin.site.register(Color) 766admin.site.register(Thing, ThingAdmin) 767admin.site.register(Actor) 768admin.site.register(Inquisition, InquisitionAdmin) 769admin.site.register(Sketch, SketchAdmin) 770admin.site.register(Person, PersonAdmin) 771admin.site.register(Persona, PersonaAdmin) 772admin.site.register(Subscriber, SubscriberAdmin) 773admin.site.register(ExternalSubscriber, ExternalSubscriberAdmin) 774admin.site.register(OldSubscriber, OldSubscriberAdmin) 775admin.site.register(Podcast, PodcastAdmin) 776admin.site.register(Vodcast, VodcastAdmin) 777admin.site.register(Parent, ParentAdmin) 778admin.site.register(EmptyModel, EmptyModelAdmin) 779admin.site.register(Fabric, FabricAdmin) 780admin.site.register(Gallery, GalleryAdmin) 781admin.site.register(Picture, PictureAdmin) 782admin.site.register(Language, LanguageAdmin) 783admin.site.register(Recommendation, RecommendationAdmin) 784admin.site.register(Recommender) 785admin.site.register(Collector, CollectorAdmin) 786admin.site.register(Category, CategoryAdmin) 787admin.site.register(Post, PostAdmin) 788admin.site.register(Gadget, GadgetAdmin) 789admin.site.register(Villain) 790admin.site.register(SuperVillain) 791admin.site.register(Plot) 792admin.site.register(PlotDetails) 793admin.site.register(CyclicOne) 794admin.site.register(CyclicTwo) 795admin.site.register(WorkHour, WorkHourAdmin) 796admin.site.register(Reservation) 797admin.site.register(FoodDelivery, FoodDeliveryAdmin) 798admin.site.register(RowLevelChangePermissionModel, RowLevelChangePermissionModelAdmin) 799admin.site.register(Paper, PaperAdmin) 800admin.site.register(CoverLetter, CoverLetterAdmin) 801admin.site.register(Story, StoryAdmin) 802admin.site.register(OtherStory, OtherStoryAdmin) 803 804# We intentionally register Promo and ChapterXtra1 but not Chapter nor ChapterXtra2. 805# That way we cover all four cases: 806# related ForeignKey object registered in admin 807# related ForeignKey object not registered in admin 808# related OneToOne object registered in admin 809# related OneToOne object not registered in admin 810# when deleting Book so as exercise all four troublesome (w.r.t escaping 811# and calling force_unicode to avoid problems on Python 2.3) paths through 812# contrib.admin.util's get_deleted_objects function. 813admin.site.register(Book, inlines=[ChapterInline]) 814admin.site.register(Promo) 815admin.site.register(ChapterXtra1, ChapterXtra1Admin) 816admin.site.register(Pizza, PizzaAdmin) 817admin.site.register(Topping) 818admin.site.register(Album, AlbumAdmin) 819admin.site.register(Question) 820admin.site.register(Answer)