Is there a fundamental reason that I'm missing (other than "nobody's taken the trouble of writing it") that I can't do the following? If there isn't I'll create a ticket for it.
class R(Model): user = ForeignKey(User) my_model = ForeignKey('MyModel') comment = CharField(max_length=100, blank=True)
class MyModel(Model): users = ManyToManyField(User, through=R, null=True)
m = MyModel.objects.create() u = User.objects.create_user('roald', 'downa...@gmail.com', 'password')
# these things I can't do: m.users.add(u) m.users.add(u, comment='Blablabla')
> Is there a fundamental reason that I'm missing (other than "nobody's taken > the trouble of writing it") that I can't do the following? If there isn't > I'll create a ticket for it.
> class R(Model): > user = ForeignKey(User) > my_model = ForeignKey('MyModel') > comment = CharField(max_length=100, blank=True)
> class MyModel(Model): > users = ManyToManyField(User, through=R, null=True)
> m = MyModel.objects.create() > u = User.objects.create_user('roald', 'downa...@gmail.com', 'password')
> # these things I can't do: > m.users.add(u) > m.users.add(u, comment='Blablabla')
> Cheers, Roald
I'm 100% sure there's *at least one* ticket for this. You just need to search for it and you'll probably find the discussion of this too.
> Is there a fundamental reason that I'm missing (other than "nobody's taken the trouble of writing it") that I can't do the following? If there isn't I'll create a ticket for it.
> class R(Model): > user = ForeignKey(User) > my_model = ForeignKey('MyModel') > comment = CharField(max_length=100, blank=True)
> class MyModel(Model): > users = ManyToManyField(User, through=R, null=True)
> m = MyModel.objects.create() > u = User.objects.create_user('roald', 'downa...@gmail.com', 'password')
> # these things I can't do: > m.users.add(u) > m.users.add(u, comment='Blablabla')
You can't use add() when specifying the intermediate model. You would have to check all fields of the intermediate model and make sure all of them have defaults or are allowed to be null. It might not be worth the trouble of implementing it.
>> Is there a fundamental reason that I'm missing (other than >> "nobody's taken the trouble of writing it") that I can't do the >> following? If there isn't I'll create a ticket for it.
>> class R(Model): >> user = ForeignKey(User) >> my_model = ForeignKey('MyModel') >> comment = CharField(max_length=100, blank=True)
>> class MyModel(Model): >> users = ManyToManyField(User, through=R, null=True)
>> m = MyModel.objects.create() >> u = User.objects.create_user('roald', 'downa...@gmail.com', >> 'password')
>> # these things I can't do: >> m.users.add(u) >> m.users.add(u, comment='Blablabla')
> You can't use add() when specifying the intermediate model. You > would have to check all fields of the intermediate model and make > sure all of them have defaults or are allowed to be null. It might > not be worth the trouble of implementing it.
I don't see how this is different from the create method on the intermediary model.
> On 20 September 2011 15:52, Roald de Vries <downa...@gmail.com> wrote: >> Hi all,
>> Is there a fundamental reason that I'm missing (other than "nobody's taken >> the trouble of writing it") that I can't do the following? If there isn't >> I'll create a ticket for it.
>> class R(Model): >> user = ForeignKey(User) >> my_model = ForeignKey('MyModel') >> comment = CharField(max_length=100, blank=True)
>> class MyModel(Model): >> users = ManyToManyField(User, through=R, null=True)
>> m = MyModel.objects.create() >> u = User.objects.create_user('roald', 'downa...@gmail.com', 'password')
>> # these things I can't do: >> m.users.add(u) >> m.users.add(u, comment='Blablabla')
>> Cheers, Roald
> I'm 100% sure there's *at least one* ticket for this. You just need to > search for it and you'll probably find the discussion of this too.
#9475 [1] is the ticket for the default value case. Russell's comments indicate that the other case (providing extra attributes for the intermediary model) may also be in scope for this ticket.
Here is the function definition for add() on related object manager:
add(obj1[, obj2, ...])
As you can see, it can be used to add multiple objects to the relationship in one go, and therefore the arguments to this function would need to change to support what you propose. This would require going through the whole deprecation procedure (2/3 major releases before it is gone), and I guess the pain outweighs the gain on that one.
create() takes **kwargs, but those arguments relate to the instance being created on the other end of the relationship, there would still be no way to specify non-default values for the intermediate model. You would have to do something similar to passing a defaults dictionary to create(), which then makes it different to how create() on an object manager works, and introduces another field that you would have to do some magic to work around.
I guess the main thing is what's the point? The argument is over which of these is prettier:
Beauty contests in code are rather pointless - the documentation has for a long time said that the latter is the only way you can do it, and most developers are now used to that.
> Here is the function definition for add() on related object manager:
> add(obj1[, obj2, ...])
> As you can see, it can be used to add multiple objects to the > relationship in one go, and therefore the arguments to this function > would need to change to support what you propose. This would require > going through the whole deprecation procedure (2/3 major releases > before it is gone), and I guess the pain outweighs the gain on that > one.
add(*objs, **kwargs) is backward compatible with add(*objs), so that's not the reason a deprecation procedure is needed. The thing that might be considered backward incompatible is the fact that with this new feature, the 'add' method is also defined on ManyRelatedManagers with explicit intermediary models.
> create() takes **kwargs, but those arguments relate to the instance > being created on the other end of the relationship, there would still > be no way to specify non-default values for the intermediate model. > You would have to do something similar to passing a defaults > dictionary to create(), which then makes it different to how create() > on an object manager works, and introduces another field that you > would have to do some magic to work around.
> I guess the main thing is what's the point? The argument is over which > of these is prettier:
> Beauty contests in code are rather pointless - the documentation has > for a long time said that the latter is the only way you can do it, > and most developers are now used to that.
I don't want to forbid the second form, you may still use it if you like it better. For me, it seems more consistent (which I think is more beautiful) to create a relation between 2 instances from one of the instances, because I always access the other instance through the ManyRelatedManager on the one. If there are enough people that like the first form, then that's the point.
> On 20 September 2011 15:52, Roald de Vries <downa...@gmail.com> wrote: >> Hi all,
>> Is there a fundamental reason that I'm missing (other than "nobody's taken >> the trouble of writing it") that I can't do the following? If there isn't >> I'll create a ticket for it.
>> class R(Model): >> user = ForeignKey(User) >> my_model = ForeignKey('MyModel') >> comment = CharField(max_length=100, blank=True)
>> class MyModel(Model): >> users = ManyToManyField(User, through=R, null=True)
>> m = MyModel.objects.create() >> u = User.objects.create_user('roald', 'downa...@gmail.com', 'password')
>> # these things I can't do: >> m.users.add(u) >> m.users.add(u, comment='Blablabla')
>> Cheers, Roald
> I'm 100% sure there's *at least one* ticket for this. You just need to > search for it and you'll probably find the discussion of this too.
There certainly is "at least one" ticket :-)
There's the original ticket that introduced m2m intermediate models:
Back when the feature was added (#6095), we discussed add() with intermediate models that have extra data. If you read the full ticket history for #6095, and #9475, you can see the edge cases that existed at the time. Ultimately, we punted on the issue in the interest of delivering *something*.
I'm certainly interested in the idea, as long as the edge cases can be managed and/or explained.