windows form 下拉选项_Django限制表单中ForeignKey对应下拉菜单选项数量的两种经典方法...

有朋友问: 假如我们有文章Article和类别Category两个模型,其中类别和文章是一对多的关系。我们希望某个用户在使用表单创建或编辑某篇新文章时,表单上类别对应的下拉菜单选项不显示所有类别,而只显示用户自己创建的类别,我们该如何实现?小编我今天就提供两种经典方法供参考。

如果不出意外,Django模型models.py应该是如下所示:

from django.db import modelsfrom django.contrib.auth.models import Userclass Article(models.Model):"""文章模型"""title = models.CharField('标题', max_length=200, db_index=True)    author = models.ForeignKey(User, verbose_name='作者', on_delete=models.CASCADE, related_name='articles')    category = models.ForeignKey('Category', verbose_name='分类', on_delete=models.CASCADE, blank=False, null=False)def __str__(self):return self.titleclass Category(models.Model):"""类别模型"""        name = models.CharField('name', max_length=30, unique=True)    author = models.ForeignKey(User, verbose_name='作者', on_delete=models.CASCADE, blank=True, null=True,)def __str__(self):return self.name

表单文件forms.py应该如下所示。从ArticleForm定义我们可得知,ArticleForm类没有指定显示何种类别,所以默认将显示所有类别。或许你想尝试修改ArticleForm的定义来将类别选项限定于作者自己创建的类别,但却找不到真正的突破口。

from django import formsfrom .models import Article, Categoryclass ArticleForm(forms.ModelForm):class Meta:        model = Article        exclude = ['author',]

那么答案在哪里?答案在视图里。我们可以在视图里对表单ForeignKey对应下拉菜单选项的内容和数量做出限制。接下来我们将分别介绍如何在基于类的视图和传统函数视图里实现。

基于类的视图(Class-based Views)

原先的视图views.py可能如下所示。 你直接使用ArticleForm,没有对form的各个字段做出任何修改或调整。

@method_decorator(login_required, name='dispatch')class ArticleCreateView(CreateView):    model = Article    form_class = ArticleForm    template_name = 'blog/article_form.html'# Associate form.instance.user with self.request.userdef form_valid(self, form):        form.instance.author = self.request.userreturn super().form_valid(form)

现在我们就要来见证下奇迹的时刻了。通过重写基于类的视图自带的get_context_data方法,你可以对form的任何字段做出修改和限制。比如本例中限定了category对应的queryset仅限于用户自己创建的类别。models.py, forms.py和模板文件什么都不需要修改。

@method_decorator(login_required, name='dispatch')class ArticleCreateView(CreateView):    model = Article    form_class = ArticleForm    template_name = 'blog/article_form.html'# Associate form.instance.user with self.request.userdef get_context_data(self, **kwargs):        context = super().get_context_data(**kwargs)        context['form'].fields['category'].queryset = Category.objects.filter(author=self.request.user)return contextdef form_valid(self, form):        form.instance.author = self.request.userreturn super().form_valid(form)

传统函数视图(Functional Based Views)

如果你喜欢传统的函数视图,你会从下面的代码中获取启发。其中最重要的一行代码莫过于 

form.fields['category'].queryset = Category.objects.filter(author=request.user).
@login_requireddef article_create(request):if request.method == 'POST':        form = ArticleForm(request.POST)if form.is_valid():

article = form.save(commit=False)

article.author = request.user # Set the user object here article.save() # Now you can send it to DB

return HttpResponseRedirect("/blog/")else: form = ArticleForm() form.fields['category'].queryset = Category.objects.filter(author=request.user)return render(request, 'blog/article_create_form.html', {'form': form, })

注意:

本例ArticleForm使用的是ModelForm,由模型创建,所以使用form.fields['category']获取category字段。如果你是自定义的普通form,应使用form.category获取category字段。

小结

如果你想对表单里显示的各个字段的内容或数量做出限制,你应该在视图里操作,而不是表单里操作。记住了吗?

大江狗

2019.12

6b5e76aea9f7de555fe01b8e82eba456.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值