【问题标题】:Django CreateView: How to perform action upon saveDjango CreateView:如何在保存时执行操作
【发布时间】:2016-01-05 01:02:18
【问题描述】:

我正在使用自定义 CreateView (CourseCreate) 和 UpdateView (CourseUpdate) 来保存和更新课程。我想在保存课程时采取行动。我将在新课程的讲师和用户之间创建一个新的多对多关系(如果它不存在的话)。

所以,我想将 Course 保存为 course,然后使用 course.faculty 创建新的关系。实现这一目标的最佳地点在哪里?

我试图在视图中的 form_valid 中执行此操作,但在尝试访问 form.instance.faculty 时出现错误,因为课程尚未创建(在 CourseCreate 中)。错误信息是这样的:

“Course: ...”需要为字段“course”设置一个值,然后才能使用这种多对多关系。

它在 CourseUpdate 中也不起作用。未创建 Assists 关系。我应该在表格中尝试这个吗?但我不确定如何将用户信息获取到表单。 谢谢。

models.py

class Faculty(models.Model):
    last_name = models.CharField(max_length=20)

class Course(models.Model):
    class_title = models.CharField(max_length=120)
    faculty = models.ManyToManyField(Faculty)

class UserProfile(models.Model):
    user = models.OneToOneField(User)
    faculty = models.ManyToManyField(Faculty, through='Assists')

class Assists(models.Model):
    user = models.ForeignKey(UserProfile)
    faculty = models.ForeignKey(Faculty)

views.py

class CourseCreate(CreateView):
    model = Course
    template_name = 'mcadb/course_form.html'
    form_class = CourseForm
    def form_valid(self, form):
        my_course = form.instance
        for f in my_course.faculty.all():
            a, created = Assists.objects.get_or_create(user=self.request.user.userprofile, faculty=f)
        return super(CourseCreate, self).form_valid(form)

class CourseUpdate(UpdateView):
    model = Course
    form_class = CourseForm
    def form_valid(self, form):
        my_course = form.instance
        for f in my_course.faculty.all():
            a, created = Assists.objects.get_or_create(user=self.request.user.userprofile, faculty=f)
        return super(CourseUpdate, self).form_valid(form)

【问题讨论】:

  • 尝试用my_course = form.save(commit=False)替换my_course = form.instance
  • @Vingtoft,谢谢。当我尝试这样做时,在创建新课程时单击 Save btn 时,我仍然看到相同的错误:“在使用这种多对多关系之前,Course 对象需要具有字段‘course’的值。”我不太明白“课程”提及的来源......我确实有一个名为“课程”的课程,但它没有一个名为“课程”的字段,而且我的观点没有提及“课程”。

标签: django


【解决方案1】:

CreateViewUpdateViewform_valid() 方法保存表单,然后重定向到成功 url。不可能做到return super(),因为你想在保存的对象和重定向之间做一些事情。

第一个选项是不调用super(),并在您的视图中复制这两行。这样做的好处是非常清楚发生了什么。

def form_valid(self, form):
    self.object = form.save()
    # do something with self.object
    # remember the import: from django.http import HttpResponseRedirect
    return HttpResponseRedirect(self.get_success_url())

第二种选择是继续调用super(),但在您更新关系之前不要返回响应。这样做的好处是您不会复制 super() 中的代码,但缺点是不清楚发生了什么,除非您熟悉 super() 所做的事情。

def form_valid(self, form):
    response = super(CourseCreate, self).form_valid(form)
    # do something with self.object
    return response

【讨论】:

  • 哇,谢谢,这行得通(我选择了第一个选项以提高透明度)。我确实花了很多时间查看文档,但仍然发现自己很难解决此类问题。非常感谢@Alasdair!
  • 我个人也更喜欢第一个选项。很高兴它有帮助:-)
  • @Alasdair:如何覆盖form_valid() 并更新其中的form.instance,这是使用POST 数据生成的,因为form.is_validform_valid() 之前调用。这个instance 稍后用于在form_valid 中调用form.save() 时设置object
  • @batMan 如果我没记错的话,form.instanceNone 对应于 CreateView。您可以在get_form_kwargs 中将instance 设置为Course(),但这对这个特定问题没有多大帮助,因为必须先保存实例,然后才能设置多对多字段的值。
【解决方案2】:

我建议使用 Django 的 Signal。这是当模型发生某些事情时触发的操作,例如 saveupdate。这样您的代码就会保持干净(表单处理中没有业务逻辑),并且您确定它只会在 save 后触发。

#views.py
from django.dispatch import receiver
...

@receiver(post_save, sender=Course)
def post_save_course_dosomething(sender,instance, **kwargs):
    the_faculty = instance.faculty
    #...etc  

【讨论】:

【解决方案3】:

可以像在 django 文档中一样返回 super()https://docs.djangoproject.com/en/4.0/topics/class-based-views/generic-editing/

def form_valid(self, form):
    # This method is called when valid form data has been POSTed.
    # It should return an HttpResponse.
    form.send_email()
    return super().form_valid(form)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-08-08
    • 2021-12-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-22
    • 2021-06-14
    相关资源
    最近更新 更多