【问题标题】:Restrict form field in CreateView to not show current-user as a choice in template限制 CreateView 中的表单字段不将当前用户显示为模板中的选项
【发布时间】:2016-06-02 14:11:14
【问题描述】:

我正在使用简单的表格和通用的 CBV UpdateView 向所有用户使用“令牌”来给予其他用户额外的信用。用户不应该被允许给自己额外的信用,所以他们不应该出现在选择字段中作为选择。我在这里没有使用模型表单,并且想知道如何在不这样做的情况下执行此操作。到目前为止,这是我的代码:

models.py

class ExtraCredit(models.Model):
    recipient = models.ForeignKey(Developer, related_name='extracredit_recipient')
    sender = models.ForeignKey(Developer, related_name='extracredit_sender')
    skill = models.ForeignKey(Skill, related_name='extracredit_skill')
    description = models.TextField(blank=True, null=True)
    date_credited = models.DateField(auto_now_add=True)

    def __str__(self):
        return '%s %s -> %s %s - %s' % (self.sender.user.first_name, self.recipient.user.last_name, self.recipient.user.first_name, self.recipient.user.last_name, self.skill.name)

views.py

class ExtraCreditCreateView(CreateView):
    model = ExtraCredit
    template_name = 'extracredit_create.html'

    def __init__(self, *args, **kwargs):
        user = kwargs.pop('user', None)
        super(ExtraCreditCreateView, self).__init__(*args, **kwargs)

        self.fields['recipient'].queryset = ExtraCredit.objects.exclude(recipient=user)
        self.fields['description'].help_text = "Why does this user deserve extra credit?"

    def get_form_kwargs(self):
        kwargs = super(ExtraCreditCreateView, self).get_form_kwargs()
        kwargs.update({'user': self.request.user})
        return kwargs

    def get_success_url(self):
        return reverse('my_developer_details')

    def form_invalid(self, form):
        return self.render_to_response(self.get_context_data(form=form))

    def form_valid(self, form):
        form.save(commit=False)
        sender = get_object_or_404(Developer, user_id=self.request.user.id)
        extra_credit_tokens = Developer.objects.get(user_id=sender.user_id).extra_credit_tokens

        if extra_credit_tokens:
            Developer.objects.filter(user_id=sender.user_id).update(extra_credit_tokens=extra_credit_tokens-1)

            form.instance.sender = sender
            form.save()

            return super(ExtraCreditCreateView, self).form_valid(form)
        else:
            raise forms.ValidationError("The user does not have enough tokens")

    fields = ['recipient', 'skill', 'description']

我拥有get_form_kwargs(self) 函数的唯一原因是尝试在def __init__ 函数中使用self.request.user。如果我在 __init__ 函数中使用 self.request.user,我会收到一个错误,即请求不是 ExtraCreditCreateView 的属性。如果我确实向选项添加了请求,例如__init__(self, request, *args, **kwargs):,那么我会收到一个关于需要两个参数并且只提供一个参数的错误。现在设置的方式,我得到一个 TypeError:list indices must be integers, not str

当在模板中创建表单时,确保当前登录用户不在“收件人”字段中的正确方法是什么?

更新的解决方案(基于@Alasdair 的回答):

class ExtraCreditForm(forms.ModelForm):
    class Meta:
        model = ExtraCredit
        exclude = ['id', 'sender', 'date_credited']

    def __init__(self, *args, **kwargs):
        user = kwargs.pop('user', None)
        super(ExtraCreditForm, self).__init__(*args, **kwargs)

        self.fields['recipient'].queryset = self.fields['recipient'].queryset.exclude(user_id=user.id)
        self.fields['description'].help_text = "Why does this user deserve extra credit?"

class ExtraCreditCreateView(CreateView):
    template_name = 'extracredit_create.html'
    form_class = ExtraCreditForm

    def get_form_kwargs(self):
        kwargs = super(ExtraCreditCreateView, self).get_form_kwargs()
        kwargs.update({'user': self.request.user})
        return kwargs

    def get_success_url(self):
        return reverse('my_developer_details')

    def form_valid(self, form):
        form.save(commit=False)
        sender = get_object_or_404(Developer, user_id=self.request.user.id)
        extra_credit_tokens = Developer.objects.get(user_id=sender.user_id).extra_credit_tokens

        if extra_credit_tokens:
            Developer.objects.filter(user_id=sender.user_id).update(extra_credit_tokens=extra_credit_tokens-1)

            form.instance.sender = sender
            form.save()

            return super(ExtraCreditCreateView, self).form_valid(form)
        else:
            raise forms.ValidationError("The user does not have enough tokens")

【问题讨论】:

  • 如果不定义 ModelForm,您将无法执行此操作。您的视图不是表单,没有必要覆盖其 init 方法或尝试访问 self.fields

标签: python django dictionary django-views django-class-based-views


【解决方案1】:

您说您想避免定义模型表单,但这是最好的方法。 可能可以在get_form 方法中破解表单的字段,但您不应该这样做。

设置接收者的queryset属于表单,而不是视图的__init__方法。

class ExtraCreditForm(forms.ModelForm):

    def __init__(self, *args, **kwargs):
        user = kwargs.pop('user', None)
        super(ExtraCreditForm, self).__init__(*args, **kwargs)

        self.fields['recipient'].queryset = ExtraCredit.objects.exclude(recipient=user)
        self.fields['description'].help_text = "Why does this user deserve extra credit?"

然后从您的视图中删除__init__ 方法,并设置form_class 以便它使用您的模型表单。您已经更新了 get_form_kwargs 以将用户传递给表单的 __init__ 方法,因此您不必进行任何其他更改。您的 form_invalid 方法没有做任何特别的事情,因此您可以将其删除。

class ExtraCreditCreateView(CreateView):
    form_class = ExtraCreditForm
    ...

【讨论】:

  • 谢谢!你带领我走向正确的方向。我将我的最终解决方案作为上面的更新发布,但主要变化是:self.fields['recipient'].queryset = self.fields['recipient'].queryset.exclude(user_id=user.id) 排除当前用户。
猜你喜欢
  • 1970-01-01
  • 2013-08-20
  • 2022-01-15
  • 1970-01-01
  • 2018-04-21
  • 2018-02-14
  • 2017-11-11
  • 2021-12-28
  • 2017-09-23
相关资源
最近更新 更多