在通用CRUD视图中排除字段

1 投票
1 回答
1169 浏览
提问于 2025-04-16 21:43

我有一个叫做 Domain 的模型,它的结构是这样的:

class Domain(models.Model):
    """
    Model for storing the company domains
    """
    user = models.ForeignKey(
        User
    )
    host = models.CharField(
        null=False, verbose_name="Host", max_length=128, unique=True
    )

我想用Django的通用视图来进行CRUD操作(即创建、读取、更新和删除)。这个模型里有一个字段需要用户输入,但有一个外键字段不需要用户输入。我该怎么做才能让通用视图生成的表单里不包含那个外键字段,同时把它的值设置为当前登录的用户呢?

谢谢。

1 个回答

2

看看Russel在本周早些时候在django-users小组上对类似问题的回答。

引用他的回答*:

表单和视图解决的是不同的问题。

视图解决的是“我该如何处理这个请求并把它转化为响应?”这个问题。表单解决的是“我该如何把这个请求中的POST数据转化为一个模型对象(或者对模型对象的更改)?”这个问题。

简单来说,视图的工作流程大致是这样的:

  1. 视图接收到一个请求
  2. 视图判断这是一个GET请求还是POST请求
  3. 如果是POST请求,视图会请求表单把POST数据转化为模型的更改
  4. 表单返回成功或失败的结果
  5. 视图根据表单的成功或失败做出响应。
  6. 视图返回一个响应。

表单的功能是视图功能的一个完整子集,因此它是一个完全可以互换的内部组件。

在简单的情况下,视图可以猜测表单的所有默认设置——它只需要知道你在处理一个Foo模型,就可以构建一个默认的Foo ModelForm。但是,如果你有更复杂的表单需求,就需要一个定制的表单了。

我们本可以通过在视图类中暴露ModelForm的所有选项来实现这一点;但为了保持代码的整洁,我们将ModelForm隔离开来,并提供了一种方式让视图指定它将使用哪个表单类。

所以,为了满足你排除字段的需求,你需要定义一个排除字段的ModelForm,然后让CreateView知道你想使用哪个表单:

class CampaignForm(forms.ModelForm):


    class Meta:
        model = Campaign
        exclude = ('user', 'name', 'content_inlined')

class CreateCampaignView(CreateView):
    form_class = CampaignForm
    template_name = "forms/create.html"

我猜当你说“为字段固定值”时,你是指在保存新的Campaign实例之前,设置用户、名称和内容的值;为此,你需要在表单处理逻辑中注入一些额外的代码:

class CreateCampaignView(CreateView):
    form_class = CampaignForm
    template_name = "forms/create.html"

    def form_valid(self, form):
        form.instance.user = ... (something meaningful.. e.g., self.request.user)
        return super(CreateCampaignView, self).form_valid(form)

这会覆盖表单有效时的默认行为,并设置额外的值。然后,super()实现的form_valid()会保存这个实例。

顺便说一下,这也可以通过重写ModelForm的save()方法来完成——但是,如果你这么做,你就会失去请求对象,而这个对象在你试图将实例值设置为与请求相关的内容时是需要的。

*原始回答中使用了self.object.user而不是form.instance.user。这样会导致AttributeError,所以我在上面做了修改。

撰写回答