[M2M字段小部件,以内联表单集的形式添加或更新数据

问题描述 投票:0回答:1

我花了很多时间寻找我认为应该是Django中非常基本的功能的功能。但是我只是无法正常工作,

我找不到与django的m2m小部件功能相同的小部件,但是如果不存在,还将创建新的模型实例。

[注意:这里的模型实例已经存在,意味着在嵌入式窗口小部件中输入的数据已经存在于数据库中。

例如如果我有以下模型:

class Outcome(models.Model):
    outcome = models.CharField(max_length=255)
    outcome_short_name = models.CharField(max_length=10, blank=True, null=True)


class Course(models.Model):
    course_title = models.CharField(
        verbose_name=COURSE_SINGULAR + " title", max_length=200, unique=True
    )

    course_outcome = models.ManyToManyField(
        Outcome, verbose_name=COURSE_SINGULAR + " outcome", blank=True
    )

然后我希望在创建课程时将“结果”显示为该图像:Image of adding new course with inline outcomes

现在,如果用户添加的结果数据已经存在,则应仅将它们映射到课程。否则,它应该首先将结果存储到数据库中,然后将其映射到课程中。

任何正确方向的指导都将受到高度赞赏。

谢谢,

编辑:正如@dirkgroten建议使用modelformset一样,我将FormView更改为:

class CourseFormView(FormView):
    template_name = "course/course_form.html"
    form_class = CourseForm
    success_url = "/admin/"

    def get_context_data(self, **kwargs):
        context = super(CourseFormView, self).get_context_data(**kwargs)
        if self.request.POST:
            context["outcomes"] = OutcomeFormSet(self.request.POST)
        else:
            context["outcomes"] = OutcomeFormSet(queryset=Outcome.objects.none())
        return context

    def form_valid(self, form, **kwargs):
        super(CourseFormView, self).get_context_data(**kwargs)
        context = self.get_context_data()
        outcomes_formset = context["outcomes"]
        if not outcomes_formset.is_valid():
            return super().form_invalid(form)

        cleaned_data = form.cleaned_data
        cleaned_data.pop("course_outcome")
        course = Course.objects.create(**cleaned_data)
        course.save()

        outcomes_formset.instance = course
        outcomes_formset.save()


course.course_outcome.set(Outcome.objects.filter(course_outcome=course))
    return super().form_valid(form)

一切看起来都很好,但是如果数据库中已经存在formset中的表单数据,那么我的model_formset不会经过验证。例如。如果我在表单集中输入(outcome =“ test_outcome”,result_short_name =“ test_short”)并且结果表中已经存在相同的数据,那么我的表单集会给出错误:具有该结果和结果简称的结果已经存在。

有什么办法可以解决这种情况,或者我做错了什么?

您可以在以下位置进行测试:http://code.gdy.club:8001/course/add/results_list:http://code.gdy.club:8001/outcome/

谢谢,

-苏拉杰https://hacksj4u.wordpress.comhttps://github.com/SurajDadral

python django m2m
1个回答
0
投票

您需要处理自己已经存在Outcome的情况。验证表单时的默认设置是假定将创建一个新对象,因此,如果您将字段设置为unique_together,则单个表单将不进行验证。

您可以像这样在OutcomeFormsetclean()方法上进行操作:

from django.core.exceptions import NON_FIELD_ERRORS

def clean(self):
    cleaned_data = super().clean()
    for i in range(0, self.total_form_count()):
        form = self.forms[i]
        if form.non_field_errors() and len(form.errors) == 1:
            # the only error is probably due to unique_together constraint
            try:
                form.instance = Outcome.objects.get(outcome=form.data.get('outcome'), outcome_short_name=form.data.get('outcome_short_name'))
            except Outcome.DoesNotExist:
                pass  # some other error
            else:
                del form._errors[NON_FIELD_ERRORS]
    return cleaned_data

然后在您的视图中,保存表单集时,应遍历所有表单,而不是保存实例具有pk的表单:

for form in outcomes_formset:
    outcome = form.instance    
    if not outcome.pk:
        outcome = form.save()
    course.course_outcome.add(outcome)
热门问题
推荐问题
最新问题