Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to add bi-directional manytomanyfields in django admin?

In my models.py i have something like:

class LocationGroup(models.Model):
    name = models.CharField(max_length=200)

class Report(models.Model):
    name = models.CharField(max_length=200)
    locationgroups = models.ManyToManyField(LocationGroup)

admin.py (standard):

admin.site.register(LocationGroup)
admin.site.register(Report)

When I enter the admin page for Report, it shows a nice multiple choice field. How can I add the same multiple choice field in LocationGroup? I can access all Reports by calling LocationGroup.report_set.all()

like image 539
Jack Ha Avatar asked Aug 27 '09 07:08

Jack Ha


3 Answers

The workaround I found was to follow the instructions for ManyToManyFields with intermediary models. Even though you're not using the 'through' model feature, just pretend as if you were and create a stub model with the necessary ForeignKey.

# models:  make sure the naming convention matches what ManyToManyField would create
class Report_LocationGroups(models.Model):
    locationgroup = models.ForeignKey(LocationGroup)
    report = models.ForeignKey(Report)

# admin
class ReportInline(admin.TabularInline):
    model = models.Report_LocationGroups

class LocationGroupAdmin(admin.ModelAdmin):
    inlines = ReportInline,
like image 192
A. Coady Avatar answered Oct 10 '22 15:10

A. Coady


I think yon can combine this sample code (source) wich breaks sync_db

class ItemType(meta.Model):
    name = meta.CharField(maxlength=100)
    description = meta.CharField(maxlength=250)
    properties = meta.ManyToManyField('PropertyType',
            db_table='app_propertytype_itemtypes')

class PropertyType(meta.Model):
    name = meta.CharField(maxlength=100)
    itemtypes = meta.ManyToManyField(ItemType)

with this snippet

class ManyToManyField_NoSyncdb(models.ManyToManyField):
    def __init__(self, *args, **kwargs):
        super(ManyToManyField_NoSyncdb, self).__init__(*args, **kwargs)
       self.creates_table = False

to obtain something like

class ItemType(meta.Model):
    name = meta.CharField(maxlength=100)
    description = meta.CharField(maxlength=250)
    properties = meta.ManyToManyField_NoSyncdb('PropertyType',
            db_table='app_propertytype_itemtypes')

class PropertyType(meta.Model):
    name = meta.CharField(maxlength=100)
    itemtypes = meta.ManyToManyField(ItemType)

Disclaimer : this is just a rough idea

Edit: There is probably someting to do with Django's 1.1 Proxy Models

like image 26
Pierre-Jean Coudert Avatar answered Oct 10 '22 13:10

Pierre-Jean Coudert


I think what are you are looking for is admin inlines. In your admin.py you will want to add something like this:

class LocationGroupInline(admin.TabularInline):
    model = LocationGroup

class ReportAdmin(admin.ModelAdmin):
    inlines = [ LocationGroupInline, ]
admin.site.register(Report, ReportAdmin)
admin.site.register(LocationGroup)

There are many options to include in LocationGroupInline if you want to further configure the inline display of the related model. Two of these options are form and formset, which will let you use custom Django Form and FormSet classes to further customize the look and feel of the inline model admin. Using this you can create a simple Form that displays just the multiple choice field you want (except for a M2M field it will not be possible to display as a single drop down, but a multiple select box). For example:

class MyLocationGroupForm(forms.Form):
    location = forms.MultipleModelChoiceField(
           queryset=LocationGroup.objects.all())

class LocationGroupInline(admin.TabularInline):
    model = LocationGroup
    form = MyLocationGroupForm
like image 42
Jesse L Avatar answered Oct 10 '22 14:10

Jesse L