How to create an object for a Django model with a many to many field?
You cannot create m2m relations from unsaved objects. If you have the pk
s, try this:
sample_object = Sample()
sample_object.save()
sample_object.users.add(1,2)
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 a Foo
instead of User
s and a Sample
, but you get the idea).
bar1 = Bar.objects.get(pk=1)
bar2 = Bar.objects.get(pk=2)
foo = Foo()
foo.save()
foo.bars.add(bar1)
foo.bars.add(bar2)
It generates a whopping total of 7 queries:
SELECT "app_bar"."id", "app_bar"."name" FROM "app_bar" WHERE "app_bar"."id" = 1
SELECT "app_bar"."id", "app_bar"."name" FROM "app_bar" WHERE "app_bar"."id" = 2
INSERT INTO "app_foo" ("name") VALUES ()
SELECT "app_foo_bars"."bar_id" FROM "app_foo_bars" WHERE ("app_foo_bars"."foo_id" = 1 AND "app_foo_bars"."bar_id" IN (1))
INSERT INTO "app_foo_bars" ("foo_id", "bar_id") VALUES (1, 1)
SELECT "app_foo_bars"."bar_id" FROM "app_foo_bars" WHERE ("app_foo_bars"."foo_id" = 1 AND "app_foo_bars"."bar_id" IN (2))
INSERT INTO "app_foo_bars" ("foo_id", "bar_id") VALUES (1, 2)
I'm sure we can do better. You can pass multiple objects to the add()
method:
bar1 = Bar.objects.get(pk=1)
bar2 = Bar.objects.get(pk=2)
foo = Foo()
foo.save()
foo.bars.add(bar1, bar2)
As we can see, passing multiple objects saves one SELECT
:
SELECT "app_bar"."id", "app_bar"."name" FROM "app_bar" WHERE "app_bar"."id" = 1
SELECT "app_bar"."id", "app_bar"."name" FROM "app_bar" WHERE "app_bar"."id" = 2
INSERT INTO "app_foo" ("name") VALUES ()
SELECT "app_foo_bars"."bar_id" FROM "app_foo_bars" WHERE ("app_foo_bars"."foo_id" = 1 AND "app_foo_bars"."bar_id" IN (1, 2))
INSERT INTO "app_foo_bars" ("foo_id", "bar_id") VALUES (1, 1)
INSERT INTO "app_foo_bars" ("foo_id", "bar_id") VALUES (1, 2)
I wasn't aware that you can also assign a list of objects:
bar1 = Bar.objects.get(pk=1)
bar2 = Bar.objects.get(pk=2)
foo = Foo()
foo.save()
foo.bars = [bar1, bar2]
Unfortunately, that creates one additional SELECT
:
SELECT "app_bar"."id", "app_bar"."name" FROM "app_bar" WHERE "app_bar"."id" = 1
SELECT "app_bar"."id", "app_bar"."name" FROM "app_bar" WHERE "app_bar"."id" = 2
INSERT INTO "app_foo" ("name") VALUES ()
SELECT "app_foo_bars"."id", "app_foo_bars"."foo_id", "app_foo_bars"."bar_id" FROM "app_foo_bars" WHERE "app_foo_bars"."foo_id" = 1
SELECT "app_foo_bars"."bar_id" FROM "app_foo_bars" WHERE ("app_foo_bars"."foo_id" = 1 AND "app_foo_bars"."bar_id" IN (1, 2))
INSERT INTO "app_foo_bars" ("foo_id", "bar_id") VALUES (1, 1)
INSERT INTO "app_foo_bars" ("foo_id", "bar_id") VALUES (1, 2)
Let's try to assign a list of pk
s, as saverio suggested:
foo = Foo()
foo.save()
foo.bars = [1,2]
As we don't fetch the two Bar
s, we save two SELECT
statements, resulting in a total of 5:
INSERT INTO "app_foo" ("name") VALUES ()
SELECT "app_foo_bars"."id", "app_foo_bars"."foo_id", "app_foo_bars"."bar_id" FROM "app_foo_bars" WHERE "app_foo_bars"."foo_id" = 1
SELECT "app_foo_bars"."bar_id" FROM "app_foo_bars" WHERE ("app_foo_bars"."foo_id" = 1 AND "app_foo_bars"."bar_id" IN (1, 2))
INSERT INTO "app_foo_bars" ("foo_id", "bar_id") VALUES (1, 1)
INSERT INTO "app_foo_bars" ("foo_id", "bar_id") VALUES (1, 2)
And the winner is:
foo = Foo()
foo.save()
foo.bars.add(1,2)
Passing pk
s to add()
gives us a total of 4 queries:
INSERT INTO "app_foo" ("name") VALUES ()
SELECT "app_foo_bars"."bar_id" FROM "app_foo_bars" WHERE ("app_foo_bars"."foo_id" = 1 AND "app_foo_bars"."bar_id" IN (1, 2))
INSERT INTO "app_foo_bars" ("foo_id", "bar_id") VALUES (1, 1)
INSERT INTO "app_foo_bars" ("foo_id", "bar_id") VALUES (1, 2)
How to add an object to a manytomany field in django
For a ManyToManyField
, it makes not much sense to use a Select
widget [Django-doc], since that selects only a single element, a SelectMultiple
widget [Django-doc] is constructed to select mulitple objects.
You should also take a look to the HTML form whether it indeed submits values for the contact
field. You can do that by inspecting the browser data.
Nevertheless, even if you get this working, by using commit=False
, the form can not save the many-to-many field. Indeed, in order to save records in a many-to-many field, first the Group
object should be saved, since the junction table [wiki] has ForeignKey
s to the Contact
and Group
, and thus these records need to be created first. It is also better not to construct a new Form
in case the form is not valid, since then the errors will be reported when you render that form:
def create_group(request):
if request.method == 'POST':
form = CreateGroupForm(request.POST)
if form.is_valid():
form.save() # ← no commit=False
return redirect('name-of-some-view')
# do not create a new form.
else:
form = CreateGroupForm()
return render(request, "create-group.html", { 'form' : form})
Note: In case of a successful POST request, you should make a
redirect
[Django-doc]
to implement the Post/Redirect/Get pattern [wiki].
This avoids that you make the same POST request when the user refreshes the
browser.
How to add value to a many-to-many field in Django
You create a Meeting
and than populate it with Teacher
s and Student
s, so:
s1 = Student.objects.create(firstname='Foo', last_name='Bar')
s2 = Student.objects.create(firstname='Qux', last_name='Qux')
t1 = Teacher.objects.create(
firstname='Some',
last_name='One',
email='someone@something.com'
)
m = Meeting.objects.create()
m.student.add(s1, s2)
m.teacher.add(t1)
For more information, see the Many-to-many relationships section of the documentation.
Based on the exception you shared in the question, you created the Meeting
model before you made primary keys of type UUIDField
. We can fix this problem by:
- removing the
Meeting
model; - run
makemigrations
; - create a new
Meeting
model; - run
makemigrations
again; and - run
migrate
to update the database.
How do you add one object to a Django Model that has a ManyToManyField?
The *
in the arguments converts a list to individual args. For example-
lst = [1,2,3,4,5]
function(*lst)
can be just read as
function(1,2,3,4,5)
You have used follower.followers.add(*user)
. Hence, user
must be an iterable to be unpacked and passed as a list or arguments. But user
is a single User
object.
You should just use follower.followers.add(user)
in this case.
How to add id (instead of object) in ManyToManyField of Django model?
We can use method add
(Django Docs):
Adds the specified model objects to the related object set.
dept = Department.objects.create(name=name)
dept.employee.add(*[1, 2])
Or method set
(Django Docs):
Replace the set of related objects
dept.employee.set([1, 2])
Note that
add()
,create()
,remove()
,clear()
, andset()
all
apply database changes immediately for all types of related fields. In
other words, there is no need to call save() on either end of the
relationship.
Django: How to efficiently add objects to ManyToManyFields of multiple objects?
You can bulk create a record for each combination with a single query:
biology_classes = Class.objects.filter(name__contains='Biology')
linuses = Student.object.filter(first_name='Linus')
StudentClass = Student.classes.through
items = [
StudentClass(student=student, class=class)
for student in linuses
for class in biologoy_classes
]
StudentClass.objects.bulk_create(items)
This thus will make a total of three queries:
- one query to fetch the relevant
Class
es; - one query to fetch the relevant
Student
s; and - one query to create all connections between the
Class
es andStudent
s.
How to add data to a ManyToMany field model?
You have to use add()
function to add new object to ManyToManyField
. Remember also, that with filter
you get QuerySet
. To get object you should ust get
or even get_object_or_404
, but look yourself for that :)
...
tmp = Department.objects.get(title=self.superior.title)
tmp.subsidiary.add(self.superior)
...
You don't need to save it.
Django - Retrieve all manytomany field objects related to a specific model
You'll want to retrieve objects through the Category model.
You can filter on the related name on the Category model.
Try Category.objects.filter(reviews__isnull=False)
or Category.objects.filter(news__isnull=False)
A Django model that only has many to many fields?
You can not directly assign a value to a ManyToManyField
, but use the .add(…)
method [Djang-doc] as the error indicates:
from django.shortcuts import get_object_or_404
item = get_object_or_404(Listing, pk=self.kwargs['pk'])
watchlist = Watchlist.objects.create()
watchlist.user.add(request.user)
watchlist.listing.add(item)
Note: It is often better to use
get_object_or_404(…)
[Django-doc],
then to use.get(…)
[Django-doc] directly. In case the object does not exists,
for example because the user altered the URL themselves, theget_object_or_404(…)
will result in returning a HTTP 404 Not Found response, whereas using.get(…)
will result in a HTTP 500 Server Error.
Note: Since a
ManyToManyField
refers to a collection of elements,ManyToManyField
s are normally given a plural name. You thus might want
to consider renamingtouser
users
.
Related Topics
How to Create an Empty Array and Then Append to It in Numpy
Python Split a String with at Least 2 Whitespaces
Suppress Insecurerequestwarning: Unverified Https Request Is Being Made in Python2.6
Python | Accessing Dll Using Ctypes
Openpyxl 1.8.5: Reading the Result of a Formula Typed in a Cell Using Openpyxl
How to Log Server Errors on Django Sites
Pandas Selecting by Label Sometimes Return Series, Sometimes Returns Dataframe
Attributeerror: Can't Set Attribute When Connecting to SQLite Database with Flask-Sqlalchemy
Extract a String Between Double Quotes
Tab Completion in Python's Raw_Input()
How to Print a Dictionary's Key
Combining Two Series into a Dataframe in Pandas
How to Use 'Cv2.Findcontours' in Different Opencv Versions
Access Data in Package Subdirectory
Take Multiple Lists into Dataframe
MySQL "Incorrect String Value" Error When Save Unicode String in Django