简体   繁体   中英

How can I use django forms to assign values to multiple different objects

I am new to django. I am making a teacher utility website that will help keep track of student's grades for different classes and assignments. Currently I have made a page for one class and I am displaying the information in a table, where students are the rows and each assignment is the column.

I would like to make an 'edit' page where I can modify the student's grades for each assignment in the same format as the main class page. So that instead of the grades in each 'cell' of the table there will be an input field with a save button at the bottom of the page. And I'm not sure how to accomplish that. How can I make a form assign a value to a specific student/assignment pair? And how can I have multiple of those forms for each student/assignment pair? I tried using (unsuccessfully) using formsets but I wasn't able to make much progress with that.

Here are my models

class Student(models.Model):
    name = models.CharField(max_length=40)
    section = models.ForeignKey(Section, blank=False, on_delete=models.PROTECT)
    subjects = models.ManyToManyField(Subject)

    def __str__(self):
        return self.name

class Assignment(models.Model):

    section = models.ForeignKey(Section, blank=False, on_delete=models.PROTECT)
    subject = models.ForeignKey(Subject, blank=False, on_delete=models.PROTECT)
    assign_date = models.DateField('date assigned', primary_key=True)
    def __str__(self):
        return self.assign_date.strftime('%d/%m/%y')
    class Meta:
        unique_together = ('section', 'assign_date')

class AssignmentScore(models.Model):
    student = models.ForeignKey(Student, blank=False, on_delete=models.PROTECT)
    assignment = models.ForeignKey(Assignment, blank=False, on_delete=models.PROTECT)
    assignment_score = models.PositiveIntegerField(validators=[MaxValueValidator(5)], blank=False)
    class_assignment_score = models.PositiveIntegerField(validators=[MaxValueValidator(5)], blank=False)
    def __str__(self):
        return str(self.assignment_score)
    class Meta:
        unique_together = ('student', 'assignment')

Here is my attempt at a form

class GradeForm(forms.ModelForm):
    # def __init__(self, *args, **kwargs):
    #     super(GradeForm, self).__init__(*args, **kwargs)
    #     self.fields['assignment_score'].widget.attrs['style'] = "width:50px"
    class Meta:
        model = AssignmentScore
        fields = ('assignment_score', 'class_assignment_score')
        widgets = {
            'assignment_score': forms.TextInput(attrs={'size':1}),
            'class_assignment_score': forms.TextInput(attrs={'size':1})
        }
        labels = {
            'assignment_score': '',
            'class_assignment_score': '',
        }

and here is the html Im using to generate the class page

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
     <html xmlns="http://www.w3.org/1999/xhtml">
     <head>
     <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
     <title>Untitled Document</title>
     {% load static %}
     <link rel="stylesheet" type="text/css" href="{% static 'gradebook/style.css' %}" />
     </head>

<body>
    <form action='.' method='POST'>
        {% csrf_token %}
        {{ form }}
    </form>
<table cellpadding="0" cellspacing="0">
    <tr>
        <td>
        {% if assignments %}
            {% for assignment in assignments %}
                <td colspan="2">{{assignment}}</td>
            {% endfor %}
        {% endif %}
        </td>
    </tr>
    <tr>
        <td>&nbsp;</td>
        {% if assignments %}
            {% for assignment in assignments %}
                <td>д.р.</td>
                <td>к.р.</td>
            {% endfor %}
        {% endif %}

    </tr>
    {% if students %}
    <form actions='.' method='POST'>
        {% csrf_token %}
        {% for student in students %}
            <tr>
                <td>{{student.name}}</td>

                {% for s in assignment_scores %}
                    {% if s.student.name == student.name %}
                        <td> {{ s.assignment_score }} </td>
                        <td> {{ s.class_assignment_score }} </td>
                    {%endif%}
                {% endfor %}
            </tr>
        {% endfor %}
        <button type="submit" class="save btn btn-default">Save</button>

    </form>

    {% else %}
        <p> No students </p>
    {% endif %}
</table>
</body>
</html>

Thanks for the help

It's certainly possible. But you would have to do it manually in the forms clean method. See: https://docs.djangoproject.com/en/1.10/ref/forms/validation/#validating-fields-with-clean .

POST data for a particular value can be a list of values. So if you had the frontend POST a list of lists [[<student_id>, <assignment_id>, <assignment_score>, <class_assignment_score>] ... ] then in your clean method you could convert these values back into the actual AssignmentScore models.

Whether this is the best way to do this? It's not supported directly by Django Forms. But I've certainly done something similar in the past.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM