【问题标题】:Django - How to populate manytomany field in forms by previously selected options by usersDjango - 如何通过用户先前选择的选项填充表单中的多字段
【发布时间】:2021-07-30 14:44:28
【问题描述】:

如何使用以前用户选择的子项填充多页表单字段。

在此代码中,表单呈现带有空复选框的选项。 我希望复选框显示用户订阅了哪些订阅。

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

【问题讨论】:

    标签: python django forms orm


    【解决方案1】:

    不要创建UserSubscription,现在您定义了两个联结表。这将导致重复数据,并使查询效率降低,逻辑更容易出错。

    您需要的是从SubscriptionUserManyToManyField,所以:

    class Subscription(models.Model):
        # …
        subscribers = models.ManyToManyField(
            settings.AUTH_USER_MODEL,
            related_name='subscriptions'
        )

    然后我们可以定义一个表单来选择Subscriptions:

    from django import forms
    
    class SubscribingForm(forms.Form):
        subscriptions = forms.ModelMultipleChoiceField(
            queryset=Subscription.objects.all(),
            widget=forms.CheckboxSelectMultiple()
        )

    然后在视图中我们可以处理表单并将登录用户订阅到所有已选择的订阅:

    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')

    注意:您可以将视图限制为基于类的视图,以便通过身份验证的用户使用 LoginRequiredMixin mixin [Django-doc].


    注意:如果 POST 请求成功,请发送redirect [Django-doc] 实施Post/Redirect/Get pattern [wiki]。 这样可以避免在用户刷新时发出相同的 POST 请求 浏览器。

    【讨论】:

    • 感谢您的回答。这很棒,但并没有解决我的问题。我希望复选框在用户已经订阅某些内容时显示为选中状态。
    • @Allehparast:您可以覆盖 get_initial 以选择人们已经订阅的内容,请参阅编辑。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-17
    • 2018-09-26
    • 1970-01-01
    • 2011-06-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多