【问题标题】:How to configure Django generic view for both GET and POST using model form如何使用模型表单为 GET 和 POST 配置 Django 通用视图
【发布时间】:2018-03-17 05:00:15
【问题描述】:

我想创建一个视图函数 + 模板,它显示一个简单的表单(从用户模型派生)并捕获表单提交。如何在 Django 中使用通用视图来做到这一点?

我的用户模型是:

class User(models.Model):
   email = models.EmailField(unique=True)
   name = models.CharField(max_length=100)

我只需要捕获表单中的电子邮件字段。

我认为必须有一种使用通用表单的简单方法来执行此操作,但是我不确定要使用哪一个,也不知道该怎么做。我知道的唯一其他方法是:

1) 显式创建 UserForm 和一个分离 POST 和 GET 请求的单一视图函数。例如,:

def contact(request):
   if request.method == 'GET':
       # display UserForm
        ....
   elif request.method == 'POST':
       # process form submission
        ....

2) 创建两个视图(具有单独的 URL) - 一个使用通用视图来显示表单,另一个视图用于接收表单提交,例如:

class contact(generic.DetailView):
   # display form from User model
   model = User
   ....

def submit(request):
   # process form submission
    ....

所以,我的两个问题是:

  • 仅使用通用视图可以以及应该如何实现?
  • 应该使用哪个通用视图?

【问题讨论】:

    标签: python django


    【解决方案1】:

    这也可以只使用CreateView来完成。在fields中指定email,因为您只需要表单中的电子邮件字段。您也可以在form_valid方法中处理提交的表单。

     class UserCreate(CreateView):
        model = User
        fields = ['email']
        success_url = '/your_success_url/'
    
        @transaction.atomic
        def form_valid(self, form):
           new_user = form.save(commit=False)
           # process your submitted form here.
           # eg. add any extra fields as:
           # new_user.something = something
           new_user.save()
           return super().form_valid(form)
    

    【讨论】:

      【解决方案2】:

      答案的第一部分:使用单一视图。如果您使用函数视图(这是迄今为止最简单的解决方案),规范的表单处理编辑视图如下所示:

      def myview(request, instance_id, ...):
          instance = get_object_or_404(pk=instance_id)
          if request.method == "POST":
              form = MyForm(request.POST, ..., instance=instance)
              if form.is_valid():
                  # assuming a ModelForm 
                  form.save()
                  return redirect(somewhere)
              # invalid forms will be re-rendered with the error messages
          else:
              form = MyForm(instance=instance)
          return render(request, "myapp/mytemplate.html", {"form": form})
      

      对于创建视图,您只需删除所有 instance_xxx 部分。或者,您可以使用相同的视图来创建和更新,使 instance_id 成为可选:

      def myview(request, instance_id=None, ...):
          if instance_id is not None:
              instance = get_object_or_404(pk=instance_id)
          else:
              instance = None
      
          if request.method == "POST":
              form = MyForm(request.POST, ..., instance=instance)
              if form.is_valid():
                  # assuming a ModelForm 
                  form.save()
                  return redirect(somewhere)
              # invalid forms will be re-rendered with the error messages
          else:
              form = MyForm(instance=instance)
          return render(request, "myapp/mytemplate.html", {"form": form})
      

      如果你想要一个基于类的通用视图they are documented here。我个人认为基于类的通用视图并没有什么好处(除了当你试图掌握分散在六个基类和 mixin 中的执行流程时最终会让人头疼),而是 YMMV。

      更新

      如果我想在将实例保存到数据库之前对数据进行一些处理(包括添加额外的字段),我应该在哪里进行?

      最好在表单本身中,除非您需要一些您不想传递给表单的其他数据。对于所有表格,您都可以在the validation stage 处理数据。使用 ModelForm,您还可以覆盖 save() 方法本身:

      class MyModelForm(forms.ModelForm):
      
          class Meta:
              model = MyModel
              fields = ('whatever', 'something')
      
          def save(self, commit=True):
              """ Save user and create a pro account """
              instance = super(MyModelForm, self).save(commit=False)
              instance.something_else = 42 
              if commit:
                  instance.save()
              return instance
      

      【讨论】:

      • 好吧,是的,考虑到所有其他内置的东西,我开始认为通用视图会更令人头疼而不是有用......使用你的方法 - 如果我想做在将实例保存到数据库之前对数据进行一些处理(包括添加额外的字段),我将在哪里执行此操作?
      • 好的,明白了。您将在什么时候开始将该处理放入模型本身(或其他地方)?我的“验证”的一部分是多次拒绝来自同一 IP 的表单提交,但我想知道这是要放置在模型中的任务还是在表单本身经过验证后的某种后处理......
      • (我要做的另一个处理是检查用户是否已经存在,如果是这种情况,则将它们转发到不同的 URL...显然必须在保存表单之前完成,所以不确定我应该在哪里构建该逻辑)
      • > "你什么时候开始将处理放入模型本身":这里没有一刀切的答案,这取决于所涉及的“处理”,这说明了哪些信息处理需要,你需要在哪里调用它等等。就我而言,我倾向于支持“智能”模型,但这并不意味着一切都应该成为模型上的方法。恐怕我能在这里提出的唯一建议是“用你的判断力”。
      • > "检查用户是否已经存在,如果是这种情况,则将其转发到不同的 URL":这部分显然需要在视图级别本身解决(因为您想返回 @987654328 @。假设您正在使用表单来验证电子邮件,然后使用此电子邮件来确定用户是否已经存在,这可能会在保存表单之前进入 if form.is_valid(): 分支。但您还想确保您对email 表单有一个唯一性约束,以防止通过代码的另一部分创建重复的电子邮件。
      【解决方案3】:

      CreateView 可以根据您的要求完美工作,您只需要创建一个联系人模型和success_url 表单提交后用户将重定向的表单。它将自动将用户数据保存到模型中

      class ContactView(generic.CreateView):
          form_class = ContactForm
          template_name = 'contact/index.html'
          success_url = '/homepage/' . #Mention URL here
      

      【讨论】:

      • 如果这样做,表单提交后会发生什么?(我需要知道,以便在保存到数据库之前对提交的数据进行一些操作)
      • 当用户提交一次表单时,它会自动验证表单数据并将用户数据保存在模型中,并将重定向到success_url使用,如果用户数据无效则返回与输入数据的用户相同的页面。 CreateView 的流程ccbv.co.uk/projects/Django/1.11/django.views.generic.edit/…
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-02-12
      • 2015-10-13
      • 2013-05-25
      • 2013-02-27
      • 1970-01-01
      • 2017-10-25
      • 2016-11-02
      相关资源
      最近更新 更多