On 9/18/07, Russell Keith-Magee <[EMAIL PROTECTED]> wrote:
> First off - I acknowledge the underlying problem (making m2m
> intermediate models easier to use), and I would like to see a
> solution. However, while I'm sure your propsed solution could be made
> to work, I'm not sure it would be a good solution to the problem.

And I'm glad to hear opposition, it helps makes things that much cleaner.

> The biggest problem with the "m2m intermediate" pattern is that it
> requires you to think about an m2m relation as 'a model with a foreign
> key on two other models', which while completely accurate, is not a
> natural way to think about the problem (witness the large number of
> users who ask for explanations of the m2m intermediate example).

I admit I don't have experience with how many people ask for
explanations of that pattern, but I can understand your point all the
same.

> The syntax you propose here aims to formalize the use of this pattern,
> adding accessors on the related objects. This means that defining an
> m2m relation ceases to be a simple matter of putting a field on one
> model that references another model, and becomes an exposition of a
> not-entirely-obvious pattern. This pattern is syntactically verbose,
> and has a few edge cases which would require it to be more verbose.
>
> For example: consider what happens when you define a Relationship with
> _three_ foreign keys. Which two get magically picked as the m2m keys?
> This means that you need to add a keyword to ForeignKeys to identify
> the m2m keys, or you need to add a RelationshipKey class with
> validation logic to make sure that you have exactly 2 instances.

I admit that this situation had crossed my mind in the previous
discussion, and I had simply set it aside for the time being.
Unfortuantely, I neglected to pick it back up before writing up this
proposal. I wish I could say that's unlikely, but it's not even an
edge case, really. In a Person-Role-Film scenario, the Role
relationship could have a ForeignKey to some RoleCategory, indicating
whether it's an acting role, directing, production, set design, etc.

So, point taken.

> > * Should something like this happen?
>
> If you go back into the archives to the last time you raised this
> issue [1], you'll see that Jacob and I are in agreement that there is
> significant room to improve the interface for m2m intermediate
> classes.

Well, wen I wrote "something like this" I meant "something like the
design I'm proposing here". Obviously everybody wants a better way to
do this, I just wasn't sure if my existing proposal was even worth
considering.

> > * How should the Relationship be tied to related Models? Through
> > explicit ForeignKeys on the Relationship? Through a new "through"
> > attribute on ManyToManyField? Something else entirely?
>
> The 'through' attribute has always been the suggested syntax.

And I'm beginning to lean more that way myself, after some more
reflection. More on that below.

> > * How would add(), remove() and company reference the related models
> > in a reliable fashion?
>
> This has always been the sticking point. However, a pretty good
> solution came out of the discussion the last time this came up.

Are you referring to the ManyToManyHelper I proposed recently? The
discussion you linked to didn't really touch on this issue, so I
figure you probably are. That proposal still has a lot of ambiguity as
to which side of the relationship triggered the add(), though
admittedly that's not *as* necessary. What's really necessary is
having arguments to the function which are quite clear as to what they
reference. I'm beginning to think that signals may indeed be the way
to go here.

Okay, so to go about this a little differently, here's another option,
which should be more in line with the existing sentiments on the
issue.

class Actor(models.Model):
    name = models.CharField(maxlength=255)

class CrewMember(models.Model):
    name = models.CharField(maxlength=255)

class Role(models.Relationship):
    name = models.CharField(maxlength=255)

class Film(models.Model):
    title = models.CharField(maxlength=255)
    actors = models.ManyToManyField(Actor, through=Role)
    crew = models.ManyToManyField(CrewMember, through=Role)

This eliminates the explicit ForeignKeys, relying on the
ManyToManyField's definition to specify those. As shown, this would
also allow (and, in essence, encourage) relationships to be reusable.
In this case, the Role relationship could be used to link two
different pairs of models, with each relationship forming a separate
table behind the scenes. Of course, this means that it no longer makes
sense to have an inner Meta class on Role, but that was probably a bad
approach anyway. The db_table can still be optionally specified the
same way it is now, in ManyToManyField.

Now, yes, I realize that this looks almost exactly like what you guys
told me to do last time, but I think it's still worth separating
Relationship from Model, so that it doesn't look like just any other
model, but with some sparkly magic involved. The default manager for
Relationship would probably be considerably different as well, but I
haven't thought much about that yet. It would still make sense (to me)
to create a full-fledged Model behind the scenes though, so that the
existing model Fields can simply be passed over to that and let syncdb
and company be happy with a proper Model.

I think I can make signals work well, if the signal provides a few
arguments. I'm think that if it sent "sender" (the Relationship),
"origin" and "related" (the two models), people should be able to
register functions to do just about anything. I'm not sure though,
there are still some questions about how it would be registered, and
whether a single function could adequately handle being called from
both sides. I'm trying to stick to DRY here, but it's a tricky one.

-Gul

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Django developers" group.
To post to this group, send email to django-developers@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-developers?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to