![e8d5b613062f2dbb0b255a419bd96ee2.png](https://i-blog.csdnimg.cn/blog_migrate/a27663e63bb170500cc5f99d9fd46141.jpeg)
假如我们有文章Article和类别Category两个模型,其中类别和文章是一对多的关系。我们希望某个用户在使用表单创建或编辑某篇新文章时,表单上类别对应的下拉菜单选项不显示所有类别,而只显示用户自己创建的类别,我们该如何实现?小编我今天就提供两种经典方法供参考。
如果不出意外,Django模型models.py应该是如下所示:
from django.db import models
from django.contrib.auth.models import User
class 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.title
class 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 forms
from .models import Article, Category
class 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.user
def form_valid(self, form):
form.instance.author = self.request.user
return 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'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['form'].fields['category'].queryset = Category.objects.filter(author=self.request.user)
return context
def form_valid(self, form):
form.instance.author = self.request.user
return super().form_valid(form)
传统函数视图(Functional Based Views)
如果你喜欢传统的函数视图,你会从下面的代码中获取启发。其中最重要的一行代码莫过于
form.fields['category'].queryset = Category.objects.filter(author=request.user).
@login_required
def 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
![ee6412897a3179a60f5fb0ad4b34e3be.png](https://i-blog.csdnimg.cn/blog_migrate/db17f957be55cf9d1748c7d3ae8fcae2.jpeg)