On 8/21/06, James Punteney <[EMAIL PROTECTED]> wrote:
Thanks for the responses, and yeah Maciej is correct the m2m
relationship works fine without any errors, it's just that I can only
edit the prey relationship (as Maciej text art does a much better job
of showing than my explanation).

Ok. Now we're on the same page :-)

When I try adding a predator field so I have this in my model:
prey = models.ManyToManyField("self", related_name="predator",
symmetrical=False)
predator = models.ManyToManyField("self", related_name="prey",
symmetrical=False)

Then it gives the following errors:

As you should expect. The related names clash with the existing fields - yielding the errors you receive. Django automatically adds the 'other' side of the m2m relation - you shouldn't (and are prevented) from manually adding it yourself. 

If this is something the admin interface can't do then any pointers on
how to customize it or where to look for more information would be
great.

To the best of my knowledge, no - the admin interface can't do this. This is a limitation of the automatic manipulator framework. If you pull apart the manipulators, they only represent value, OneToOne, ForeignKey and ManyToMany fields, plus the reverse direction of Foreign Keys. M2M objects are not traversed in reverse.

As a result, the admin interface can't represent the reverse direction of the relation like you describe.

The same is also true of your own views if you use the default Add/Change manipulators. However, if you are working with your own view, you can customize the default manipulators to do most of the heavy lifting for you. Here's how:

1) Obtain a default manipulator:

    manipulator = Animal.ChangeManipulator(id)
 
2) Tweak the 'fields' member of the manipulator, manually adding a field to represent the reverse field.

    choices = [( a.id, a) for a in Animal.objects.all()]
    predator_field = forms.SelectMultipleField('predator',
                                  choices=choices,
                                  size=min(max(len(choices),5),15))
    manipulator.fields.append(predator_field)

    Choices is a list of (id, display value) tuples of available options. The size field is used in the rendering of the html element.

3) Construct a form wrapper, extract post data, validate, and save as normal for a validator

4) Extract the data relating to the reverse field. Assuming that new_data is the duplicate of the post dictionary:

     if new_data.getlist('predator'):
            Animal.predator = Animals.objects.filter (id__in=new_data.getlist('predator'))

    This doesn't require an explicit save, because it is modifying a m2m descriptor (which automatically save). Side note - this example highlights a problem with your model - your related_field name should be a plural, as it describes a set of predators, not a single predator.

Modify your template to include a {{ form.predator }} element, and you're in business. If you include both a {{ form.predator }} and {{ form.prey }} element in your template, be aware that you could get some interesting behaviour, as changing the selection in one input element won't change the selection in another. As a result, it is possible for a change in one input to be overwritten by a change in a different element.

Yours,
Russ Magee %-)


--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups "Django users" group.
To post to this group, send email to django-users@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at http://groups.google.com/group/django-users
-~----------~----~----~----~------~----~------~--~---

Reply via email to