невозможно сохранить данные с помощью django форм - PullRequest
0 голосов
/ 03 марта 2020

Данные, введенные в форму, не сохраняются в базе данных и не показывают ошибок. Я пытаюсь создать экзамен по крайней мере с одним вопросом, используя ExamModelForm и QuestionFormset. После ввода сведений об экзамене и вопросов в create_exam_with_questions. html кнопка создания не сохраняет данные в базу данных

views.py

from django.shortcuts import render
from django.shortcuts import redirect
from django.http import HttpResponseRedirect, HttpResponse

from .forms import ExamModelForm, ExamFormset, QuestionFormset
from .models import Question

def create_exam_with_questions(request):
    template_name = 'school/create_exam_with_questions.html'
    if request.method == 'GET':
        examform = ExamModelForm(request.GET or None)
        formset = QuestionFormset(queryset=Question.objects.none())
    elif request.method == 'POST':
        examform = ExamModelForm(request.POST)
        formset = QuestionFormset(request.POST)
        if examform.is_valid() and formset.is_valid():
            # first save this exam, as its reference will be used in `Question`
            exam = examform.save()
            for form in formset:
                # so that `question` instance can be attached.
                question = form.save(commit=False)
                question.exam = exam 
                question.save()
            return redirect("map:map-home")
    return render(request, template_name, {
        'examform': examform,
        'formset': formset,
    })


forms.py

from django import forms
from django.forms import (formset_factory, modelformset_factory)
from .models import Exam, Question

class ExamModelForm(forms.ModelForm):
    class Meta:
        model = Exam
        fields = ['name', 'section', 'duration', 'subject', 'start', 'teacher']

QuestionFormset = modelformset_factory(
    Question,
    fields=('question', 'ans', 'op2', 'op3', 'op4', ),
    extra=1,
    widgets={'question': forms.TextInput(attrs={
            'class': 'form-control',
            'placeholder': 'Enter Question here'
        }),
    'ans': forms.TextInput(attrs={
        'class': 'form-control',
        'placeholder': 'Enter answer here'
        }),
    'op2': forms.TextInput(attrs={
        'class': 'form-control',
        'placeholder': 'Enter option2 here'
        }),
    'op3': forms.TextInput(attrs={
        'class': 'form-control',
        'placeholder': 'Enter option3 here'
        }),
    'op4': forms.TextInput(attrs={
        'class': 'form-control',
        'placeholder': 'Enter option4 here'
        }),
    }
)


models.py

class Section(models.Model):
    name = models.CharField(max_length = 20)
    school = models.ForeignKey(School, on_delete = models.CASCADE)

    def __str__(self):
        return self.name

class Subject(models.Model):
    name = models.CharField(max_length = 20)
    section = models.ForeignKey(Section, on_delete = models.CASCADE)

    def __str__(self):
        return self.name


class Exam(models.Model):
    name = models.CharField(max_length = 20)
    section = models.ForeignKey(Section, on_delete = models.CASCADE)
    subject = models.ForeignKey(Subject, on_delete = models.CASCADE)
    duration = models.TimeField()
    start = models.DateTimeField()
    teacher = models.CharField(max_length = 20)

    def __str__(self):
        return self.name


class Question(models.Model):
    question = models.TextField(max_length = 20)
    ans = models.CharField(max_length = 20)
    op2 = models.CharField(max_length = 20)
    op3 = models.CharField(max_length = 20)
    op4 = models.CharField(max_length = 20)
    exam = models.ForeignKey(Exam, on_delete = models.CASCADE)

    def __str__(self):
        return self.question


create_exam_with_questions. html

{% extends "school/base.html" %}

{% block container %}
{% if heading %}
<h3>{{heading}}</h3>
{% endif %}
<form class="form-horizontal" method="POST" action="">
    {% csrf_token %}
<div class="row spacer">
<div class="col-2">
    <label>{{examform.name.label}}</label>
</div>
<div class="col-4">
    <div class="input-group">
        {{examform.name}}
    </div>
</div>
</div>
<div class="row spacer">
<div class="col-2">
    <label>{{examform.subject.label}}</label>
</div>
<div class="col-4">
    <div class="input-group">
        {{examform.subject}}
    </div>
</div>
</div>
<div class="row spacer">
<div class="col-2">
    <label>{{examform.duration.label}}</label>
