1

I have the following models:

class Foo(models.Model):
    field1 = models.IntegerField()
    ...

class Bar(models.Model):
    field1 = models.IntegerField()
    ...

class Foo_bar(models.Model):
    foo = models.ForeignKey(Foo)
    bar = models.ForeignKey(Bar)
    ...

In the admin, I want it so that in the Foo change/add page, you can specify a Bar object, and on save I want to create a Foo_bar object to represent the relationship. How can I do this through customizing the Admin site/ModelAdmins? Note that inlining isn't quite what I need because there is no explicit foreign key relationship between foo and bar. And second, I don't actually want to edit bar objects, I just want to choose from amongst the ones that are in the system.

Thanks.

Neil
  • 7,042
  • 9
  • 43
  • 78

3 Answers3

2

Are you sure you don't just want a ManyToManyField? In the admin, this would manifest as a multiple-selection list of Bar objects. Look at the group selection part of the admin for User.

If you need additional data attached to the relationship, you could use a through parameter:

class Foo(models.Model):
    field1 = models.IntegerField()
    bars = models.ManyToManyField("Bar", related_name="foos", through="Foo_bar")

You'll need to add Foo_bar to the admin in order to edit these additional parameters in the admin.

Mike DeSimone
  • 41,631
  • 10
  • 72
  • 96
  • Thanks! If I declare the ManyToManyField in Bar, can I get it to show up in Foo? – Neil May 18 '10 at 00:24
  • That's what the `related_name` parameter is all about. Using my example, every `Foo` object has a `bars` field that is the M2M, and every `Bar` object has a `foos` field that is the reverse-going relation. So it doesn't matter much which one you put the `ManyToManyField` in; you'll get both directions automatically. Just don't put it in both models, or it will mock you. – Mike DeSimone May 18 '10 at 02:47
  • Also check out the `limit_choices_to` parameter, described in `ForeignKey`'s docs, for a way to keep the size of the list down. One more thing: in the admin, the relation only shows up in the admin for the model that declared the `ManyToManyField`. – Mike DeSimone May 18 '10 at 02:50
  • Are you sure just adding 'related_name' will make the Foo listbox show up in Bar's admin page? According to this, you might need to do more than that: http://stackoverflow.com/questions/1339409/how-to-add-bi-directional-manytomanyfields-in-django-admin – Neil May 18 '10 at 03:04
  • See the last sentence of my previous comment. – Mike DeSimone May 18 '10 at 03:57
  • It seems I misinterpreted your first comment. I thought you were speaking of the models, not the admins. – Mike DeSimone May 18 '10 at 03:58
1

I can think of two possibilities:

  1. You could create a custom form for your Foo model and add a field containing the Bar.objects.all() queryset to it. then override the ModelAdmin's default save_form() method to create a new Bar instance upon saving the object.

  2. You could create a custom Field class and add it to you Foo model, and class this functionality via a ´post_save` signal...

Bernhard Vallant
  • 49,468
  • 20
  • 120
  • 148
0

For those actually looking to add an unrelated model field to add/change, use ModelChoiceField

from django import forms

class CustomForm(forms.Form):
    foo = forms.ModelChoiceField(queryset=Foo.objects.all())
    bar = forms.ModelChoiceField(queryset=Bar.objects.all())

Then simply add the form to the ModelAdmin's add_form/change_form

Bemis
  • 3,092
  • 2
  • 17
  • 24