问题
The data entered in the form is not saving in the database and it is not showing any errors. Iam trying to create an exam with atleast one question, using ExamModelForm and QuestionFormset. After entering exam details and questions in create_exam_with_questions.html, the create button is not saving the data into the database
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:
You need to replace line
exam = examform.save()
with
examform.save()
and when saving the question, write
for form in formset:
# so that `question` instance can be attached.
question = form.save(commit=False)
question.exam = examform
question.save()
来源:https://stackoverflow.com/questions/60505144/unable-to-save-data-using-django-formsets