Múltiples ModelAdmins / views para el mismo modelo en Django admin

150

¿Cómo puedo crear más de un ModelAdmin para el mismo modelo, cada uno personalizado de manera diferente y vinculado a diferentes URL?

Digamos que tengo un modelo de Django llamado Posts. De forma predeterminada, la vista de administrador de este modelo enumerará todos los objetos de publicación.

Sé que puedo personalizar la lista de objetos que se muestran en la página de varias maneras estableciendo variables como list_display o anulando el querysetmétodo en mi ModelAdmin de la siguiente manera:

class MyPostAdmin(admin.ModelAdmin):
    list_display = ('title', 'pub_date')

    def queryset(self, request):
        request_user = request.user
        return Post.objects.filter(author=request_user)

admin.site.register(MyPostAdmin, Post)

Por defecto, esto sería accesible en la URL /admin/myapp/post. Sin embargo, me gustaría tener múltiples vistas / ModelAdmins del mismo modelo. por ejemplo /admin/myapp/post, enumeraría todos los objetos de publicación y /admin/myapp/mypostsenumeraría todas las publicaciones que pertenecen al usuario, y /admin/myapp/draftpostpodría enumerar todas las publicaciones que aún no se han publicado. (estos son solo ejemplos, mi caso de uso real es más complejo)

No puede registrar más de un ModelAdmin para el mismo modelo (esto da como resultado una AlreadyRegisteredexcepción). Idealmente, me gustaría lograr esto sin poner todo en una sola clase ModelAdmin y escribir mi propia función 'urls' para devolver un conjunto de consultas diferente dependiendo de la URL.

He echado un vistazo a la fuente de Django y veo que funciones como ModelAdmin.changelist_viewesa podrían incluirse de alguna manera en mi urls.py, pero no estoy seguro de cómo funcionaría.

Actualización : He encontrado una forma de hacer lo que quiero (ver más abajo), pero todavía me gustaría escuchar otras formas de hacerlo.

Paul Stone
fuente

Respuestas:

275

He encontrado una manera de lograr lo que quiero, mediante el uso de modelos proxy para evitar el hecho de que cada modelo puede registrarse solo una vez.

class PostAdmin(admin.ModelAdmin):
    list_display = ('title', 'pubdate','user')

class MyPost(Post):
    class Meta:
        proxy = True

class MyPostAdmin(PostAdmin):
    def get_queryset(self, request):
        return self.model.objects.filter(user = request.user)


admin.site.register(Post, PostAdmin)
admin.site.register(MyPost, MyPostAdmin)

Entonces, el PostAdminacceso predeterminado sería accesible en /admin/myapp/posty la lista de publicaciones propiedad del usuario estaría en /admin/myapp/myposts.

Después de mirar http://code.djangoproject.com/wiki/DynamicModels , se me ocurrió la siguiente función de función para hacer lo mismo:

def create_modeladmin(modeladmin, model, name = None):
    class  Meta:
        proxy = True
        app_label = model._meta.app_label

    attrs = {'__module__': '', 'Meta': Meta}

    newmodel = type(name, (model,), attrs)

    admin.site.register(newmodel, modeladmin)
    return modeladmin

Esto se puede usar de la siguiente manera:

class MyPostAdmin(PostAdmin):
    def get_queryset(self, request):
        return self.model.objects.filter(user = request.user)

create_modeladmin(MyPostAdmin, name='my-posts', model=Post)
Paul Stone
fuente
8
Esto es asombroso. No sabía que un modelo de proxy podría registrarse en el sitio de administración. Esto realmente me ayudará mucho.
Brandon Henry
8
También necesitaba registrar los mismos modelos dos veces en django admin y los modelos proxy parecen funcionar. Pero encontré un problema con el sistema de permisos. Ver aquí: code.djangoproject.com/ticket/11154
bjunix el
44
También es una buena idea cambiar el administrador predeterminado en lugar del conjunto de consultas ModelAdmin. Por lo tanto, el comportamiento del modelo proxy es coherente incluso fuera del administrador.
bjunix
44
Ahora la respuesta real es, ¿por qué django no te permite tener dos administradores para el mismo modelo? no deberíamos necesitar hackear cosas por solo 2 líneas que verifican eso y arrojan un error: s. Gran respuesta aún!
Hassek el
1
@zzart: hay una solicitud de extracción pendiente, que parece faltar documentos: github.com/django/django/pull/146/files
azulada
3

¡La respuesta de Paul Stone es absolutamente genial! Solo para agregar, para Django 1.4.5 necesitaba heredar mi clase personalizada deadmin.ModelAdmin

class MyPostAdmin(admin.ModelAdmin):
    def queryset(self, request):
        return self.model.objects.filter(id=1)
zzart
fuente