I was hoping to bring up some ManyToMany enhancements at the sprint,
but I didn't manage to participate after all, so they went unvoiced.
Instead, I'll bring up some thoughts here and see what you guys think.
I apologize in advance for the length of this post, but if you're
interested in seeing M2M stuff work better, I think it's worth the
read.

The more I read about what people want out of M2M fields, the more I
think we need to define relationships as a separate high-level
structure. I'm thinking of adding a Relationship class to the mix,
which would be subclassed much like the existing Model class. This
Relationship would then reuse much of the existing Model system to
provide more flexibility to developers.

For instance, a Relationship subclass could optionally have fields to
describe the relationship, such as "role" in the now-ubiquitous
Actor-Film example. In that example, "role" would just be an instance
of CharField, just like on a Model.

Additionally, by including a separate Relationship class, any defined
subclasses could also define a Meta class for more fine-grained
control. Using django.db.models.options.Options would be necessary
anyway, in order to reuse contribute_to_class() on existing Field
types, so it makes sense to just allow developers to define Meta
directly if needed. This would allow custom values for db_table
(currently impossible for standard M2M), verbose_name and
verbose_name_plural (useful for edit_inline, possibly), even ordering
and unique_together.

Ultimately, the Relationship would create a Model behind the scenes,
which will be used to actually store and retrieve the data.This hidden
Model would share the Meta options and fields declared on the
Relationship, as well as have ForeignKey fields for the related
models. This would allow manage.py commands like sql, reset and syncdb
to treat it as a standard Django model, rather than having to branch
into oddities to handle M2M tables. This would (I hope) replace all of
the hackery that's currently in place to deal with the hidden M2M
table, swapping it out for something that's far more in line with the
rest of Django.

For existing code, the ManyToManyField would be modified to simply
create a Relationship behind the scenes, and then reference that as if
it were supplied by the developer.

The base Relationship class would also have a set of methods on it to
supply behaviour for add(), remove() and the like. That way,
individual Relationships could override those methods to provide
custom features, like notification of new relationships, limits on
what types of relationships can happen, etc.

The questions then become (not meant to be exhaustive):

* Should something like this happen?
* What fields should a Relationship define? Namely, should the related
models be included explicitly as ForeignKeys?
* 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?
* How would add(), remove() and company reference the related models
in a reliable fashion?
* How would syncdb generate the SQL for the relationship?
* What backward compatibility concerns are there?

Personally, I'd answer these questions like so.

Yes, it should definitely happen. Obviously, or I wouldn't be recommending it.

A Relationship should define all the fields that would be present on a
Model that would represent the relationship table. So ForeignKeys
would be supplied explicitly on the Relationship class (more on why
below).

By including ForeignKeys in the Relationship definition, the existing
related_name code will kick in and supply a manager on the related
Models. Of course, this would have to be modified somewhat to provide
a manager more knowledgeable about ManyToMany fields, but that's
already being done elsewhere, and should be able to be done here as
well (I hope).

By being methods on the Relationship itself, add(), remove() and
whatnot else would have access to the related models via ForeignKey
fields (and other relationship fields via standard mechanisms)
directly as attributes of "self". So the signatures for all of them
could be simply add(self), remove(self), etc. This way, there's never
any confusion, regardless of which direction the relationship is being
modified. For the case of adding multiple objects at once, add(self)
would simply called multiple times, once for each object being added.

Since it would create a true Model behind the scenes, using any
options specified in Meta, syncdb would already have everything it
needs to generate SQL. Including ForeignKeys ensures that even
REFERENCES and the like are generated correctly, without any special
handling as an M2M table.

For developers using the current ManyToManyField, there would be no
change. A Relationship would be created behind the scenes, matching
the existing features, like table name and column names. This would
then be able to access their existing data without a hiccup.

For those using additional fields, who have thus resorted to creating
a separate Model for the relationship, they can just change the
subclass from models.Model to models.Relationship and the rest comes
for free. This is another bonus of specifying ForeignKey fields on the
Relationship.

I have a little bit of code laid down for this already, but not enough
to be nearly functional. If there's sufficient interest in this
approach, I'll flesh it out and submit a ticket for it. If not, tell
me now so we can discuss other options.

-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