'Django - How to populate manytomany field in forms by previously selected options by users
How can I populate manytomany form field with previous user selected subs.
In this code forms render choices with empty checkboxes. I want checkboxes to show which subscriptions user subscribed to.
models.py
class Subscription(models.Model):
SUBSCRIPTION_TYPES = (
('SUB1', _('sub 1')),
('SUB2', _('sub 2')),
)
subscription_type = models.CharField(choices=SUBSCRIPTION_TYPES, max_length=30, unique=True)
description = models.CharField(max_length=255, blank=True)
class UserSubscription(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
subscriptions = models.ManyToManyField(Subscription, related_name='subscriptions',
related_query_name='subscriptions')
forms.py
class SubscriptionForm(forms.ModelForm):
class Meta:
model = UserSubscription
fields = ('subscriptions',)
widgets = {
'subscriptions': forms.CheckboxSelectMultiple(),
}
views.py
class SubscriptionFormView(FormView):
template_name = 'profile/subscription.html'
form_class = SubscriptionForm
Solution 1:[1]
Please do not create a UserSubscription, now you defined two junction tables. This will result in duplicate data, and will make queries less efficient, and more error-prone logic.
What you need is a ManyToManyField from the Subscription to the User, so:
class Subscription(models.Model):
# …
subscribers = models.ManyToManyField(
settings.AUTH_USER_MODEL,
related_name='subscriptions'
)
Then we can define a form to select the Subscriptions:
from django import forms
class SubscribingForm(forms.Form):
subscriptions = forms.ModelMultipleChoiceField(
queryset=Subscription.objects.all(),
widget=forms.CheckboxSelectMultiple()
)
Then in the view we can handle the form and subscribe the logged in user to all the subscriptions that have been selected:
from django.contrib.auth.mixins import LoginRequiredMixin
from django.shortcuts import redirect
class SubscriptionFormView(LoginRequiredMixin, FormView):
template_name = 'profile/subscription.html'
form_class = SubscribingForm
def get_initial(self):
initial = super().get_initial()
initial['subscriptions'] = self.request.user.subscriptions.all()
return initial
def form_valid(self, form):
subs = form.cleaned_data['subscriptions']
self.request.user.subscriptions.add(*subs)
return redirect('name-of-some-view')
Note: You can limit views to a class-based view to authenticated users with the
LoginRequiredMixinmixin [Django-doc].
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.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
