用一种形式创建一个对象和他的许多到许多关系与外字段。

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

我用的是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时,它显然就不能工作了。

我想做的是在我的表单中选择组件并为每个组件设置一个数量。我并不关心它看起来如何,它可以是一个复选框,上面有组件的名称和一个数字字段,或者是许多选择列表来选择组件和一个数字字段,这不是重要的部分。

更明确的是,我想在同一个表单中创建一个对象和他的许多关系,并带有额外的字段。

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

有什么办法吗?

django django-models django-forms django-orm
1个回答
0
投票

在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%}

0
投票

希望你觉得这个命题有趣。

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)

model.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)

表单.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>
© www.soinside.com 2019 - 2024. All rights reserved.