My model:
class Sample(models.Model):
users = models.ManyToManyField(User)
I want to save both user1
and user2
in that model:
user1 = User.objects.get(pk=1)
user2 = User.objects.get(pk=2)
sample_object = Sample(users=user1, users=user2)
sample_object.save()
I know that's wrong, but I'm sure you get what I want to do. How would you do it ?
You could replace the set of related objects in this way (new in Django 1.9):
Django 1.9
A quick example:
RelatedObjectManagers are different "attributes" than fields in a Model. The simplest way to achieve what you are looking for is
That's the same as assigning a User list, without the additional queries and the model building.
If the number of queries is what bothers you (instead of simplicity), then the optimal solution requires three queries:
This will work because we already know that the 'users' list is empty, so we can create mindlessly.
For future visitors, you can create an object and all of its m2m objects in 2 queries using the new bulk_create in django 1.4. Note that this is only usable if you don't require any pre or post-processing on the data with save() methods or signals. What you insert is exactly what will be in the DB
You can do this without specifying a "through" model on the field. For completeness, the example below creates a blank Users model to mimic what the original poster was asking.
Now, in a shell or other code, create 2 users, create a sample object, and bulk add the users to that sample object.
You cannot create m2m relations from unsaved objects. If you have the
pk
s, try this:Update: After reading the saverio's answer, I decided to investigate the issue a bit more in depth. Here are my findings.
This was my original suggestion. It works, but isn't optimal. (Note: I'm using
Bar
s and aFoo
instead ofUser
s and aSample
, but you get the idea).It generates a whopping total of 7 queries:
I'm sure we can do better. You can pass multiple objects to the
add()
method:As we can see, passing multiple objects saves one
SELECT
:I wasn't aware that you can also assign a list of objects:
Unfortunately, that creates one additional
SELECT
:Let's try to assign a list of
pk
s, as saverio suggested:As we don't fetch the two
Bar
s, we save twoSELECT
statements, resulting in a total of 5:And the winner is:
Passing
pk
s toadd()
gives us a total of 4 queries: