I have a form which I am posting to my model, saved in a postgreSQL database. All of the fields are saving except for a ManyToMany field I have as part of my model for "opening_days". On the front end this form field is a ModelMultipleChoiceField, with CheckboxSelectMultiple. Within my view, I have verified that the checkbox selections are being picked up with a print statement, however, I cannot get them to save to my database. I would expect it to save as a list of strings, with each item being a day of the week. Days of the week are defined in their own model, and used in the model I am trying to save to via ManyToMany field. I cannot work out how to fix it and have been stuck for days. Further details with code snippets can be found here: https://stackoverflow.com/questions/75932404/checkboxselectmultiple-values-not-saving-to-django-database
#ManyToManyField won't save to database.
48 messages · Page 1 of 1 (latest)
booking_management.opening_days.set(form.cleaned_data['opening_days'])
...
form.save_m2m()
Aren't those two lines doing the same thing?
form.instance.user = self.request.user
form.instance.listing = get_object_or_404(Listing, slug=self.kwargs['slug'])
booking_management = form.save()
return redirect(self.get_next_url())
Could you use that instead of commit=False and save_m2m?
Hi @gloomy copper , thanks for getting back to me. I've commented out the save_m2m, however I dont think this was the problem. I've tried so many different approaches to try and get it to save a value to the opening_days field and nothing seems to work. I've tried loooping through the data from the form and using .add() for each value too but this still doesn't save anything in the field for the model instance:
def post(self, request, *args, **kwargs):
form = self.form_class(request.POST)
if form.is_valid():
form.instance.user = self.request.user
booking_management = form.save(commit=False)
listing = get_object_or_404(Listing, slug=self.kwargs['slug'])
booking_management.listing = listing
booking_management.save()
instance = get_object_or_404(BookingManagement, id=booking_management.id)
print(instance.opening_days)
day_list = request.POST.getlist('opening_days')
print(day_list)
for day in day_list:
instance.opening_days.add(day)
instance.save()
next_path = self.get_next_url()
return redirect(next_path)
Feel like I am slowly losing hope and really can't work out the issue here
Did you try what I suggested?
@gloomy copper do you mean like this:
def post(self, request, *args, **kwargs):
form = self.form_class(request.POST)
if form.is_valid():
form.instance.user = self.request.user
form.instance.listing = get_object_or_404(Listing, slug=self.kwargs['slug'])
booking_management = form.save()
booking_management.opening_days.set(form.cleaned_data['opening_days'])
next_path = self.get_next_url()
return redirect(next_path)
?
In which case, the 'opening_days' field for that instance is still null
upon creation of a new instance
No, I meant ```python
def post(self, request, *args, **kwargs):
form = self.form_class(request.POST)
if form.is_valid():
form.instance.user = self.request.user
form.instance.listing = get_object_or_404(Listing, slug=self.kwargs['slug'])
booking_management = form.save()
return redirect(self.get_next_url())
If that doesn't work, then you need to confirm that opening_days is being specified properly and Django is converting that to the correct instances.
Use print statements or a debugger to confirm what the server is receiving. And use the browser's developer tools' network panel to confirm that the browser is sending.
Yeah I tried that initially and have just tried that again 😦 still no luck
Have been using print statements, and they are printing the expected ouputs when getting the data from the 'opening_days' form field. It is literally just when it comes to saving it to the database for that model instance that it's not working.
(Thanks so much for your help btw!)
That's why I am so confused, it's sending the data and I can see that when using print statements, but it just wont write to the database and I've tried so many different methods to do so and none of them have worked.
Is anything else manipulating the database? Have you confirmed that after you save it, that the field is updated? Have you confirmed that the inserts are actually occurring (you can use connection.queries)? https://docs.djangoproject.com/en/4.1/faq/models/#how-can-i-see-the-raw-sql-queries-django-is-running
Okay thanks, I've printed that as I've added a new instance to my database, and this was the result:
[{'sql': 'SELECT "listings_daysofweek"."id", "listings_daysofweek"."day" FROM "listings_daysofweek" WHERE "listings_daysofweek"."id" IN (1, 2)', 'time': '0.001'}, {'sql': 'SELECT "listings_listing"."id", "listings_listing"."business_id", "listings_listing"."title", "listings_listing"."slug", "listings_listing"."activity_id", "listings_listing"."listing_image", "listings_listing"."price", "listings_listing"."accessible", "listings_listing"."description", "listings_listing"."date_added", "listings_listing"."active", "listings_listing"."address", "listings_listing"."town", "listings_listing"."county", "listings_listing"."post_code", "listings_listing"."country", "listings_listing"."longitude", "listings_listing"."latitude" FROM "listings_listing" WHERE "listings_listing"."slug" = \'gsretbstrebtr-4z7jlf\' LIMIT 21', 'time': '0.002'}, {'sql': 'INSERT INTO "listings_bookingmanagement" ("listing_id", "opening_time", "closing_time", "booking_slots_per_day", "max_bookings_per_time_slot", "standard_booking_duration", "min_booking_duration", "max_booking_duration", "booking_duration_increment", "min_people_per_booking", "max_people_per_booking", "turnaround_time", "time_slot_frequency", "max_people_per_time_slot", "max_people_per_day", "min_adults_per_booking", "max_children_per_adult", "min_age", "max_age", "child_max_age") VALUES (167, \'09:00:00\'::time, \'17:00:00\'::time, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) RETURNING "listings_bookingmanagement"."id"', 'time': '0.007'},
{'sql': 'SELECT "listings_daysofweek"."id" FROM "listings_daysofweek" INNER JOIN "listings_bookingmanagement_opening_days" ON ("listings_daysofweek"."id" = "listings_bookingmanagement_opening_days"."daysofweek_id") WHERE "listings_bookingmanagement_opening_days"."bookingmanagement_id" = 108', 'time': '0.001'}, {'sql': 'INSERT INTO "listings_bookingmanagement_opening_days" ("bookingmanagement_id", "daysofweek_id") VALUES (108, 1), (108, 2) ON CONFLICT DO NOTHING', 'time': '0.001'}]
Would I be right and thinking the issue could be here:
ON CONFLICT DO NOTHING', 'time': '0.001'}] ? But the problem is, I'm not sure what the conflict is and how to resolve this?
I wonder if it's something to do with the fact that I am trying to add multiple items to one instance, i.e. openings days could be Monday and Tuesday (as I selected in the above instance) which tries to write 1 & 2 (the pk values within my DaysOfWeek model for Monday and Tuesday) both to the opening_days field of this instance
But ultimately, that's what I need it to do as it should be possible to be open every day of the week if applicable
There's no insert into the many2many's through table...
What was day_list = request.POST.getlist('opening_days') print(day_list) printing exactly?
For the above instance, that would print:
['1', '2']
However, if I were to print:
print(form.cleaned_data['opening_days'])
I would get:
<QuerySet [<DaysOfWeek: Monday>, <DaysOfWeek: Tuesday>]>
Okay, good. That's right.
Ah, never mind. I see the insert into the intermediate table now.
That's the INNER JOIN right?
No, this ```
{'sql': 'INSERT INTO "listings_bookingmanagement_opening_days" ("bookingmanagement_id", "daysofweek_id") VALUES (108, 1), (108, 2) ON CONFLICT DO NOTHING', 'time': '0.001'}
Did you check the database for a row matching those values?
Yeah so I have a row with the 108 id value, but the opening_days field on that row is null
Show me the query and result exactly as it is. opening_days shouldn't be a column.
Just been looking at the entire table in pg_admin; with SELECT * FROM listings_bookingmanagement
That's not the right table though.
listings_bookingmanagement_opening_days is the table you need to check. It's the intermediate / through relationship between the other two objects.
oh my
I am so stupid
I've been checking the wrong table all this time
So sorry for wasting your time; is there anything I can do to show my appreciation
Just for my understanding then, the opening_days field will always be null because the opening_days are stored in a seperate table which acts as an intermediary between the two models
What do you mean by "opening_days field"? Are you talking about the ORM, the column on a table, a form field?
So as in within my BookingManagement model I have: opening_days = models.ManyToManyField(DaysOfWeek, verbose_name="Opening Days")
And that field is appearing in my database as null under my BookingManagement model
If you're seeing a column opening_days on the table for BookingManagement, your database is out of sync with your models. That column should not exist from the models that you've shared with me.
models.ManyToManyField() does not create any columns on the table. It creates an intermediate/through table that allows you to map the two models together.
Ahhh I see, that's a reminent from an older migration where I tried something different. That makes sense so I just need to remove that now
Thank you so much honestly I've been pulling my hair out over that
Do you have an account on buymeacoffee.com or anything?
Nope, I do this because I enjoy our community and want to help folks level up. If you insist on compensating me, you'll need to pay it forward to someone else you can help out.
That's amazing to hear, I'll make sure I do! Thanks so much once again and hope you had a great Easter weekend!