How can I customize the display of a model using contenttypes in the admin?
Asked Answered
E

2

6

I have these models:

class App(models.Model):
  name = models.CharField(max_length=100)

class ProjectA(models.Model):
  name = models.CharField(max_length=100)
  app  = models.ForeignKey(App)

class ProjectB(ProjectA):
  pass

class Attachment(models.Model):
  content_type    = models.ForeignKey(ContentType)
  object_id       = models.PositiveIntegerField()
  project         = generic.GenericForeignKey("content_type","object_id")
  file            = models.FileField(upload_to=".")

I'm registering all the models for the admin, and I'm unregistering Group, User and Site. The thing is, when I access the Attachment in the admin, I see it rendered like this:

admin for attachment

In the Content type select, I see this list:

select

The reason Attachment has a GenericForeignKey is because both ProjectA and ProjectB need to access it. I know that ProjectA and ProjectB are identical, but it's a requirement that they are stored in 2 separate tables. How could I made the Attachment class useable from the admin? I know how to use contenttypes from normal views, but from the admin not.

In the Attachment class I would only like to have a select for Project A or Project B, and then a list of all Project A's or all Project B's, followed by the file that I want to attach.

Is such a thing possible from the Admin? Will I need to show the user the Object Id column?

Elaterium answered 13/6, 2011 at 19:54 Comment(0)
E
7

if I'm not wrong, you want this. http://code.google.com/p/django-genericadmin/

my advice will work differently. you will add a little more form in ProjectA, ProjectB as inline. in your admin.py

from django.contrib import admin
from django.contrib.contenttypes import generic

from myproject.myapp.models import Attachment, ProjectA, ProjectB

class Attachmentline(generic.GenericTabularInline): #or generic.GenericStackedInline, this has different visual layout.
    model = Attachment

class ProjectAdmin(admin.ModelAdmin):
    inlines = [
        Attachmentline,
    ]

admin.site.register(ProjectA, ProjectAdmin)
admin.site.register(ProjectB, ProjectAdmin)

go your ProjectA or ProjectB admin and see new admin.

this isn't what you want but it can help you. otherwise you need check first link.

Ebner answered 14/6, 2011 at 10:39 Comment(2)
Beautiful alternative. Thank you!Elaterium
I did not know there was a generic.GenericTabularInlineHydromel
W
1

You should notice that

" know that ProjectA and ProjectB are identical, but it's a requirement that they are stored in 2 separate tables"

is not really correct. All the data is stored in your app_projecta table, and (only) some pointers are kept in table app_projectb. If you are already going in this path, I would suggest starting with this instead:

class App(models.Model):
  name = models.CharField(max_length=100)

class Project(models.Model):
    name = models.CharField(max_length=100)
    app = models.ForeignKey(App)

class ProjectA(Project):
  pass

class ProjectB(Project):
  pass

class Attachment(models.Model):
  project = models.ForeignKey(Project)
  file = models.FileField(upload_to=".")  

This already gets you a bit closer to where you want to get...

Weissmann answered 13/6, 2011 at 22:5 Comment(2)
Thanks. What about the choices field for the GenericForeignKey? Would you happen to know a solution for that?Elaterium
The method presented by Udi does not require the use of generic foreign keys. You only reference the Project model using plain old foreign keys. However, a drawback is that a Project can both be a ProjectA and a ProjectB, or neither. You will have to check for database consistency once in a while, if you offer the possibility of converting a ProjectA to a ProjectB.Standing

© 2022 - 2024 — McMap. All rights reserved.