Django - 如何通过用户先前选择的选项填充表单中的 manytomany 字段
Django - How to populate manytomany field in forms by previously selected options by users
如何使用以前用户选择的子项填充 manytomany 表单字段。
在此代码中,表单呈现带有空复选框的选项。
我希望复选框显示用户订阅了哪些订阅。
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
请不要创建UserSubscription
,现在您定义了两个联结表。这将导致重复数据,并使查询效率降低,逻辑更容易出错。
你需要的是从Subscription
到User
的ManyToManyField
,所以:
class Subscription(models.Model):
# …
subscribers = models.ManyToManyField(
settings.AUTH_USER_MODEL,
related_name='subscriptions'
)
然后我们可以定义一个表单到select的Subscription
s:
from django import forms
class SubscribingForm(forms.Form):
subscriptions = forms.<strong>ModelMultipleChoiceField(</strong>
queryset=Subscription.objects.all(),
widget=forms.CheckboxSelectMultiple()
<strong>)</strong>
然后在视图中我们可以处理表单并为登录用户订阅所有已 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()
<b>initial['subscriptions'] = self.request.user.subscriptions.all()</b>
return initial
def form_valid(self, form):
subs = form.cleaned_data['subscriptions']
self.request.user.subscriptions.add(*subs)
return redirect(<em>'name-of-some-view'</em>)
Note: You can limit views to a class-based view to authenticated users with the
LoginRequiredMixin
mixin [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.
如何使用以前用户选择的子项填充 manytomany 表单字段。
在此代码中,表单呈现带有空复选框的选项。 我希望复选框显示用户订阅了哪些订阅。
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
请不要创建UserSubscription
,现在您定义了两个联结表。这将导致重复数据,并使查询效率降低,逻辑更容易出错。
你需要的是从Subscription
到User
的ManyToManyField
,所以:
class Subscription(models.Model):
# …
subscribers = models.ManyToManyField(
settings.AUTH_USER_MODEL,
related_name='subscriptions'
)
然后我们可以定义一个表单到select的Subscription
s:
from django import forms
class SubscribingForm(forms.Form):
subscriptions = forms.<strong>ModelMultipleChoiceField(</strong>
queryset=Subscription.objects.all(),
widget=forms.CheckboxSelectMultiple()
<strong>)</strong>
然后在视图中我们可以处理表单并为登录用户订阅所有已 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()
<b>initial['subscriptions'] = self.request.user.subscriptions.all()</b>
return initial
def form_valid(self, form):
subs = form.cleaned_data['subscriptions']
self.request.user.subscriptions.add(*subs)
return redirect(<em>'name-of-some-view'</em>)
Note: You can limit views to a class-based view to authenticated users with the
LoginRequiredMixin
mixin [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.