【问题标题】:Create an object and his many to many relationships with extrafields in one form以一种形式创建一个对象及其与外场的多对多关系
【发布时间】:2020-09-28 17:18:42
【问题描述】:

我使用的是 Django 2.2,这是我的简化模型:

class Course(CustomModelClass):
    name = models.CharField(max_length=200, null=False, unique=True)
    components = models.ManyToManyField('Component', through='CourseComponent')

class Component(CustomModelClass):
    name = models.CharField(max_length=200, null=False, unique=True)

class CourseComponent(CustomModelClass):
    course = models.ForeignKey(Course, on_delete=models.CASCADE)
    component = models.ForeignKey(Component, on_delete=models.CASCADE)
    quantity = models.IntegerField(default=0, null=False)

我的人际关系很好,这没有问题。现在到了我做一个 ModelForm 来管理它的那一刻。

这是我现在的表格:

class CourseForm(ModelForm):
    class Meta:
        fields = ['name', 'group', 'components']
        model = Course

同样,如果我的数量有一个 null=True 参数,它工作得很好,但当然当我把它设置为 False 时,它​​显然不再工作了。

我想做的是在我的表单中提供一种选择组件并为每个组件设置数量的方法。我真的不在乎它看起来像一个带有组件名称和数字字段的复选框,或者是用于选择组件和数字字段的许多选择列表,这不是重要的部分。

更清楚地说,我想创建一个对象及其与额外字段的多对多关系以相同的形式。

我现在的问题是我当然无法访问表格中的数量。

有什么想法吗?

【问题讨论】:

  • 我根据对您的问题的理解发布了回复。如果这不是您想要的,请尝试多解释一下您的阻塞点
  • @Houda 感谢您的回答,但我的问题不在这里。我尝试以相同的形式创建一个对象及其所有多对多关系及其数量

标签: django django-models django-forms django-orm


【解决方案1】:

我希望你觉得这个提议很有趣:

Views.py:

def view1(request):
    CourseComponentFormSet = formset_factory(CourseComponentForm, extra=Component.objects.count())
    content = {'form': CourseComponentFormSet}
    return render(request, 'stack/edit.html', content)


def view2(request, mycourse):
    if request.method == 'POST':
        data = {}
        for p in request.POST:
            if p.startswith('form'):
                data[p] = request.POST[p]
        j = 0
        while j < int(data['form-MAX_NUM_FORMS']):
            if data['form-' + str(j) + '-quantity'] == '':
                data['form-' + str(j) + '-quantity'] = 0
                data['form-' + str(j) + '-course'] = mycourse
            else:
                data['form-' + str(j) + '-course'] = mycourse
            j += 1
        CourseComponentFormSet = formset_factory(CourseComponentForm)
        formset = CourseComponentFormSet(data)
        if formset.is_valid():
            j = 0
            mylist = []
            while j < int(data['form-MAX_NUM_FORMS']):
                if data['form-' + str(j) + '-quantity'] == 0:
                    pass
                else:
                    Courses = get_object_or_404(Course, name=mycourse)
                    Components = get_object_or_404(Component, id=int(data['form-' + str(j) + '-component']))
                    Courses.components.add(Components,
                                           through_defaults={'quantity': data['form-' + str(j) + '-quantity']})
                j += 1

            return HttpResponseRedirect(reverse('stack:view1'))
        else:
            errors = formset.errors
            ini = []
            i = 0
            nb = Component.objects.count()
            while i < nb:
                ini.append({'course': mycourse})
                i += 1
            CourseComponentFormSet = formset_factory(CourseComponentForm, max_num=nb)
            formset = CourseComponentFormSet(initial=ini)
            content = {'form': formset, 'course': mycourse, 'errors': errors}
            return render(request, 'stack/edit.html', content)
    else:
        if Course.objects.filter(name__exact=mycourse):
            pass
        else:
            Course.objects.create(**{'name': mycourse})
        ini = []
        i = 0
        nb = Component.objects.count()
        while i < nb:
            ini.append({'course': mycourse})
            i += 1
        CourseComponentFormSet = formset_factory(CourseComponentForm, max_num=nb)
        formset = CourseComponentFormSet(initial=ini)
        content = {'form': formset, 'course': mycourse}
        return render(request, 'stack/edit.html', content)

模型.py

class Component(models.Model):
    name = models.CharField(max_length=200, null=False, unique=True)

    def __str__(self):
        return self.name


