687 | | {{{ |
688 | | #!python |
689 | | |
690 | | # OLD: |
691 | | from django.conf.urls.defaults import * |
692 | | |
693 | | urlpatterns = patterns('', |
694 | | (r'^admin/', include('django.contrib.admin.urls')), |
695 | | ) |
696 | | |
697 | | # NEW: |
698 | | from django.conf.urls.defaults import * |
699 | | from django.contrib import admin |
700 | | |
701 | | admin.autodiscover() |
702 | | |
703 | | urlpatterns = patterns('', |
704 | | (r'^admin/(.*)', admin.site.root), |
705 | | ) |
706 | | }}} |
707 | | |
708 | | Note that, in this above URLconf example, we're dealing with the object {{{django.contrib.admin.site}}}. This is an instance of {{{django.contrib.admin.AdminSite}}}, which is a class that lets you specify admin-site functionality. The object {{{django.contrib.admin.site}}} is a default {{{AdminSite}}} instance that is created for you automatically, but you can also create other instances as you see fit. |
709 | | |
710 | | We use the {{{admin.autodiscover()}}} call above to force the import of the {{{admin.py}}} module of each {{{INSTALLED_APPS}}} entry. This won't be needed if you use your own {{{AdminSite}}} instance since you will likely be importing those modules explicily in a project-level {{{admin.py}}}. This was added in [7872]. |
711 | | |
712 | | Previously, there was one "global" version of the admin site, which used all models that contained a {{{class Admin}}}. This new scheme allows for much more fine-grained control over your admin sites, allowing you to have multiple admin sites in the same Django instance. |
713 | | |
714 | | In this example, we create two {{{AdminSite}}} instances, registering different models with both. Assume {{{Book}}}, {{{Author}}}, {{{Musician}}} and {{{Instrument}}} are Django model classes (not instances). |
715 | | |
716 | | {{{ |
717 | | #!python |
718 | | |
719 | | # project-level admin.py |
720 | | |
721 | | from django.contrib import admin |
722 | | from myproject.myapp.models import Book, Author |
723 | | from myproject.anotherapp.models import Musician, Instrument |
724 | | |
725 | | site1 = admin.AdminSite() |
726 | | site1.register(Book) |
727 | | site1.register(Author) |
728 | | |
729 | | site2 = admin.AdminSite() |
730 | | site2.register(Musician) |
731 | | site2.register(Instrument) |
732 | | |
733 | | # URLconf |
734 | | |
735 | | from django.conf.urls.defaults import * |
736 | | from myproject.admin import site1, site2 |
737 | | |
738 | | urlpatterns = patterns('', |
739 | | (r'^book_admin/(.*)', site1.root), |
740 | | (r'^music_admin/(.*)', site2.root), |
741 | | ) |
742 | | }}} |
743 | | |
744 | | With this example, if you go to {{{/book_admin/}}}, you'll get a Django admin site for the {{{Book}}} and {{{Author}}} models. If you go to {{{/music_admin/}}}, you'll get a Django admin site for the {{{Musician}}} and {{{Instrument}}} models. |
745 | | |
746 | | Admin options -- the inner {{{class Admin}}} -- have changed, too. Models no longer use an inner class to declare their admin site options. In fact, '''all admin functionality has been decoupled from the model syntax'''! How, then, do we declare admin options? Like this: |
747 | | |
748 | | {{{ |
749 | | #!python |
750 | | # a sample models.py file |
751 | | from django.db import models |
752 | | |
753 | | class Author(models.Model): |
754 | | first_name = models.CharField(max_length=30) |
755 | | last_name = models.CharField(max_length=30) |
756 | | |
757 | | def __unicode__(self): |
758 | | return u'%s %s' % (self.first_name, self.last_name) |
759 | | |
760 | | class Book(models.Model): |
761 | | title = models.CharField(max_length=100) |
762 | | author = models.ForeignKey(Author) |
763 | | |
764 | | # a sample admin.py file (in same app) |
765 | | from django.contrib import admin |
766 | | from myproject.myapp.models import Author, Book |
767 | | |
768 | | class BookAdmin(admin.ModelAdmin): |
769 | | list_display = ('title', 'author') |
770 | | ordering = ('title',) |
771 | | |
772 | | admin.site.register(Author) |
773 | | admin.site.register(Book, BookAdmin) |
774 | | }}} |
775 | | |
776 | | In this example, we register both {{{Author}}} and {{{Book}}} with the {{{AdminSite}}} instance {{{django.contrib.admin.site}}}. {{{Author}}} doesn't need any custom admin options, so we just call {{{admin.site.register(Author)}}}. {{{Book}}}, on the other hand, has some custom admin options, so we define a {{{BookAdmin}}} class and pass that class as a second argument to {{{admin.site.register()}}}. |
777 | | |
778 | | You'll notice the {{{BookAdmin}}} class looks a lot like the old-style {{{class Admin}}}. Almost all of the old {{{class Admin}}} options work exactly the same, with one or two exceptions. (For the options that have changed, we've made them '''much''' more powerful.) In addition to the classic options such as {{{list_display}}} and {{{ordering}}}, the {{{ModelAdmin}}} class introduces a wealth of extra hooks you can use to customize the admin site for that particular model. For example: |
779 | | |
780 | | {{{ |
781 | | #!python |
782 | | |
783 | | class BookAdmin(admin.ModelAdmin): |
784 | | list_display = ('title', 'author') |
785 | | ordering = ('title',) |
786 | | |
787 | | def has_change_permission(self, request, obj=None): |
788 | | """ |
789 | | John can only edit books by Roald Dahl. |
790 | | """ |
791 | | if obj and request.user.username == 'john': |
792 | | return obj.author.last_name == 'Dahl' |
793 | | return super(BookAdmin, self).has_change_permission(request, obj) |
794 | | }}} |
795 | | |
796 | | Look at the class {{{ModelAdmin}}} in the file [source:/django/branches/newforms-admin/django/contrib/admin/options.py django/contrib/admin/options.py] to see all of the methods you can override. This is exciting stuff. |
797 | | |
798 | | == To-do list == |
799 | | |
800 | | * See [http://code.djangoproject.com/query?status=new&status=assigned&status=reopened&keywords=%7Enfa-blocker&order=priority list of tickets] blocking the merge to trunk. |
801 | | * See [http://code.djangoproject.com/query?status=new&status=assigned&status=reopened&keywords=%7Enfa-someday&order=priority list of tickets] that will be looked at after a merge to trunk. |
802 | | * See [http://code.djangoproject.com/query?status=new&status=assigned&status=reopened&status=closed&keywords=%7Enfa-fixed&order=priority list of tickets] that have been fixed. |
803 | | |
804 | | == Backwards-incompatible changes == |
805 | | |
806 | | This is a (currently incomplete) list of backwards-incompatible changes made in this branch. |
807 | | |