</div>
<div class="col-4">
    <div class="input-group">
        {{examform.duration}}
    </div>
</div>
</div>
<div class="row spacer">
<div class="col-2">
    <label>{{examform.teacher.label}}</label>
</div>
<div class="col-4">
    <div class="input-group">
        {{examform.teacher}}
    </div>
</div>
</div>
<div class="row spacer">
<div class="col-2">
    <label>{{examform.start.label}}</label>
</div>
<div class="col-4">
    <div class="input-group">
        {{examform.start}}
    </div>
</div>
</div>
<div class="row spacer">
<div class="col-2">
    <label>{{examform.section.label}}</label>
</div>
<div class="col-4">
    <div class="input-group">
        {{examform.section}}
    </div>
</div>
</div>
{{ formset.management_form }}
{% for form in formset %}
<div class="row form-row spacer">
    <div class="col-2">
        <label>{{form.question.label}}</label>
    </div>
    <div class="col-4">
        <div class="input-group">
            {{form.question}}
        </div>
        <div class="input-group">
            {{form.ans}}
        </div>
        <div class="input-group">
            {{form.op2}}
        </div>
        <div class="input-group">
            {{form.op3}}
        </div>
        <div class="input-group">
            {{form.op4}}
        </div>
    </div>
    <div class="input-group-append">
                <button class="btn btn-success add-form-row">+</button>
    </div>
</div>
{% endfor %}
<div class="row spacer">
    <div class="col-4 offset-2">
        <button type="submit" class="btn btn-block btn-primary">Create</button>
    </div>
</div>
</form>
{% endblock %}

{% block custom_js %}
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
<script type="text/javascript">
function updateElementIndex(el, prefix, ndx) {
    var id_regex = new RegExp('(' + prefix + '-\\d+)');
    var replacement = prefix + '-' + ndx;
    if ($(el).attr("for")) $(el).attr("for", $(el).attr("for").replace(id_regex, replacement));
    if (el.id) el.id = el.id.replace(id_regex, replacement);
    if (el.name) el.name = el.name.replace(id_regex, replacement);
}
function cloneMore(selector, prefix) {
    var newElement = $(selector).clone(true);
    var total = $('#id_' + prefix + '-TOTAL_FORMS').val();
    newElement.find(':input:not([type=button]):not([type=submit]):not([type=reset])').each(function() {
        var name = $(this).attr('name')
        if(name) {
            name = name.replace('-' + (total-1) + '-', '-' + total + '-');
            var id = 'id_' + name;
            $(this).attr({'name': name, 'id': id}).val('').removeAttr('checked');
        }
    });
    newElement.find('label').each(function() {
        var forValue = $(this).attr('for');
        if (forValue) {
          forValue = forValue.replace('-' + (total-1) + '-', '-' + total + '-');
          $(this).attr({'for': forValue});
        }
    });
    total++;
    $('#id_' + prefix + '-TOTAL_FORMS').val(total);
    $(selector).after(newElement);
    var conditionRow = $('.form-row:not(:last)');
    conditionRow.find('.btn.add-form-row')
    .removeClass('btn-success').addClass('btn-danger')
    .removeClass('add-form-row').addClass('remove-form-row')
    .html('-');
    return false;
}
function deleteForm(prefix, btn) {
    var total = parseInt($('#id_' + prefix + '-TOTAL_FORMS').val());
    if (total > 1){
        btn.closest('.form-row').remove();
        var forms = $('.form-row');
        $('#id_' + prefix + '-TOTAL_FORMS').val(forms.length);
        for (var i=0, formCount=forms.length; i<formCount; i++) {
            $(forms.get(i)).find(':input').each(function() {
                updateElementIndex(this, prefix, i);
            });
        }
    }
    return false;
}
$(document).on('click', '.add-form-row', function(e){
    e.preventDefault();
    cloneMore('.form-row:last', 'form');
    return false;
});
$(document).on('click', '.remove-form-row', function(e){
    e.preventDefault();
    deleteForm('form', $(this));
    return false;
});

</script>
{% endblock %}

1 Ответ

0 голосов
/ 03 марта 2020

Вам нужно заменить строку

exam = examform.save()

на

examform.save()

и при сохранении вопроса напишите

for form in formset:
    # so that `question` instance can be attached.
    question = form.save(commit=False)
    question.exam = examform
    question.save()
...