|
1 # -*- coding: utf-8 -*- |
|
2 import datetime |
|
3 import tempfile |
|
4 import os |
|
5 |
|
6 from django.contrib import admin |
|
7 from django.core.files.storage import FileSystemStorage |
|
8 from django.contrib.admin.views.main import ChangeList |
|
9 from django.core.mail import EmailMessage |
|
10 from django.db import models |
|
11 from django import forms |
|
12 from django.forms.models import BaseModelFormSet |
|
13 from django.contrib.auth.models import User |
|
14 from django.contrib.contenttypes import generic |
|
15 from django.contrib.contenttypes.models import ContentType |
|
16 |
|
17 class 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 |
|
24 class 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 |
|
41 class 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 |
|
50 class 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 |
|
57 class 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 |
|
69 class 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 |
|
76 class 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 |
|
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 ArticleAdmin(admin.ModelAdmin): |
|
94 list_display = ('content', 'date', callable_year, 'model_year', 'modeladmin_year') |
|
95 list_filter = ('date', 'section') |
|
96 |
|
97 def changelist_view(self, request): |
|
98 "Test that extra_context works" |
|
99 return super(ArticleAdmin, self).changelist_view( |
|
100 request, extra_context={ |
|
101 'extra_var': 'Hello!' |
|
102 } |
|
103 ) |
|
104 |
|
105 def modeladmin_year(self, obj): |
|
106 return obj.date.year |
|
107 modeladmin_year.admin_order_field = 'date' |
|
108 modeladmin_year.short_description = None |
|
109 |
|
110 class CustomArticle(models.Model): |
|
111 content = models.TextField() |
|
112 date = models.DateTimeField() |
|
113 |
|
114 class CustomArticleAdmin(admin.ModelAdmin): |
|
115 """ |
|
116 Tests various hooks for using custom templates and contexts. |
|
117 """ |
|
118 change_list_template = 'custom_admin/change_list.html' |
|
119 change_form_template = 'custom_admin/change_form.html' |
|
120 add_form_template = 'custom_admin/add_form.html' |
|
121 object_history_template = 'custom_admin/object_history.html' |
|
122 delete_confirmation_template = 'custom_admin/delete_confirmation.html' |
|
123 delete_selected_confirmation_template = 'custom_admin/delete_selected_confirmation.html' |
|
124 |
|
125 def changelist_view(self, request): |
|
126 "Test that extra_context works" |
|
127 return super(CustomArticleAdmin, self).changelist_view( |
|
128 request, extra_context={ |
|
129 'extra_var': 'Hello!' |
|
130 } |
|
131 ) |
|
132 |
|
133 class ModelWithStringPrimaryKey(models.Model): |
|
134 id = models.CharField(max_length=255, primary_key=True) |
|
135 |
|
136 def __unicode__(self): |
|
137 return self.id |
|
138 |
|
139 class Color(models.Model): |
|
140 value = models.CharField(max_length=10) |
|
141 warm = models.BooleanField() |
|
142 def __unicode__(self): |
|
143 return self.value |
|
144 |
|
145 class Thing(models.Model): |
|
146 title = models.CharField(max_length=20) |
|
147 color = models.ForeignKey(Color, limit_choices_to={'warm': True}) |
|
148 def __unicode__(self): |
|
149 return self.title |
|
150 |
|
151 class ThingAdmin(admin.ModelAdmin): |
|
152 list_filter = ('color',) |
|
153 |
|
154 class Fabric(models.Model): |
|
155 NG_CHOICES = ( |
|
156 ('Textured', ( |
|
157 ('x', 'Horizontal'), |
|
158 ('y', 'Vertical'), |
|
159 ) |
|
160 ), |
|
161 ('plain', 'Smooth'), |
|
162 ) |
|
163 surface = models.CharField(max_length=20, choices=NG_CHOICES) |
|
164 |
|
165 class FabricAdmin(admin.ModelAdmin): |
|
166 list_display = ('surface',) |
|
167 list_filter = ('surface',) |
|
168 |
|
169 class Person(models.Model): |
|
170 GENDER_CHOICES = ( |
|
171 (1, "Male"), |
|
172 (2, "Female"), |
|
173 ) |
|
174 name = models.CharField(max_length=100) |
|
175 gender = models.IntegerField(choices=GENDER_CHOICES) |
|
176 alive = models.BooleanField() |
|
177 |
|
178 def __unicode__(self): |
|
179 return self.name |
|
180 |
|
181 class Meta: |
|
182 ordering = ["id"] |
|
183 |
|
184 class BasePersonModelFormSet(BaseModelFormSet): |
|
185 def clean(self): |
|
186 for person_dict in self.cleaned_data: |
|
187 person = person_dict.get('id') |
|
188 alive = person_dict.get('alive') |
|
189 if person and alive and person.name == "Grace Hopper": |
|
190 raise forms.ValidationError, "Grace is not a Zombie" |
|
191 |
|
192 class PersonAdmin(admin.ModelAdmin): |
|
193 list_display = ('name', 'gender', 'alive') |
|
194 list_editable = ('gender', 'alive') |
|
195 list_filter = ('gender',) |
|
196 search_fields = (u'name',) |
|
197 ordering = ["id"] |
|
198 save_as = True |
|
199 |
|
200 def get_changelist_formset(self, request, **kwargs): |
|
201 return super(PersonAdmin, self).get_changelist_formset(request, |
|
202 formset=BasePersonModelFormSet, **kwargs) |
|
203 |
|
204 |
|
205 class Persona(models.Model): |
|
206 """ |
|
207 A simple persona associated with accounts, to test inlining of related |
|
208 accounts which inherit from a common accounts class. |
|
209 """ |
|
210 name = models.CharField(blank=False, max_length=80) |
|
211 def __unicode__(self): |
|
212 return self.name |
|
213 |
|
214 class Account(models.Model): |
|
215 """ |
|
216 A simple, generic account encapsulating the information shared by all |
|
217 types of accounts. |
|
218 """ |
|
219 username = models.CharField(blank=False, max_length=80) |
|
220 persona = models.ForeignKey(Persona, related_name="accounts") |
|
221 servicename = u'generic service' |
|
222 |
|
223 def __unicode__(self): |
|
224 return "%s: %s" % (self.servicename, self.username) |
|
225 |
|
226 class FooAccount(Account): |
|
227 """A service-specific account of type Foo.""" |
|
228 servicename = u'foo' |
|
229 |
|
230 class BarAccount(Account): |
|
231 """A service-specific account of type Bar.""" |
|
232 servicename = u'bar' |
|
233 |
|
234 class FooAccountAdmin(admin.StackedInline): |
|
235 model = FooAccount |
|
236 extra = 1 |
|
237 |
|
238 class BarAccountAdmin(admin.StackedInline): |
|
239 model = BarAccount |
|
240 extra = 1 |
|
241 |
|
242 class PersonaAdmin(admin.ModelAdmin): |
|
243 inlines = ( |
|
244 FooAccountAdmin, |
|
245 BarAccountAdmin |
|
246 ) |
|
247 |
|
248 class Subscriber(models.Model): |
|
249 name = models.CharField(blank=False, max_length=80) |
|
250 email = models.EmailField(blank=False, max_length=175) |
|
251 |
|
252 def __unicode__(self): |
|
253 return "%s (%s)" % (self.name, self.email) |
|
254 |
|
255 class SubscriberAdmin(admin.ModelAdmin): |
|
256 actions = ['mail_admin'] |
|
257 |
|
258 def mail_admin(self, request, selected): |
|
259 EmailMessage( |
|
260 'Greetings from a ModelAdmin action', |
|
261 'This is the test email from a admin action', |
|
262 'from@example.com', |
|
263 ['to@example.com'] |
|
264 ).send() |
|
265 |
|
266 class ExternalSubscriber(Subscriber): |
|
267 pass |
|
268 |
|
269 class OldSubscriber(Subscriber): |
|
270 pass |
|
271 |
|
272 def external_mail(modeladmin, request, selected): |
|
273 EmailMessage( |
|
274 'Greetings from a function action', |
|
275 'This is the test email from a function action', |
|
276 'from@example.com', |
|
277 ['to@example.com'] |
|
278 ).send() |
|
279 |
|
280 def redirect_to(modeladmin, request, selected): |
|
281 from django.http import HttpResponseRedirect |
|
282 return HttpResponseRedirect('/some-where-else/') |
|
283 |
|
284 class ExternalSubscriberAdmin(admin.ModelAdmin): |
|
285 actions = [external_mail, redirect_to] |
|
286 |
|
287 class Media(models.Model): |
|
288 name = models.CharField(max_length=60) |
|
289 |
|
290 class Podcast(Media): |
|
291 release_date = models.DateField() |
|
292 |
|
293 class PodcastAdmin(admin.ModelAdmin): |
|
294 list_display = ('name', 'release_date') |
|
295 list_editable = ('release_date',) |
|
296 |
|
297 ordering = ('name',) |
|
298 |
|
299 class Vodcast(Media): |
|
300 media = models.OneToOneField(Media, primary_key=True, parent_link=True) |
|
301 released = models.BooleanField(default=False) |
|
302 |
|
303 class VodcastAdmin(admin.ModelAdmin): |
|
304 list_display = ('name', 'released') |
|
305 list_editable = ('released',) |
|
306 |
|
307 ordering = ('name',) |
|
308 |
|
309 class Parent(models.Model): |
|
310 name = models.CharField(max_length=128) |
|
311 |
|
312 class Child(models.Model): |
|
313 parent = models.ForeignKey(Parent, editable=False) |
|
314 name = models.CharField(max_length=30, blank=True) |
|
315 |
|
316 class ChildInline(admin.StackedInline): |
|
317 model = Child |
|
318 |
|
319 class ParentAdmin(admin.ModelAdmin): |
|
320 model = Parent |
|
321 inlines = [ChildInline] |
|
322 |
|
323 class EmptyModel(models.Model): |
|
324 def __unicode__(self): |
|
325 return "Primary key = %s" % self.id |
|
326 |
|
327 class EmptyModelAdmin(admin.ModelAdmin): |
|
328 def queryset(self, request): |
|
329 return super(EmptyModelAdmin, self).queryset(request).filter(pk__gt=1) |
|
330 |
|
331 class OldSubscriberAdmin(admin.ModelAdmin): |
|
332 actions = None |
|
333 |
|
334 temp_storage = FileSystemStorage(tempfile.mkdtemp()) |
|
335 UPLOAD_TO = os.path.join(temp_storage.location, 'test_upload') |
|
336 |
|
337 class Gallery(models.Model): |
|
338 name = models.CharField(max_length=100) |
|
339 |
|
340 class Picture(models.Model): |
|
341 name = models.CharField(max_length=100) |
|
342 image = models.FileField(storage=temp_storage, upload_to='test_upload') |
|
343 gallery = models.ForeignKey(Gallery, related_name="pictures") |
|
344 |
|
345 class PictureInline(admin.TabularInline): |
|
346 model = Picture |
|
347 extra = 1 |
|
348 |
|
349 class GalleryAdmin(admin.ModelAdmin): |
|
350 inlines = [PictureInline] |
|
351 |
|
352 class PictureAdmin(admin.ModelAdmin): |
|
353 pass |
|
354 |
|
355 class Language(models.Model): |
|
356 iso = models.CharField(max_length=5, primary_key=True) |
|
357 name = models.CharField(max_length=50) |
|
358 english_name = models.CharField(max_length=50) |
|
359 shortlist = models.BooleanField(default=False) |
|
360 |
|
361 class Meta: |
|
362 ordering = ('iso',) |
|
363 |
|
364 class LanguageAdmin(admin.ModelAdmin): |
|
365 list_display = ['iso', 'shortlist', 'english_name', 'name'] |
|
366 list_editable = ['shortlist'] |
|
367 |
|
368 # a base class for Recommender and Recommendation |
|
369 class Title(models.Model): |
|
370 pass |
|
371 |
|
372 class TitleTranslation(models.Model): |
|
373 title = models.ForeignKey(Title) |
|
374 text = models.CharField(max_length=100) |
|
375 |
|
376 class Recommender(Title): |
|
377 pass |
|
378 |
|
379 class Recommendation(Title): |
|
380 recommender = models.ForeignKey(Recommender) |
|
381 |
|
382 class RecommendationAdmin(admin.ModelAdmin): |
|
383 search_fields = ('titletranslation__text', 'recommender__titletranslation__text',) |
|
384 |
|
385 class Collector(models.Model): |
|
386 name = models.CharField(max_length=100) |
|
387 |
|
388 class Widget(models.Model): |
|
389 owner = models.ForeignKey(Collector) |
|
390 name = models.CharField(max_length=100) |
|
391 |
|
392 class DooHickey(models.Model): |
|
393 code = models.CharField(max_length=10, primary_key=True) |
|
394 owner = models.ForeignKey(Collector) |
|
395 name = models.CharField(max_length=100) |
|
396 |
|
397 class Grommet(models.Model): |
|
398 code = models.AutoField(primary_key=True) |
|
399 owner = models.ForeignKey(Collector) |
|
400 name = models.CharField(max_length=100) |
|
401 |
|
402 class Whatsit(models.Model): |
|
403 index = models.IntegerField(primary_key=True) |
|
404 owner = models.ForeignKey(Collector) |
|
405 name = models.CharField(max_length=100) |
|
406 |
|
407 class Doodad(models.Model): |
|
408 name = models.CharField(max_length=100) |
|
409 |
|
410 class FancyDoodad(Doodad): |
|
411 owner = models.ForeignKey(Collector) |
|
412 expensive = models.BooleanField(default=True) |
|
413 |
|
414 class WidgetInline(admin.StackedInline): |
|
415 model = Widget |
|
416 |
|
417 class DooHickeyInline(admin.StackedInline): |
|
418 model = DooHickey |
|
419 |
|
420 class GrommetInline(admin.StackedInline): |
|
421 model = Grommet |
|
422 |
|
423 class WhatsitInline(admin.StackedInline): |
|
424 model = Whatsit |
|
425 |
|
426 class FancyDoodadInline(admin.StackedInline): |
|
427 model = FancyDoodad |
|
428 |
|
429 class Category(models.Model): |
|
430 collector = models.ForeignKey(Collector) |
|
431 order = models.PositiveIntegerField() |
|
432 |
|
433 class Meta: |
|
434 ordering = ('order',) |
|
435 |
|
436 def __unicode__(self): |
|
437 return u'%s:o%s' % (self.id, self.order) |
|
438 |
|
439 class CategoryAdmin(admin.ModelAdmin): |
|
440 list_display = ('id', 'collector', 'order') |
|
441 list_editable = ('order',) |
|
442 |
|
443 class CategoryInline(admin.StackedInline): |
|
444 model = Category |
|
445 |
|
446 class CollectorAdmin(admin.ModelAdmin): |
|
447 inlines = [ |
|
448 WidgetInline, DooHickeyInline, GrommetInline, WhatsitInline, |
|
449 FancyDoodadInline, CategoryInline |
|
450 ] |
|
451 |
|
452 class Link(models.Model): |
|
453 posted = models.DateField( |
|
454 default=lambda: datetime.date.today() - datetime.timedelta(days=7) |
|
455 ) |
|
456 url = models.URLField() |
|
457 post = models.ForeignKey("Post") |
|
458 |
|
459 |
|
460 class LinkInline(admin.TabularInline): |
|
461 model = Link |
|
462 extra = 1 |
|
463 |
|
464 readonly_fields = ("posted",) |
|
465 |
|
466 |
|
467 class Post(models.Model): |
|
468 title = models.CharField(max_length=100) |
|
469 content = models.TextField() |
|
470 posted = models.DateField(default=datetime.date.today) |
|
471 public = models.NullBooleanField() |
|
472 |
|
473 def awesomeness_level(self): |
|
474 return "Very awesome." |
|
475 |
|
476 class PostAdmin(admin.ModelAdmin): |
|
477 list_display = ['title', 'public'] |
|
478 readonly_fields = ('posted', 'awesomeness_level', 'coolness', 'value', lambda obj: "foo") |
|
479 |
|
480 inlines = [ |
|
481 LinkInline |
|
482 ] |
|
483 |
|
484 def coolness(self, instance): |
|
485 if instance.pk: |
|
486 return "%d amount of cool." % instance.pk |
|
487 else: |
|
488 return "Unkown coolness." |
|
489 |
|
490 def value(self, instance): |
|
491 return 1000 |
|
492 value.short_description = 'Value in $US' |
|
493 |
|
494 class Gadget(models.Model): |
|
495 name = models.CharField(max_length=100) |
|
496 |
|
497 def __unicode__(self): |
|
498 return self.name |
|
499 |
|
500 class CustomChangeList(ChangeList): |
|
501 def get_query_set(self): |
|
502 return self.root_query_set.filter(pk=9999) # Does not exist |
|
503 |
|
504 class GadgetAdmin(admin.ModelAdmin): |
|
505 def get_changelist(self, request, **kwargs): |
|
506 return CustomChangeList |
|
507 |
|
508 class Villain(models.Model): |
|
509 name = models.CharField(max_length=100) |
|
510 |
|
511 def __unicode__(self): |
|
512 return self.name |
|
513 |
|
514 class SuperVillain(Villain): |
|
515 pass |
|
516 |
|
517 class FunkyTag(models.Model): |
|
518 "Because we all know there's only one real use case for GFKs." |
|
519 name = models.CharField(max_length=25) |
|
520 content_type = models.ForeignKey(ContentType) |
|
521 object_id = models.PositiveIntegerField() |
|
522 content_object = generic.GenericForeignKey('content_type', 'object_id') |
|
523 |
|
524 def __unicode__(self): |
|
525 return self.name |
|
526 |
|
527 class Plot(models.Model): |
|
528 name = models.CharField(max_length=100) |
|
529 team_leader = models.ForeignKey(Villain, related_name='lead_plots') |
|
530 contact = models.ForeignKey(Villain, related_name='contact_plots') |
|
531 tags = generic.GenericRelation(FunkyTag) |
|
532 |
|
533 def __unicode__(self): |
|
534 return self.name |
|
535 |
|
536 class PlotDetails(models.Model): |
|
537 details = models.CharField(max_length=100) |
|
538 plot = models.OneToOneField(Plot) |
|
539 |
|
540 def __unicode__(self): |
|
541 return self.details |
|
542 |
|
543 class SecretHideout(models.Model): |
|
544 """ Secret! Not registered with the admin! """ |
|
545 location = models.CharField(max_length=100) |
|
546 villain = models.ForeignKey(Villain) |
|
547 |
|
548 def __unicode__(self): |
|
549 return self.location |
|
550 |
|
551 class SuperSecretHideout(models.Model): |
|
552 """ Secret! Not registered with the admin! """ |
|
553 location = models.CharField(max_length=100) |
|
554 supervillain = models.ForeignKey(SuperVillain) |
|
555 |
|
556 def __unicode__(self): |
|
557 return self.location |
|
558 |
|
559 class CyclicOne(models.Model): |
|
560 name = models.CharField(max_length=25) |
|
561 two = models.ForeignKey('CyclicTwo') |
|
562 |
|
563 def __unicode__(self): |
|
564 return self.name |
|
565 |
|
566 class CyclicTwo(models.Model): |
|
567 name = models.CharField(max_length=25) |
|
568 one = models.ForeignKey(CyclicOne) |
|
569 |
|
570 def __unicode__(self): |
|
571 return self.name |
|
572 |
|
573 class Topping(models.Model): |
|
574 name = models.CharField(max_length=20) |
|
575 |
|
576 class Pizza(models.Model): |
|
577 name = models.CharField(max_length=20) |
|
578 toppings = models.ManyToManyField('Topping') |
|
579 |
|
580 class PizzaAdmin(admin.ModelAdmin): |
|
581 readonly_fields = ('toppings',) |
|
582 |
|
583 class Album(models.Model): |
|
584 owner = models.ForeignKey(User) |
|
585 title = models.CharField(max_length=30) |
|
586 |
|
587 class AlbumAdmin(admin.ModelAdmin): |
|
588 list_filter = ['title'] |
|
589 |
|
590 admin.site.register(Article, ArticleAdmin) |
|
591 admin.site.register(CustomArticle, CustomArticleAdmin) |
|
592 admin.site.register(Section, save_as=True, inlines=[ArticleInline]) |
|
593 admin.site.register(ModelWithStringPrimaryKey) |
|
594 admin.site.register(Color) |
|
595 admin.site.register(Thing, ThingAdmin) |
|
596 admin.site.register(Person, PersonAdmin) |
|
597 admin.site.register(Persona, PersonaAdmin) |
|
598 admin.site.register(Subscriber, SubscriberAdmin) |
|
599 admin.site.register(ExternalSubscriber, ExternalSubscriberAdmin) |
|
600 admin.site.register(OldSubscriber, OldSubscriberAdmin) |
|
601 admin.site.register(Podcast, PodcastAdmin) |
|
602 admin.site.register(Vodcast, VodcastAdmin) |
|
603 admin.site.register(Parent, ParentAdmin) |
|
604 admin.site.register(EmptyModel, EmptyModelAdmin) |
|
605 admin.site.register(Fabric, FabricAdmin) |
|
606 admin.site.register(Gallery, GalleryAdmin) |
|
607 admin.site.register(Picture, PictureAdmin) |
|
608 admin.site.register(Language, LanguageAdmin) |
|
609 admin.site.register(Recommendation, RecommendationAdmin) |
|
610 admin.site.register(Recommender) |
|
611 admin.site.register(Collector, CollectorAdmin) |
|
612 admin.site.register(Category, CategoryAdmin) |
|
613 admin.site.register(Post, PostAdmin) |
|
614 admin.site.register(Gadget, GadgetAdmin) |
|
615 admin.site.register(Villain) |
|
616 admin.site.register(SuperVillain) |
|
617 admin.site.register(Plot) |
|
618 admin.site.register(PlotDetails) |
|
619 admin.site.register(CyclicOne) |
|
620 admin.site.register(CyclicTwo) |
|
621 |
|
622 # We intentionally register Promo and ChapterXtra1 but not Chapter nor ChapterXtra2. |
|
623 # That way we cover all four cases: |
|
624 # related ForeignKey object registered in admin |
|
625 # related ForeignKey object not registered in admin |
|
626 # related OneToOne object registered in admin |
|
627 # related OneToOne object not registered in admin |
|
628 # when deleting Book so as exercise all four troublesome (w.r.t escaping |
|
629 # and calling force_unicode to avoid problems on Python 2.3) paths through |
|
630 # contrib.admin.util's get_deleted_objects function. |
|
631 admin.site.register(Book, inlines=[ChapterInline]) |
|
632 admin.site.register(Promo) |
|
633 admin.site.register(ChapterXtra1) |
|
634 admin.site.register(Pizza, PizzaAdmin) |
|
635 admin.site.register(Topping) |
|
636 admin.site.register(Album, AlbumAdmin) |