如何将django forms.py select items转换为html中的列表



我有一个表格,我打算用它来获取学生分数。我有一个问题,我不知道最好的表达方式,所以我有学生名称和旁边的标记字段,供所有学生使用。调用{{ form }}会带来带有选择下拉项的表单(不是我想要的(。指定表单字段不会填充任何内容。例如

{% for field in form %}
{{ field.student }}
{{ field.marks }}
{% endfor %}

这是表格

class AddMarksForm(forms.ModelForm):
def __init__(self, school,klass,term,stream,year, *args, **kwargs):
super(AddMarksForm, self).__init__(*args, **kwargs)
self.fields['student'] = forms.ModelChoiceField(
queryset=Students.objects.filter(school=school,klass__name__in=klass,stream__name=stream[0]))
class Meta:
model = Marks
fields = ('student','marks')

这就是我如何尝试html呈现

<form method="post" enctype="multipart/form-data" action="{% url 'add_marks' %}">
{% csrf_token %}
{% if form %}
<table>
<tr>
<td>Student</td>
<td>Marks</td>
</tr>
{% for field in form %}
<tr>
<td>{{ field.student }}</td>
<td>{{ field.marks }}</td>
</tr>
</table>
{% endfor %}
<button class="btn btn-outline-primary">Save</button>
</form>

我的模特。

class Year(models.Model):
year = models.IntegerField(validators=[MinValueValidator(2018), MaxValueValidator(4000),])
year_term = models.ForeignKey('exams.Term',on_delete=models.SET_NULL,related_name='year_term', null=True,blank=True)
class Subject(models.Model):
name = models.CharField(max_length=50)
teacher = models.ForeignKey(TeacherData,on_delete=models.CASCADE)
students = models.ManyToManyField(Students)

class Term(models.Model):
year = models.ForeignKey(Year,on_delete=models.CASCADE)
name = models.CharField(max_length=30)
exam_term = models.ForeignKey('exams.Exam',on_delete=models.SET_NULL,null=True,blank=True,related_name='exam_term')

class Exam(models.Model):
school = models.ForeignKey(School,on_delete=models.CASCADE)
year = models.ForeignKey(Year,on_delete=models.SET_NULL, null=True)
term = models.ForeignKey(Term,on_delete=models.SET_NULL, null=True)
name = models.CharField(max_length=20)
klass = models.ManyToManyField("students.Klass", related_name='klass',null=True,blank=True)

class Marks(models.Model):
exam = models.ForeignKey(Exam,on_delete=models.SET_NULL,null=True,blank=True)
subject = models.ForeignKey(Subject,on_delete=models.SET_NULL,null=True,blank=True)
student = models.ForeignKey(Students,on_delete=models.SET_NULL,null=True,blank=True)
marks = models.IntegerField(validators=[MinValueValidator(0), MaxValueValidator(100),] ,null=True,blank=True)

更多型号

class Klass(models.Model):
name = models.IntegerField(validators=[MinValueValidator(1), MaxValueValidator(4),], help_text='E.g 1,2,3, 4')
school = models.ForeignKey(School,on_delete=models.CASCADE)
exam = models.ForeignKey("exams.Exam",on_delete=models.CASCADE, related_name='exam',null=True,blank=True)
class Stream(models.Model):
name = models.CharField(max_length=50,help_text='Name of the stream')
klass = models.ForeignKey(Klass,on_delete=models.CASCADE,help_text='Choose a class the stream belongs to')
class Students(models.Model):
id = models.AutoField(primary_key=True)
#student_user = models.OneToOneField(User, on_delete=models.CASCADE,null=True,blank=True)
school = models.ForeignKey(School,on_delete=models.CASCADE,help_text='A school must have a name')
adm = models.IntegerField(unique=True,validators=[MinValueValidator(1), MaxValueValidator(1000000),],help_text="Student's admission number" )
name = models.CharField(max_length=200,help_text="Student's name")
kcpe = models.IntegerField(validators=[MinValueValidator(100), MaxValueValidator(500),], help_text='What the student scored in primary')
klass = models.ForeignKey(Klass, on_delete=models.CASCADE,null=True,help_text="Student's Class/Form")
stream = models.ForeignKey(Stream,on_delete=models.CASCADE,blank=True,null=True,help_text="Student's Stream")
gender = models.ForeignKey(Gender,on_delete=models.CASCADE,null=True,help_text="Student's Gender")
notes = models.TextField(blank=True,null=True,help_text='Anything to say about the student. Can always be edited later')

这是我根据问题评论中的讨论提出的建议。

# models.py
class User(models.Model):
is_teacher = models.BoolField(default=False)
is_student = models.BoolField(default=False)

class Subject(models.Model):
taught_by = models.ForeignKey(User, on_delete=models.PROTECT, limit_choices_to={"is_teacher": True})
students = models.ManyToManyField(User, limit_choices_to={"is_student": True})

class Exam(models.Model):
subject = models.ForeignKey(Subject, on_delete=models.CASCADE)

class Marks(models.Model):
exam = models.ForeignKey(Exam, on_delete=models.CASCADE)
student = models.ForeignKey(User, on_delete=models.CASCADE, limit_choices_to={"is_student": True})
marks = models.IntegerField(validators=[MinValueValidator(0), MaxValueValidator(100),], null=True, blank=True)
# no need for a subject field here, that is linked through the Exam object
class Meta:
unique_togetger = [('exam', 'student'),]

我只写了重要的字段,你可以添加更多你需要的字段。

# views.py
class AddMarks(views.View):
def get(self, request, exam_id):
try:
exam = Exam.objects.get(id=exam_id)
except Exam.DoesNotExist:
# some kind of handler that returns (important!)
context = {
"students": exam.subject.students.all()
"current_marks": Marks.objects.filter(exam=exam)
}
return render("add_marks.html", context=context)
def post(self, request, exam_id):
try:
exam = Exam.objects.get(id=exam_id)
except Exam.DoesNotExist:
# some kind of handler that returns (important!)
for student in exam.subject.students.all():
marks = int(request.POST.get(f"marks_{student.username}", None))
if marks:
# if that particular marks field exists in POST and is filled, let's update (if it exists) or create a new marks object
marks_object = Marks.objects.filter(exam=exam, student=student).first() or Marks(exam=exam, student=student)
marks_object.marks = marks
marks_object.save()
return self.get(request, exam_id)
<!--add_marks.html-->
<form method="POST">
<table>
{% for student in students %}
<tr>
<td>{{ student.get_full_name }}</td>
<td><input type="number" name="marks_{{ student.username }}" /></td>
</tr>
{% endfor %}
{% if students %}
<tr><td colspan="2"><input type="submit" value="Save marks" /></td></tr>
{% else %}
<tr><td colspan="2">No student is taking this class</td></tr>
{% endif %}
</table>
</form>
{% if current_marks %}
<h3>Currently saved marks</h3>
<table>
{% for marks in current_marks %}
<tr>
              <td>{{ marks.student.get_full_name }}</td>
<td>{{ marks.marks }}</td>
</tr>
{% endfor %}
</table>
{% endfor %}

我确实做了一些改变。最引人注目的是Student模型,或者更确切地说,它的缺乏。我已经将User标记为学生或教师,允许您的学生登录并查看他们的成绩,或者注册上课。

其次,如代码中所述,Marks模型中不需要subject字段,因为数据可以从Exam本身提取。

最后是关于它的作用。它将创建一个包含表的表单,其中每一行都将包含一个名为marks_<username>的字段。然后可以在post方法处理程序中检索该字段。如果该字段存在并且具有值,则视图将更新现有模型或创建新的Marks模型。如果已经保存了任何标记,它们将在下面的单独表格中显示。

我已经完全删除了表格,因为在这种情况下这是多余的。如果你真的想,也许在其他地方,可以通过使用Django的FormSet API来实现这种多表单一页的功能。关于这一点的文档是[此处][1]。这允许您一个接一个地堆叠许多相同类型的表单,以便一次编辑多行。但由于我们实际上只有一个领域,我发现自己处理这个领域更容易。

最后一件事,我没有写任何错误检查和处理。我会留给你的。可能需要处理的地方是除了块之外的两个,它们需要从方法返回,这样就不会执行下面的代码。一些漂亮的404页就足够了。另一个地方是关于获取POST内容的int()调用。如果发送了非整数的东西,这可能会引发异常。您应该能够用一个简单的try-except块来处理它。

最新更新