class Course(models.Model):
    name = models.CharField(max_length=200, null=False, unique=True)
    components = models.ManyToManyField('Component', through='CourseComponent')

    def __str__(self):
        return self.name


class CourseComponent(models.Model):
    component = models.ForeignKey(Component, on_delete=models.CASCADE)
    course = models.ForeignKey(Course, on_delete=models.CASCADE)
    quantity = models.IntegerField(default=0, null=False)

    def __init__(self, *args, **kwargs):
        super(CourseComponent, self).__init__(*args, **kwargs)

forms.py

class CourseComponentForm(Form):

    course = CharField(label='Course')
    component = ChoiceField(label='Component')
    quantity = IntegerField(label='Quantity')

    def __init__(self, *args, **kwargs, ):
        super(CourseComponentForm, self).__init__(*args, **kwargs)
        self.fields['component'].choices = tuple(Component.objects.all().values_list(flat=False))
        self.fields['quantity'].widget.attrs['style'] = "margin:15px 56% 15px 0%;"
        self.fields['course'].widget.attrs['readonly'] = "True"
        self.fields['course'].widget.attrs['disabled'] = "disabled"

edit.html

<body>
<label>Course:</label><input id="myinput" type="text"><button onclick="myfunction()">send</button><br>'
    <form action='' id='myform' method="POST">
    {% csrf_token %}
    {{ form }}
        <button class="btn btn-primary" name="submit" onclick="submit()">submit</button>
     </form>
{{errors}}
</body>

<script>

{% if mycourse %}
{% endif %}

function submit() {
document.getElementById('myform').action="/stack/view2/"+mycourse;
document.getElementById("myform").submit();
}


function myfunction() {
    var course = document.getElementById("myinput").value;
    chemin ="\/stack\/view2\/"+course;
     window.location.replace(chemin);
}
</script>
</html>

【讨论】:

  • 感谢您的回答。但是迁移不是问题。问题是我想以一种形式创建一个对象及其与额外字段的多对多关系。你提供的modelForm不能给我我想要的。它将创建一个包含课程列表的选择。但我想创建一个:)
  • 您想要一个表格用于三个模型,就这样?
  • 每门课程有一个数量或每个课程组件有一个数量
  • 通常只有 2 个模型会更新课程和课程组件。第三个(组件)已填充,但需要填充 CourseComponents
  • 感谢您的努力。但是我必须为在同一页面中包含 30 个表单的设置页面执行此操作,所以我必须让管理变得容易,不管表单。我会继续上一个答案。但是非常感谢您的帮助
【解决方案2】:

直接在modelform中添加额外的字段:

from django import forms
from .models import Course, Component
class CourseForm(ModelForm):
    class Meta:
        fields = ['name']
        model = Course

class ComponentForm(forms.Form):
    component = forms.ModelChoiceField(queryset=Component.objects.all())
    quantity = forms.IntegerField(initial=0, required=False, min_value=0)

ComponentFormSet = forms.formset_factory(ComponentForm, extra=3)

views.py 相关

def handler(request):
    if request.method == "POST":
        form = CourseForm(request.POST)
        formset = ComponentFormSet(request.POST)
        if form.is_valid() and formset.is_valid():
            # do your business
    form = CourseForm()  #it could set initial data here for form,etc
    formset = ComponentFormSet()
    return render(request, 'your_template.html', {'form':form, 'formset':formset})

有关you_template.html

{% extends 'admin/base_site.html'%}
{% load i18n %}
{% block content%}
<div class="col-md-10">
    <form action={% url "course" %} method='post' role='form' class="form-inline">
        {% csrf_token %}
        {{ form }}<br>
        {{ formset.management_form}}
        {% for fm in formset %}
        {{ fm }}<br>
        {% endfor%}
        <input type='submit' class='btn btn-primary' value="submit"/>
    </form>
</div>
{% endblock%}

【讨论】:

  • 您好,感谢您的回答。我试过了,但在这种情况下,我只能选择一个带有数量的组件,在我的情况下,我必须创建一个包含多个组件的课程,并且每个组件在关系中都有一个数量
  • 利用表单集
  • 是的,这正是我的问题:How to do a formset multi models.
  • 我已经为你修好了。
  • 所以我知道不可能以一种统一的形式做到这一点
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-08
  • 2012-01-07
  • 1970-01-01
  • 2022-11-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多