Add most of the original functionality back

This commit is contained in:
Nathan Chapman 2022-07-27 15:45:11 -06:00
parent 4c477ac16c
commit 16ddd81a63
39 changed files with 1172 additions and 121 deletions

View File

@ -4,7 +4,7 @@
<article class="panel"> <article class="panel">
<div class="generic__header"> <div class="generic__header">
<h1>Update Entry</h1> <h1>Update Entry</h1>
<a class="action-button action-delete" href="{% url 'entry-delete' entry.pk %}">Delete {{entry}}</a> <a class="action-button action-delete" href="{% url 'entry-delete' entry.pk %}">Delete</a>
</div> </div>
<p>For <strong>{{student}}</strong></p> <p>For <strong>{{student}}</strong></p>
<section> <section>
@ -17,4 +17,4 @@
</form> </form>
</section> </section>
</article> </article>
{% endblock %} {% endblock %}

View File

@ -16,36 +16,55 @@ from .models import (
class SchoolYearCreateForm(forms.ModelForm): class SchoolYearCreateForm(forms.ModelForm):
class Meta: class Meta:
model = SchoolYear model = SchoolYear
fields = [ fields = ['year']
'year'
]
class StudentForm(forms.ModelForm): class StudentForm(forms.ModelForm):
class Meta: class Meta:
model = Student model = Student
fields = ( fields = [
'student_id', 'student_id',
'first_name', 'first_name',
'last_name', 'last_name',
'address', 'address',
'dob', 'dob',
) 'tags'
]
labels = { labels = {
'student_id': 'Student ID', 'student_id': 'Student ID',
'dob': 'DOB', 'dob': 'DOB'
} }
class ComponentCreateForm(forms.ModelForm): class ComponentCreateForm(forms.ModelForm):
class Meta: class Meta:
model = Component model = Component
fields = ( fields = [
'name', 'name',
'category', 'category',
'due_date', 'due_date',
'grade_total', 'grade_total'
) ]
widgets = { widgets = {
'due_date': forms.DateInput(attrs={'type': 'date'}), 'due_date': forms.DateInput(attrs={'type': 'date'})
}
class SchoolDayForm(forms.ModelForm):
class Meta:
model = SchoolDay
fields = ['date']
widgets = {
'date': forms.DateInput(attrs={
'type': 'date',
})
}
class AttendanceEntryForm(forms.ModelForm):
class Meta:
model = AttendanceEntry
fields = ['status']
widgets = {
'status': forms.RadioSelect()
} }

View File

@ -0,0 +1,30 @@
# Generated by Django 4.0.5 on 2022-07-27 19:55
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('core', '0006_score'),
]
operations = [
migrations.RemoveIndex(
model_name='studenttag',
name='core_studen_content_a7305d_idx',
),
migrations.RemoveField(
model_name='studenttag',
name='content_type',
),
migrations.RemoveField(
model_name='studenttag',
name='object_id',
),
migrations.AddField(
model_name='student',
name='tags',
field=models.ManyToManyField(blank=True, to='core.studenttag'),
),
]

View File

@ -0,0 +1,23 @@
# Generated by Django 4.0.5 on 2022-07-27 19:57
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('core', '0007_remove_studenttag_core_studen_content_a7305d_idx_and_more'),
]
operations = [
migrations.RemoveField(
model_name='studenttag',
name='tag',
),
migrations.AddField(
model_name='studenttag',
name='name',
field=models.CharField(default='Allergy: Seasonal/Hay', max_length=255),
preserve_default=False,
),
]

View File

@ -30,21 +30,13 @@ class SchoolYear(models.Model):
class StudentTag(models.Model): class StudentTag(models.Model):
tag = models.SlugField() name = models.CharField(max_length=255)
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type', 'object_id')
created_at = models.DateTimeField(auto_now_add=True) created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True) updated_at = models.DateTimeField(auto_now=True)
def __str__(self): def __str__(self):
return self.tag return self.name
class Meta:
indexes = [
models.Index(fields=['content_type', 'object_id']),
]
# class StudentManager(models.Manager): # class StudentManager(models.Manager):
@ -70,7 +62,7 @@ class Student(models.Model):
address = models.TextField(blank=True) address = models.TextField(blank=True)
dob = models.DateField() dob = models.DateField()
tags = GenericRelation(StudentTag) tags = models.ManyToManyField(StudentTag, blank=True)
created_at = models.DateTimeField(auto_now_add=True) created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True) updated_at = models.DateTimeField(auto_now=True)
@ -236,6 +228,12 @@ class SchoolDay(models.Model):
created_at = models.DateTimeField(auto_now_add=True) created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True) updated_at = models.DateTimeField(auto_now=True)
def get_absolute_url(self):
return reverse('core:schoolday-detail', kwargs={
'year': self.school_year.year,
'pk': self.pk
})
def __str__(self): def __str__(self):
return f'{self.date}' return f'{self.date}'
@ -265,6 +263,13 @@ class AttendanceEntry(models.Model):
created_at = models.DateTimeField(auto_now_add=True) created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True) updated_at = models.DateTimeField(auto_now=True)
def get_absolute_url(self):
return reverse('core:schoolday-detail', kwargs={
'year': self.school_day.school_year.year,
'pk': self.school_day.pk,
'entry_pk': self.pk
})
def __str__(self): def __str__(self):
return f"{self.day} | {self.student} | {self.status}" return f"{self.day} | {self.student} | {self.status}"

View File

@ -0,0 +1,13 @@
{% extends 'base.html' %}
{% block content %}
<h1>Delete Attendanceentry</h1>
<form method="POST" action="{% url 'core:attendanceentry-delete' attendanceentry.pk %}">
{% csrf_token %}
<p>Are you sure you want to delete "{{ attendanceentry }}"?</p>
{{ form.as_p }}
<p>
<input type="submit" value="Delete"> or <a href="{% url 'core:attendanceentry-detail' attendanceentry.pk %}">cancel</a>
</p>
</form>
{% endblock %}

View File

@ -0,0 +1,12 @@
{% extends 'base.html' %}
{% block content %}
<h1>+ New Attendanceentry</h1>
<form method="POST" action="{% url 'core:attendanceentry-create' %}">
{% csrf_token %}
{{ form.as_p }}
<p>
<input type="submit" value="Create"> or <a href="{% url 'core:attendanceentry-list' %}">cancel</a>
</p>
</form>
{% endblock %}

View File

@ -0,0 +1,33 @@
{% extends 'base.html' %}
{% block head_title %}Attendance | {% endblock head_title %}
{% block breadcrumbs %}
<div class="breadcrumbs">
<menu>
<li><strong><a href="{% url 'core:schoolyear-detail' entry.schoolday.school_year.year %}">{{ entry.schoolday.school_year.year }}</a></strong></li>
<span></span>
<li><a href="{% url 'core:schoolday-list' entry.schoolday.school_year.year %}">Attendance</a></li>
<span></span>
<li><a href="{% url 'core:schoolday-detail' entry.schoolday.school_year.year entry.schoolday.pk %}">{{ entry.schoolday }}</a></li>
</menu>
</div>
{% endblock breadcrumbs %}
{% block content %}
<article class="form">
<header class="form__header">
<div>
<h1>Edit Attendance</h1>
</div>
<p><a href="{% url 'core:schoolday-delete' entry.schoolday.school_year.year entry.schoolday.pk %}" class="action-button action-delete">Delete</a></p>
</header>
<form method="POST" action="{% url 'core:schoolday-update' school_year.year entry.schoolday.pk %}">
{% csrf_token %}
{{ form.as_p }}
<p>
<input type="submit" value="Save changes"> or <a href="{% url 'core:schoolday-list' school_year.year %}">cancel</a>
</p>
</form>
</article>
{% endblock %}

View File

@ -0,0 +1,33 @@
{% extends 'base.html' %}
{% block head_title %}Attendance | {% endblock head_title %}
{% block breadcrumbs %}
<div class="breadcrumbs">
<menu>
<li><strong><a href="{% url 'core:schoolyear-detail' entry.school_day.school_year.year %}">{{ entry.school_day.school_year.year }}</a></strong></li>
<span></span>
<li><a href="{% url 'core:schoolday-list' entry.school_day.school_year.year %}">Attendance</a></li>
<span></span>
<li><a href="{% url 'core:schoolday-detail' entry.school_day.school_year.year entry.school_day.pk %}">{{ entry.school_day }}</a></li>
</menu>
</div>
{% endblock breadcrumbs %}
{% block content %}
<article class="form">
<header class="form__header">
<div>
<h1>Edit Attendance</h1>
</div>
<p><a href="{% url 'core:entry-delete' entry.school_day.school_year.year entry.school_day.pk entry.pk %}" class="action-button action-delete">Delete</a></p>
</header>
<form method="POST" action="{% url 'core:entry-update' entry.school_day.school_year.year entry.school_day.pk entry.pk %}">
{% csrf_token %}
{{ form.as_p }}
<p>
<input type="submit" value="Save changes"> or <a href="{% url 'core:schoolday-detail' entry.school_day.school_year.year entry.school_day.pk %}">cancel</a>
</p>
</form>
</article>
{% endblock %}

View File

@ -0,0 +1,16 @@
{% extends 'base.html' %}
{% block content %}
<h1>Attendanceentrys</h1>
<table>
<tbody>
{% for attendanceentry in attendanceentry_list %}
<tr>
<dt>{{ attendanceentry }}</dt>
</tr>
{% empty %}
<tr>No attendanceentrys yet.</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}

View File

@ -63,7 +63,7 @@
<tr> <tr>
<td><a href="{% url 'core:student-detail' component.subject.school_year.year score.student.pk %}">{{score.student.student_id}} &mdash; {{score.student}}</a></td> <td><a href="{% url 'core:student-detail' component.subject.school_year.year score.student.pk %}">{{score.student.student_id}} &mdash; {{score.student}}</a></td>
<td>{{score.value}} / {{component.grade_total}}</td> <td>{{score.value}} / {{component.grade_total}}</td>
<td><a href="{% url 'core:score-update' component.subject.school_year.year score.pk %}">Edit score</a></td> <td><a href="{% url 'core:score-update' component.subject.school_year.year score.pk %}">Edit</a></td>
</tr> </tr>
{% endfor %} {% endfor %}
<tr> <tr>

View File

@ -1,7 +1,7 @@
{% extends 'base.html' %} {% extends 'base.html' %}
{% block content %} {% block content %}
<h1>Update Component</h1> <h1>Edit Component</h1>
<form method="POST" action="{% url 'core:component-update' component.pk %}"> <form method="POST" action="{% url 'core:component-update' component.pk %}">
{% csrf_token %} {% csrf_token %}
{{ form.as_p }} {{ form.as_p }}

View File

@ -0,0 +1,29 @@
{% extends "base.html" %}
{% block head_title %}Delete Attendance | {% endblock head_title %}
{% block breadcrumbs %}
<div class="breadcrumbs">
<menu>
<li><strong><a href="{% url 'core:schoolyear-detail' school_year.year %}">{{ school_year.year }}</a></strong></li>
<span></span>
<li><a href="{% url 'core:schoolday-list' school_year.year %}">Attendance</a></li>
<span></span>
<li><a href="{% url 'core:schoolday-detail' school_year.year schoolday.pk %}">{{ schoolday.date }}</a></li>
</menu>
</div>
{% endblock breadcrumbs %}
{% block content %}
<article class="form">
<h1>Delete Attendance</h1>
<form method="POST" action="{% url 'core:schoolday-delete' school_year.year schoolday.pk %}">
{% csrf_token %}
<p>Are you sure you want to delete "{{ schoolday }}"?</p>
{{ form.as_p }}
<p>
<input type="submit" value="Delete" class="action-button action-delete"> or <a href="{% url 'core:schoolday-detail' school_year.year schoolday.pk %}">cancel</a>
</p>
</form>
</article>
{% endblock %}

View File

@ -0,0 +1,46 @@
{% extends 'base.html' %}
{% block head_title %}Attendance | {% endblock head_title %}
{% block breadcrumbs %}
<div class="breadcrumbs">
<menu>
<li><strong><a href="{% url 'core:schoolyear-detail' school_year.year %}">{{ school_year.year }}</a></strong></li>
<span></span>
<li><a href="{% url 'core:schoolday-list' school_year.year %}">Attendance</a></li>
</menu>
</div>
{% endblock breadcrumbs %}
{% block content %}
<article class="form">
<h1>Take Attendance</h1>
<form method="POST" action="{% url 'core:schoolday-create' school_year.year %}">
{% csrf_token %}
{{ form.as_p }}
<table>
<thead>
<tr>
<td>Student</td>
<td>Present</td>
<td>Tardy</td>
<td>Absent</td>
</tr>
</thead>
<tbody>
{% for student in student_list %}
<tr>
<td><h5>{{student.full_name}}</h5></td>
<td><input type="radio" name="students_{{student.pk}}" value="P" checked></td>
<td><input type="radio" name="students_{{student.pk}}" value="T"></td>
<td><input type="radio" name="students_{{student.pk}}" value="A"></td>
</tr>
{% endfor %}
</tbody>
</table>
<p>
<input type="submit" value="Save attendance"> or <a href="{% url 'core:schoolday-list' school_year.year %}">cancel</a>
</p>
</form>
</article>
{% endblock %}

View File

@ -0,0 +1,46 @@
{% extends 'base.html' %}
{% load helpers %}
{% block head_title %}Attendance {{ schoolday.date }} | {% endblock head_title %}
{% block breadcrumbs %}
<div class="breadcrumbs">
<menu>
<li><strong><a href="{% url 'core:schoolyear-detail' schoolday.school_year.year %}">{{ schoolday.school_year.year }}</a></strong></li>
<span></span>
<li><a href="{% url 'core:schoolday-list' schoolday.school_year.year %}">Attendance</a></li>
</menu>
</div>
{% endblock breadcrumbs %}
{% block content %}
<article class="detail">
<header class="detail__header">
<div>
<h1>Attendance {{ schoolday.date }}</h1>
<p><small>Added: <time datetime="{{ schoolday.created_at|date:'Y-m-d' }}">{{ schoolday.created_at|date:'M d Y' }}</time><br>
Last updated: <time datetime="{{ schoolday.updated_at|date:'Y-m-d' }}">{{ schoolday.updated_at|date:'M d Y' }}</time></small></p>
</div>
<a href="{% url 'core:schoolday-update' schoolday.school_year.year schoolday.pk %}" class="action-button">Edit</a>
</header>
<section>
<table>
<thead>
<tr>
<td>Student</td>
<td colspan="2">Status</td>
</tr>
</thead>
<tbody>
{% for entry in schoolday.attendanceentry_set.all %}
<tr>
<td>{{entry.student}}</td>
<td>{{entry.get_status_display}}</td>
<td><a href="{% url 'core:entry-update' schoolday.school_year.year schoolday.pk entry.pk %}">Edit</a></td>
</tr>
{% endfor %}
</tbody>
</table>
</section>
</article>
{% endblock %}

View File

@ -0,0 +1,53 @@
{% extends 'base.html' %}
{% block head_title %}Edit Attendance | {% endblock head_title %}
{% block breadcrumbs %}
<div class="breadcrumbs">
<menu>
<li><strong><a href="{% url 'core:schoolyear-detail' schoolday.school_year.year %}">{{ schoolday.school_year.year }}</a></strong></li>
<span></span>
<li><a href="{% url 'core:schoolday-list' schoolday.school_year.year %}">Attendance</a></li>
<span></span>
<li><a href="{% url 'core:schoolday-detail' schoolday.school_year.year schoolday.pk %}">{{ schoolday }}</a></li>
</menu>
</div>
{% endblock breadcrumbs %}
{% block content %}
<article class="form">
<header class="form__header">
<div>
<h1>Edit Attendance</h1>
</div>
<p><a href="{% url 'core:schoolday-delete' schoolday.school_year.year schoolday.pk %}" class="action-button action-delete">Delete</a></p>
</header>
<form method="POST" action="{% url 'core:schoolday-update' school_year.year schoolday.pk %}">
{% csrf_token %}
{{ form.as_p }}
<table>
<thead>
<tr>
<td>Student</td>
<td>Present</td>
<td>Tardy</td>
<td>Absent</td>
</tr>
</thead>
<tbody>
{% for entry in schoolday.attendanceentry_set.all %}
<tr>
<td><h5>{{entry.student.full_name}}</h5></td>
<td><input type="radio" name="students_{{ entry.student.pk }}" value="P" {% if entry.status == "P" %}checked{% endif %}></td>
<td><input type="radio" name="students_{{ entry.student.pk }}" value="T" {% if entry.status == "T" %}checked{% endif %}></td>
<td><input type="radio" name="students_{{ entry.student.pk }}" value="A" {% if entry.status == "A" %}checked{% endif %}></td>
</tr>
{% endfor %}
</tbody>
</table>
<p>
<input type="submit" value="Save changes"> or <a href="{% url 'core:schoolday-detail' school_year.year schoolday.pk %}">cancel</a>
</p>
</form>
</article>
{% endblock %}

View File

@ -0,0 +1,54 @@
{% extends 'base.html' %}
{% load static %}
{% block head_title %}Attendance | {% endblock head_title %}
{% block breadcrumbs %}
<div class="breadcrumbs">
<menu>
<li><strong><a href="{% url 'core:schoolyear-detail' school_year.year %}">{{ school_year.year }}</a></strong></li>
</menu>
</div>
{% endblock breadcrumbs %}
{% block content %}
<article class="list">
<header class="list__header">
<div class="list__title">
<h1>Attendance</h1>
<a href="{% url 'core:schoolday-create' school_year.year %}" class="action-button">Take attendance &rarr;</a>
</div>
</header>
{% for schoolday in schoolday_list %}
<section>
<h4><a href="{% url 'core:schoolday-detail' school_year.year schoolday.pk %}">{{ schoolday.date }}</a></h4>
<table class="list__table">
<thead>
<tr>
<th>Student</th>
<th colspan="2">Status</th>
</tr>
</thead>
<tbody>
{% for entry in schoolday.attendanceentry_set.all %}
<tr onclick="document.location=''">
<td>{{entry.student}}</td>
<td>{{entry.get_status_display}}</td>
<td><a href="{% url 'core:entry-update' school_year.year schoolday.pk entry.pk %}">Edit</a></td>
</tr>
{% empty %}
<tr>
<td colspan="3">No attendance yet.</td>
</tr>
{% endfor %}
</tbody>
</table>
</section>
{% empty %}
<section>
<p>No attendance yet.</p>
</section>
{% endfor %}
{% include 'core/partials/pagination.html' %}
</article>
{% endblock %}

View File

@ -1,13 +1,12 @@
{% extends 'base.html' %} {% extends 'base.html' %}
{% block head_title %}Project {{ schoolyear.name }} | {% endblock head_title %} {% block head_title %}Year {{ schoolyear.year }} | {% endblock head_title %}
{% block content %} {% block content %}
<article class="detail"> <article class="detail">
<header class="detail__header"> <header class="detail__header">
<div> <div>
<h1>{{ schoolyear }}</h1> <h1>{{ schoolyear }}</h1>
<p><small>Created <time datetime="{{ schoolyear.created_at|date:'Y-m-d' }}">{{ schoolyear.created_at }}</time></small></p>
</div> </div>
{% if perms.core.can_change_schoolyear %} {% if perms.core.can_change_schoolyear %}
<a href="{% url 'core:schoolyear-update' schoolyear.year %}" class="action-button">Edit</a> <a href="{% url 'core:schoolyear-update' schoolyear.year %}" class="action-button">Edit</a>
@ -19,7 +18,7 @@
<p>Tool Description</p> <p>Tool Description</p>
<span>&rarr;</span> <span>&rarr;</span>
</a> </a>
<a href="" class="tool"> <a href="{% url 'core:schoolday-list' schoolyear.year %}" class="tool">
<h3>Attendence</h3> <h3>Attendence</h3>
<p>Tool Description</p> <p>Tool Description</p>
<span>&rarr;</span> <span>&rarr;</span>

View File

@ -1,12 +1,18 @@
{% extends 'base.html' %} {% extends 'base.html' %}
{% block head_title %}Edit Year {{ schoolyear.year }} | {% endblock head_title %}
{% block content %} {% block content %}
<h1>Update Schoolyear</h1> <article class="form">
<form method="POST" action="{% url 'core:schoolyear-update' schoolyear.year %}"> <header class="form_header">
{% csrf_token %} <h1>Edit Schoolyear</h1>
{{ form.as_p }} </header>
<p> <form method="POST" action="{% url 'core:schoolyear-update' schoolyear.year %}">
<input type="submit" value="Save changes"> or <a href="{% url 'core:schoolyear-detail' schoolyear.year %}">cancel</a> {% csrf_token %}
</p> {{ form.as_p }}
</form> <p>
<input type="submit" value="Save changes"> or <a href="{% url 'core:schoolyear-detail' schoolyear.year %}">cancel</a>
</p>
</form>
</article>
{% endblock %} {% endblock %}

View File

@ -18,7 +18,7 @@
{% for schoolyear in schoolyear_list %} {% for schoolyear in schoolyear_list %}
<a href="{% url 'core:schoolyear-detail' schoolyear.year %}" class="schoolyear"> <a href="{% url 'core:schoolyear-detail' schoolyear.year %}" class="schoolyear">
<h2>{{ schoolyear.year }}</h2> <h2>{{ schoolyear.year }}</h2>
<h5>Students: () &emsp; Subjects: ()</h5> <h5>Students: ({{ schoolyear.student__count }}) &emsp; Subjects: ({{ schoolyear.subject__count }})</h5>
<span>&rarr;</span> <span>&rarr;</span>
</a> </a>
{% empty %} {% empty %}

View File

@ -20,19 +20,18 @@
<article class="form"> <article class="form">
<header class="form__header"> <header class="form__header">
<div> <div>
<h1>Update Score</h1> <h1>Edit Score</h1>
<h2>{{score.component.subject}}&mdash; <em>{{score.component.get_category_display}}</em>: {{score.component}}</h2> <h2>{{ score.component.subject }}&mdash; <em>{{ score.component.get_category_display }}</em>: {{ score.component }}</h2>
</div> </div>
<p><a href="{% url 'core:score-delete' school_year.year score.pk %}" class="action-button action-delete">Delete score</a></p> <p><a href="{% url 'core:score-delete' school_year.year score.pk %}" class="action-button action-delete">Delete</a></p>
</header> </header>
<section> <section>
<form action="{% url 'score-update' score.pk %}" method="POST"> <form action="{% url 'core:score-update' school_year.year score.pk %}" method="POST">
{% csrf_token %} {% csrf_token %}
<input type="hidden" name="next" value="{{next}}"> <h3>{{ score.student }}</h3>
<h3>{{score.student}}</h3> {{ form.as_p }}
{{form.as_p}}
<p> <p>
<input class="action-button" type="submit" value="Save changes"> or <a href="{% url 'student-detail' score.student.pk %}">cancel</a> <input class="action-button" type="submit" value="Save changes"> or <a href="{% url 'core:component-detail' school_year.year score.component.subject.pk score.component.pk %}">cancel</a>
</p> </p>
</form> </form>
</section> </section>

View File

@ -25,10 +25,6 @@
</header> </header>
<section class="detail__info"> <section class="detail__info">
<dl class="detail__datalist"> <dl class="detail__datalist">
{% if student.allergies %}
<dt>Allergies</dt>
<dd>{{ student.allergies }}</dd>
{% endif %}
<dt>Birthday</dt> <dt>Birthday</dt>
<dd>{{ student.dob }}</dd> <dd>{{ student.dob }}</dd>
<dt>Age</dt> <dt>Age</dt>
@ -39,37 +35,47 @@
<address>{{ student.address|linebreaksbr }}</address> <address>{{ student.address|linebreaksbr }}</address>
</dd> </dd>
{% endif %} {% endif %}
{% if student.tags.count > 0 %}
<dt>Tags</dt>
<div>
{% for tag in student.tags.all %}
<dd><a href="{% url 'core:stag-detail' school_year.year tag.pk %}" class="tag tag__info">{{ tag }}</a></dd>{% if not forloop.last %}<br>{% endif %}
{% endfor %}
</div>
{% endif %}
</dl> </dl>
</section> </section>
<section class="grades"> <section class="grades">
<h2>Grades</h2> <h2>Grades</h2>
<table> <table>
<thead> <thead>
<th>Subject</th> <tr>
<th>Grade</th> <th>Subject</th>
<th>Grade</th>
</tr>
</thead> </thead>
<tbody> <tbody>
{% for subject in subject_list %} {% for subject in subject_list %}
<tr> <tr>
<td class="grade"><h5>{{subject}}</h5></td> <td class="grade"><h5>{{ subject }}</h5></td>
<td class="grade">{{subject.grade|grade_as_percentage:subject.grade_total}}%</td> <td class="grade">{{ subject.grade|grade_as_percentage:subject.grade_total }}%</td>
</tr> </tr>
{% empty %} {% empty %}
<tr> <tr>
<td colspan="2">No grades yet. To add a grade you will need to enter a score for this student on a component.</td> <td colspan="2">No grades yet. You will need to enter a score for this student on a component.</td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
</table> </table>
</section> </section>
<section> <section>
<h2>Components</h2> <h2>Scores</h2>
<div class="student__components"> <div class="student__components">
{% regroup score_list by component.subject as score_list %} {% regroup score_list by component.subject as score_list %}
{% for subject in score_list %} {% for subject in score_list %}
<div class="student__component"> <div class="student__component">
<h4>{{subject.grouper}}</h4> <h4>{{ subject.grouper }}</h4>
<table> <table>
<thead> <thead>
<tr> <tr>
@ -83,15 +89,14 @@
</thead> </thead>
<tbody> <tbody>
{% for score in subject.list %} {% for score in subject.list %}
<tr class="subject has-link" onclick="document.location='{% url 'component-detail' score.component.subject.pk score.component.pk %}'">
<tr> <tr>
<td>{{score.component.due_date}}</td> <td>{{ score.component.due_date }}</td>
<td>{{score.component}}</td> <td>{{ score.component }}</td>
<td>{{score.component.get_category_display}}</td> <td>{{ score.component.get_category_display }}</td>
<td>{{score.value}}</td> <td>{{ score.value }}</td>
<td>{{score.component.grade_total}}</td> <td>{{ score.component.grade_total }}</td>
<td>{{score.grade_as_percentage}}%</td> <td>{{ score.grade_as_percentage }}%</td>
<td><a href="{% url 'score-update' score.pk %}?return_to={{request.get_full_path}}">Change score</a></td> <td><a href="{% url 'core:score-update' student.school_year.year score.pk %}">Edit</a></td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
@ -112,15 +117,14 @@
<table> <table>
<thead> <thead>
<tr> <tr>
<th>Date</th> <th colspan="2">Date</th>
<th colspan="2">Status</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% for entry in status.list %} {% for entry in status.list %}
<tr> <tr>
<td>{{entry.day.date}}</td> <td>{{ entry.school_day.date }}</td>
<td><a href="{% url 'entry-update' entry.pk %}">Update</a></td> <td><a href="{% url 'core:entry-update' entry.school_day.school_year.year entry.school_day.pk entry.pk %}">Edit</a></td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>

View File

@ -17,7 +17,7 @@
{% block content %} {% block content %}
<article class="form"> <article class="form">
<h1>Update Student</h1> <h1>Edit Student</h1>
<form method="POST" action="{% url 'core:student-update' student.school_year.year student.pk %}"> <form method="POST" action="{% url 'core:student-update' student.school_year.year student.pk %}">
{% csrf_token %} {% csrf_token %}
{{ form.as_p }} {{ form.as_p }}

View File

@ -18,12 +18,12 @@
<h1>Students</h1> <h1>Students</h1>
<a href="{% url 'core:student-create' school_year.year %}" class="action-button">+ New Student</a> <a href="{% url 'core:student-create' school_year.year %}" class="action-button">+ New Student</a>
</div> </div>
<a href="">Student Tags &rarr;</a> <a href="{% url 'core:stag-list' school_year.year %}">Student Tags &rarr;</a>
</header> </header>
<table class="list__table"> <table class="list__table">
<thead> <thead>
<tr> <tr>
<th><a href="?order_by=record_num&direction=asc">Student No. &varr;</a></th> <th><a href="?order_by=record_num&sort=asc">Student No. &varr;</a></th>
<th>Name</th> <th>Name</th>
<th>Tags</th> <th>Tags</th>
</tr> </tr>
@ -32,12 +32,16 @@
{% for student in student_list %} {% for student in student_list %}
<tr class="has-link" onclick="document.location='{% url 'core:student-detail' school_year.year student.pk %}'"> <tr class="has-link" onclick="document.location='{% url 'core:student-detail' school_year.year student.pk %}'">
<td>{{ student.student_id }}</td> <td>{{ student.student_id }}</td>
<td>{{ student }}</td> <td><h5>{{ student }}</h5></td>
<td>(tags)</td> <td>
{% for tag in student.tags.all %}
<a href="{% url 'core:stag-detail' school_year.year tag.pk %}" class="tag tag__info">{{ tag }}</a>
{% endfor %}
</td>
</tr> </tr>
{% empty %} {% empty %}
<tr> <tr>
<td colspan="7">No students yet.</td> <td colspan="3">No students yet.</td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>

View File

@ -0,0 +1,13 @@
{% extends 'base.html' %}
{% block content %}
<h1>Delete Studenttag</h1>
<form method="POST" action="{% url 'core:studenttag-delete' studenttag.pk %}">
{% csrf_token %}
<p>Are you sure you want to delete "{{ studenttag }}"?</p>
{{ form.as_p }}
<p>
<input type="submit" value="Delete"> or <a href="{% url 'core:studenttag-detail' studenttag.pk %}">cancel</a>
</p>
</form>
{% endblock %}

View File

@ -0,0 +1,28 @@
{% extends 'base.html' %}
{% block head_title %}New Tag | {% endblock head_title %}
{% block breadcrumbs %}
<div class="breadcrumbs">
<menu>
<li><strong><a href="{% url 'core:schoolyear-detail' school_year.year %}">{{ school_year.year }}</a></strong></li>
<span></span>
<li><a href="{% url 'core:student-list' school_year.year %}">Students</a></li>
<span></span>
<li><a href="{% url 'core:stag-list' school_year.year %}">Student Tags</a></li>
</menu>
</div>
{% endblock breadcrumbs %}
{% block content %}
<article class="form">
<h1>+ New Tag</h1>
<form method="POST" action="{% url 'core:stag-create' school_year.year %}">
{% csrf_token %}
{{ form.as_p }}
<p>
<input type="submit" value="Create"> or <a href="{% url 'core:stag-list' school_year.year %}">cancel</a>
</p>
</form>
</article>
{% endblock %}

View File

@ -0,0 +1,50 @@
{% extends 'base.html' %}
{% load helpers %}
{% block head_title %}Tag {{ tag }} | {% endblock head_title %}
{% block breadcrumbs %}
<div class="breadcrumbs">
<menu>
<li><strong><a href="{% url 'core:schoolyear-detail' school_year.year %}">{{ school_year.year }}</a></strong></li>
<span></span>
<li><a href="{% url 'core:student-list' school_year.year %}">Students</a></li>
<span></span>
<li><a href="{% url 'core:stag-list' school_year.year %}">Student Tags</a></li>
</menu>
</div>
{% endblock breadcrumbs %}
{% block content %}
<article class="detail">
<header class="detail__header">
<div class="detail__title">
<h1>{{ tag }}</h1>
</div>
<a href="{% url 'core:stag-update' school_year.year tag.pk %}" class="action-button">Edit</a>
</header>
<section>
<h3>Students with this tag</h3>
<table class="list__table">
<thead>
<tr>
<th><a href="?order_by=id&sort=asc">Student No. &varr;</a></th>
<th>Name</th>
</tr>
</thead>
<tbody>
{% for student in tag.student_set.all %}
<tr class="has-link" onclick="document.location='{% url 'core:student-detail' school_year.year student.pk %}'">
<td>{{ student.student_id }}</td>
<td>{{ student }}</td>
</tr>
{% empty %}
<tr>
<td colspan="2">No students tagged yet.</td>
</tr>
{% endfor %}
</tbody>
</table>
</section>
</article>
{% endblock %}

View File

@ -0,0 +1,28 @@
{% extends 'base.html' %}
{% block head_title %}Edit Tag | {% endblock head_title %}
{% block breadcrumbs %}
<div class="breadcrumbs">
<menu>
<li><strong><a href="{% url 'core:schoolyear-detail' school_year.year %}">{{ school_year.year }}</a></strong></li>
<span></span>
<li><a href="{% url 'core:student-list' school_year.year %}">Students</a></li>
<span></span>
<li><a href="{% url 'core:stag-list' school_year.year %}">Student Tags</a></li>
</menu>
</div>
{% endblock breadcrumbs %}
{% block content %}
<article class="form">
<h1>Edit Tag</h1>
<form method="POST" action="{% url 'core:stag-update' school_year.year tag.pk %}">
{% csrf_token %}
{{ form.as_p }}
<p>
<input type="submit" value="Save changes"> or <a href="{% url 'core:stag-detail' school_year.year tag.pk %}">cancel</a>
</p>
</form>
</article>
{% endblock %}

View File

@ -0,0 +1,32 @@
{% extends 'base.html' %}
{% load helpers %}
{% block head_title %}Student Tags | {% endblock head_title %}
{% block breadcrumbs %}
<div class="breadcrumbs">
<menu>
<li><strong><a href="{% url 'core:schoolyear-detail' school_year.year %}">{{ school_year.year }}</a></strong></li>
<span></span>
<li><a href="{% url 'core:student-list' school_year.year %}">Students</a></li>
</menu>
</div>
{% endblock breadcrumbs %}
{% block content %}
<article class="list">
<header class="list__header">
<div class="list__title">
<h1>Student Tags</h1>
<a href="{% url 'core:stag-create' school_year.year %}" class="action-button">+ New Tag</a>
</div>
</header>
<section>
{% for tag in studenttag_list %}
<a href="{% url 'core:stag-detail' school_year.year tag.pk %}" class="tag tag__info">{{ tag }}</a>
{% empty %}
<p>No tags yet.</p>
{% endfor %}
</section>
</article>
{% endblock %}

View File

@ -1,12 +1,30 @@
{% extends 'base.html' %} {% extends 'base.html' %}
{% block head_title %}Edit Subject | {% endblock head_title %}
{% block breadcrumbs %}
<div class="breadcrumbs">
<menu>
<li><strong><a href="{% url 'core:schoolyear-detail' subject.school_year.year %}">{{ subject.school_year.year }}</a></strong></li>
<span></span>
<li><a href="{% url 'core:subject-list' subject.school_year.year %}">Subjects</a></li>
<span></span>
<li><a href="{% url 'core:subject-detail' subject.school_year.year subject.pk %}">{{ subject }}</a></li>
</menu>
</div>
{% endblock breadcrumbs %}
{% block content %} {% block content %}
<h1>Update Subject</h1> <article class="form">
<form method="POST" action="{% url 'core:subject-update' subject.pk %}"> <header>
{% csrf_token %} <h1>Edit Subject</h1>
{{ form.as_p }} </header>
<p> <form method="POST" action="{% url 'core:subject-update' subject.school_year.year subject.pk %}">
<input type="submit" value="Save changes"> or <a href="{% url 'core:subject-detail' subject.pk %}">cancel</a> {% csrf_token %}
</p> {{ form.as_p }}
</form> <p>
<input type="submit" value="Save changes"> or <a href="{% url 'core:subject-detail' subject.school_year.year subject.pk %}">cancel</a>
</p>
</form>
</article>
{% endblock %} {% endblock %}

View File

@ -34,7 +34,7 @@
<h5>{{ subject.name }}</h5> <h5>{{ subject.name }}</h5>
<small>{{ subject.description }}</small> <small>{{ subject.description }}</small>
</td> </td>
<td>(componenet count)</td> <td>{{ subject.component__count }}</td>
</tr> </tr>
{% empty %} {% empty %}
<tr> <tr>

View File

@ -0,0 +1,69 @@
{% extends 'base.html' %}
{% load static %}
{% block content %}
<article class="panel">
<header>
<h1>Here's what's going on today</h1>
</header>
<section>
<h3 class="domain__heading">Birthdays this week</h3>
<ul>
{% for student in birthdays %}
<li><strong><a href="{% url 'core:student-detail' current_year.year student.pk %}">{{ student }}</a></strong> is turning {{ student.age|add:1 }} on {{ student.dob|date:"M j" }}</li>
{% empty %}
<p>No Birthdays this next week.</p>
{% endfor %}
</ul>
</section>
<section>
<h3 class="domain__heading">Today's Assignments</h3>
<ul>
{% for component in components %}
<li>
{{component.subject}}, <a href="{% url 'core:component-detail' component.subject.pk component.pk %}">{{component}}</a>
</li>
{% empty %}
<p>Nothing for today.</p>
{% endfor %}
</ul>
</section>
<section>
<h3 class="domain__heading">Today's Attendance</h3>
{% for day in attendance %}
<h4><a href="{% url 'core:schoolday-update' current_year.year day.pk %}">{{day.date}}</a></h4>
<table>
<thead>
<tr>
<td>Student</td>
<td colspan="2">Status</td>
</tr>
</thead>
<tbody>
{% for entry in day.attendanceentry_set.all %}
<tr>
<td>{{entry.student}}</td>
<td>{{entry.get_status_display}}</td>
<td><a href="{% url 'core:entry-update' current_year.year entry.school_day.pk entry.pk %}">Edit</a></td>
</tr>
{% endfor %}
</tbody>
</table>
{% empty %}
<p class="greeting">No attendance taken yet: <a href="{% url 'core:day-create' %}" class="action-button">Take attendance</a></p>
{% endfor %}
</section>
<section>
<h3 class="domain__heading">Assignments to be graded</h3>
<ul>
{% for component in ungraded_components %}
<li>
{{component.subject}}, <a href="{% url 'core:component-detail' current_year.year component.subject.pk component.pk %}">{{component}}</a>
</li>
{% empty %}
<p>Everything is graded to far.</p>
{% endfor %}
</ul>
</section>
</article>
{% endblock %}

View File

@ -2,6 +2,8 @@ from django.urls import path, include
from . import views from . import views
urlpatterns = [ urlpatterns = [
path('today/', views.TodayView.as_view(), name='today'),
# SchoolYears # SchoolYears
path('years/', include([ path('years/', include([
path( path(
@ -55,6 +57,37 @@ urlpatterns = [
name='student-delete' name='student-delete'
), ),
])), ])),
# StudentTags
path('tags/', include([
path(
'',
views.StudentTagListView.as_view(),
name='stag-list'
),
path(
'new/',
views.StudentTagCreateView.as_view(),
name='stag-create'
),
path('<int:stag_pk>/', include([
path(
'',
views.StudentTagDetailView.as_view(),
name='stag-detail'
),
path(
'update/',
views.StudentTagUpdateView.as_view(),
name='stag-update'
),
path(
'delete/',
views.StudentTagDeleteView.as_view(),
name='stag-delete'
),
])),
])),
])), ])),
# Subjects # Subjects
@ -124,6 +157,68 @@ urlpatterns = [
])), ])),
])), ])),
# SchoolDays
path('schooldays/', include([
path(
'',
views.SchoolDayListView.as_view(),
name='schoolday-list'
),
path(
'new/',
views.SchoolDayCreateView.as_view(),
name='schoolday-create'
),
path('<int:pk>/', include([
path(
'',
views.SchoolDayDetailView.as_view(),
name='schoolday-detail'
),
path(
'update/',
views.SchoolDayUpdateView.as_view(),
name='schoolday-update'
),
path(
'delete/',
views.SchoolDayDeleteView.as_view(),
name='schoolday-delete'
),
# AttendanceEntries
path('entries/', include([
path(
'',
views.AttendanceEntryListView.as_view(),
name='entry-list'
),
path(
'new/',
views.AttendanceEntryCreateView.as_view(),
name='entry-create'
),
path('<int:entry_pk>/', include([
path(
'',
views.AttendanceEntryDetailView.as_view(),
name='entry-detail'
),
path(
'update/',
views.AttendanceEntryUpdateView.as_view(),
name='entry-update'
),
path(
'delete/',
views.AttendanceEntryDeleteView.as_view(),
name='entry-delete'
),
])),
])),
])),
])),
# Scores # Scores
path('scores/', include([ path('scores/', include([
path( path(

View File

@ -1,3 +1,4 @@
import datetime as dt
from django.conf import settings from django.conf import settings
from django.utils import timezone from django.utils import timezone
from django.db import models from django.db import models
@ -34,29 +35,67 @@ from .models import (
from .forms import ( from .forms import (
SchoolYearCreateForm, SchoolYearCreateForm,
ComponentCreateForm ComponentCreateForm,
SchoolDayForm,
AttendanceEntryForm
) )
class SchoolYearListView(ListView): class TodayView(LoginRequiredMixin, TemplateView):
template_name = 'core/today.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
today = timezone.localtime(timezone.now()).date()
enddate = today + dt.timedelta(days=7)
context['birthdays'] = Student.objects.filter(
dob__month=today.month,
dob__day__range=[today.day, enddate.day]
).order_by('dob')
context['components'] = Component.objects.filter(
due_date=today
).select_related('subject')
context['attendance'] = SchoolDay.objects.filter(
date=today
).prefetch_related('attendanceentry_set', 'attendanceentry_set__student')
context['ungraded_components'] = Component.objects.filter(
due_date__lte=today,
finished_grading=False
).select_related('subject')
return context
class SchoolYearListView(LoginRequiredMixin, ListView):
model = SchoolYear model = SchoolYear
paginate_by = 10 paginate_by = 10
def get_queryset(self):
queryset = SchoolYear.objects.annotate(
models.Count('student', distinct=True),
models.Count('subject', distinct=True)
).order_by('-year')
return queryset
class SchoolYearCreateView(SuccessMessageMixin, CreateView):
class SchoolYearCreateView(LoginRequiredMixin, SuccessMessageMixin, CreateView):
model = SchoolYear model = SchoolYear
success_message = 'SchoolYear created.' success_message = 'SchoolYear created.'
form_class = SchoolYearCreateForm form_class = SchoolYearCreateForm
template_name_suffix = '_create_form' template_name_suffix = '_create_form'
class SchoolYearDetailView(DetailView): class SchoolYearDetailView(LoginRequiredMixin, DetailView):
model = SchoolYear model = SchoolYear
slug_url_kwarg = 'year' slug_url_kwarg = 'year'
slug_field = 'year' slug_field = 'year'
class SchoolYearUpdateView(SuccessMessageMixin, UpdateView): class SchoolYearUpdateView(LoginRequiredMixin, SuccessMessageMixin, UpdateView):
model = SchoolYear model = SchoolYear
slug_url_kwarg = 'year' slug_url_kwarg = 'year'
slug_field = 'year' slug_field = 'year'
@ -64,7 +103,7 @@ class SchoolYearUpdateView(SuccessMessageMixin, UpdateView):
fields = '__all__' fields = '__all__'
class StudentListView(ListView): class StudentListView(LoginRequiredMixin, ListView):
model = Student model = Student
paginate_by = 50 paginate_by = 50
@ -82,7 +121,7 @@ class StudentListView(ListView):
return context return context
class StudentCreateView(SuccessMessageMixin, CreateView): class StudentCreateView(LoginRequiredMixin, SuccessMessageMixin, CreateView):
model = Student model = Student
success_message = 'Student created.' success_message = 'Student created.'
template_name_suffix = '_create_form' template_name_suffix = '_create_form'
@ -106,12 +145,16 @@ class StudentCreateView(SuccessMessageMixin, CreateView):
return context return context
class StudentDetailView(DetailView): class StudentDetailView(LoginRequiredMixin, DetailView):
model = Student model = Student
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
context['school_year'] = get_object_or_404(
SchoolYear, year=self.kwargs['year']
)
context['score_list'] = Score.objects.select_related( context['score_list'] = Score.objects.select_related(
'student' 'student'
).prefetch_related( ).prefetch_related(
@ -141,26 +184,124 @@ class StudentDetailView(DetailView):
return context return context
class StudentUpdateView(SuccessMessageMixin, UpdateView): class StudentUpdateView(LoginRequiredMixin, SuccessMessageMixin, UpdateView):
model = Student model = Student
success_message = 'Student saved.' success_message = 'Student saved.'
fields = '__all__' fields = '__all__'
class StudentDeleteView(SuccessMessageMixin, DeleteView): class StudentDeleteView(LoginRequiredMixin, SuccessMessageMixin, DeleteView):
model = Student model = Student
success_message = 'Student deleted.' success_message = 'Student deleted.'
success_url = reverse_lazy('student-list') success_url = reverse_lazy('student-list')
class SubjectListView(ListView): class StudentTagListView(LoginRequiredMixin, ListView):
model = StudentTag
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['school_year'] = get_object_or_404(
SchoolYear, year=self.kwargs['year']
)
return context
class StudentTagCreateView(LoginRequiredMixin, SuccessMessageMixin, CreateView):
model = StudentTag
success_message = 'Tag created.'
template_name_suffix = '_create_form'
fields = '__all__'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['school_year'] = get_object_or_404(
SchoolYear, year=self.kwargs['year']
)
return context
def get_success_url(self):
return reverse('core:stag-list', kwargs={
'year': self.kwargs['year']
})
class StudentTagDetailView(LoginRequiredMixin, DetailView):
model = StudentTag
pk_url_kwarg = 'stag_pk'
context_object_name = 'tag'
def get_object(self):
queryset = StudentTag.objects.filter(
pk=self.kwargs.get(self.pk_url_kwarg)
).prefetch_related(
Prefetch(
'student_set',
queryset=Student.objects.filter(
school_year__year=self.kwargs['year']
)
)
)
obj = queryset.get()
return obj
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['school_year'] = get_object_or_404(
SchoolYear, year=self.kwargs['year']
)
return context
class StudentTagUpdateView(LoginRequiredMixin, SuccessMessageMixin, UpdateView):
model = StudentTag
pk_url_kwarg = 'stag_pk'
context_object_name = 'tag'
success_message = 'Tag saved.'
fields = '__all__'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['school_year'] = get_object_or_404(
SchoolYear, year=self.kwargs['year']
)
return context
def get_success_url(self):
return reverse('core:stag-list', kwargs={
'year': self.kwargs['year']
})
class StudentTagDeleteView(LoginRequiredMixin, SuccessMessageMixin, DeleteView):
model = StudentTag
pk_url_kwarg = 'stag_pk'
context_object_name = 'tag'
success_message = 'Tag deleted.'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['school_year'] = get_object_or_404(
SchoolYear, year=self.kwargs['year']
)
return context
def get_success_url(self):
return reverse('core:stag-list', kwargs={
'year': self.kwargs['year']
})
class SubjectListView(LoginRequiredMixin, ListView):
model = Subject model = Subject
paginate_by = 50 paginate_by = 50
def get_queryset(self): def get_queryset(self):
queryset = Subject.objects.filter( queryset = Subject.objects.filter(
school_year__year=self.kwargs['year'] school_year__year=self.kwargs['year']
) ).annotate(
models.Count('component')
).order_by('name')
return queryset return queryset
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
@ -171,7 +312,7 @@ class SubjectListView(ListView):
return context return context
class SubjectCreateView(SuccessMessageMixin, CreateView): class SubjectCreateView(LoginRequiredMixin, SuccessMessageMixin, CreateView):
model = Subject model = Subject
success_message = 'Subject created.' success_message = 'Subject created.'
template_name_suffix = '_create_form' template_name_suffix = '_create_form'
@ -194,7 +335,7 @@ class SubjectCreateView(SuccessMessageMixin, CreateView):
return super().form_valid(form) return super().form_valid(form)
class SubjectDetailView(DetailView): class SubjectDetailView(LoginRequiredMixin, DetailView):
model = Subject model = Subject
def get_object(self): def get_object(self):
@ -214,7 +355,7 @@ class SubjectDetailView(DetailView):
return obj return obj
class SubjectUpdateView(SuccessMessageMixin, UpdateView): class SubjectUpdateView(LoginRequiredMixin, SuccessMessageMixin, UpdateView):
model = Subject model = Subject
success_message = 'Subject saved.' success_message = 'Subject saved.'
fields = '__all__' fields = '__all__'
@ -227,7 +368,7 @@ class SubjectUpdateView(SuccessMessageMixin, UpdateView):
return context return context
class SubjectDeleteView(SuccessMessageMixin, DeleteView): class SubjectDeleteView(LoginRequiredMixin, SuccessMessageMixin, DeleteView):
model = Subject model = Subject
success_message = 'Subject deleted.' success_message = 'Subject deleted.'
success_url = reverse_lazy('subject-list') success_url = reverse_lazy('subject-list')
@ -240,11 +381,11 @@ class SubjectDeleteView(SuccessMessageMixin, DeleteView):
return context return context
class ComponentListView(ListView): class ComponentListView(LoginRequiredMixin, ListView):
model = Component model = Component
class ComponentCreateView(SuccessMessageMixin, CreateView): class ComponentCreateView(LoginRequiredMixin, SuccessMessageMixin, CreateView):
model = Component model = Component
success_message = 'Component created.' success_message = 'Component created.'
template_name_suffix = '_create_form' template_name_suffix = '_create_form'
@ -270,7 +411,7 @@ class ComponentCreateView(SuccessMessageMixin, CreateView):
return super().form_valid(form) return super().form_valid(form)
class ComponentDetailView(DetailView): class ComponentDetailView(LoginRequiredMixin, DetailView):
model = Component model = Component
pk_url_kwarg = 'component_pk' pk_url_kwarg = 'component_pk'
@ -301,21 +442,21 @@ class ComponentDetailView(DetailView):
return context return context
class ComponentUpdateView(SuccessMessageMixin, UpdateView): class ComponentUpdateView(LoginRequiredMixin, SuccessMessageMixin, UpdateView):
model = Component model = Component
pk_url_kwarg = 'component_pk' pk_url_kwarg = 'component_pk'
success_message = 'Component saved.' success_message = 'Component saved.'
fields = '__all__' fields = '__all__'
class ComponentDeleteView(SuccessMessageMixin, DeleteView): class ComponentDeleteView(LoginRequiredMixin, SuccessMessageMixin, DeleteView):
model = Component model = Component
pk_url_kwarg = 'component_pk' pk_url_kwarg = 'component_pk'
success_message = 'Component deleted.' success_message = 'Component deleted.'
success_url = reverse_lazy('core:component-list') success_url = reverse_lazy('core:component-list')
class ComponentManagerView(LoginRequiredMixin, UpdateView): class ComponentManagerView(LoginRequiredMixin, LoginRequiredMixin, UpdateView):
model = Component model = Component
pk_url_kwarg = 'component_pk' pk_url_kwarg = 'component_pk'
template_name_suffix = '_manager' template_name_suffix = '_manager'
@ -353,22 +494,22 @@ class ComponentManagerView(LoginRequiredMixin, UpdateView):
return super().form_valid(form) return super().form_valid(form)
class ScoreListView(ListView): class ScoreListView(LoginRequiredMixin, ListView):
model = Score model = Score
class ScoreCreateView(SuccessMessageMixin, CreateView): class ScoreCreateView(LoginRequiredMixin, SuccessMessageMixin, CreateView):
model = Score model = Score
success_message = 'Score created.' success_message = 'Score created.'
template_name_suffix = '_create_form' template_name_suffix = '_create_form'
fields = '__all__' fields = '__all__'
class ScoreDetailView(DetailView): class ScoreDetailView(LoginRequiredMixin, DetailView):
model = Score model = Score
class ScoreUpdateView(SuccessMessageMixin, UpdateView): class ScoreUpdateView(LoginRequiredMixin, SuccessMessageMixin, UpdateView):
model = Score model = Score
success_message = 'Score saved.' success_message = 'Score saved.'
fields = [ fields = [
@ -384,7 +525,7 @@ class ScoreUpdateView(SuccessMessageMixin, UpdateView):
return context return context
class ScoreDeleteView(SuccessMessageMixin, DeleteView): class ScoreDeleteView(LoginRequiredMixin, SuccessMessageMixin, DeleteView):
model = Score model = Score
success_message = 'Score deleted.' success_message = 'Score deleted.'
@ -399,3 +540,148 @@ class ScoreDeleteView(SuccessMessageMixin, DeleteView):
SchoolYear, year=self.kwargs['year'] SchoolYear, year=self.kwargs['year']
) )
return context return context
class SchoolDayListView(LoginRequiredMixin, ListView):
model = SchoolDay
paginate_by = 7
def get_queryset(self):
queryset = SchoolDay.objects.filter(
school_year__year=self.kwargs['year']
)
return queryset
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['school_year'] = get_object_or_404(
SchoolYear, year=self.kwargs['year']
)
return context
class SchoolDayCreateView(LoginRequiredMixin, SuccessMessageMixin, CreateView):
model = SchoolDay
success_message = 'SchoolDay created.'
template_name_suffix = '_create_form'
form_class = SchoolDayForm
def get_initial(self):
today = timezone.localtime(timezone.now()).date()
initial = {
'date': today,
}
return initial
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['student_list'] = Student.objects.all()
context['school_year'] = get_object_or_404(
SchoolYear, year=self.kwargs['year']
)
return context
def form_valid(self, form):
form.instance.school_year = get_object_or_404(
SchoolYear, year=self.kwargs['year']
)
form.save()
for key, value in self.request.POST.items():
if 'student' in key:
s = key.split('_')[1]
AttendanceEntry.objects.create(
school_day=form.instance,
student=Student.objects.get(pk=s),
status=value,
)
return super().form_valid(form)
class SchoolDayDetailView(LoginRequiredMixin, DetailView):
model = SchoolDay
class SchoolDayUpdateView(LoginRequiredMixin, SuccessMessageMixin, UpdateView):
model = SchoolDay
success_message = 'SchoolDay saved.'
form_class = SchoolDayForm
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['student_list'] = Student.objects.all()
context['school_year'] = get_object_or_404(
SchoolYear, year=self.kwargs['year']
)
return context
def form_valid(self, form):
form.save()
for key, value in self.request.POST.items():
if 'student' in key:
s = key.split('_')[1]
AttendanceEntry.objects.filter(
school_day=self.object,
student=Student.objects.get(pk=s)
).update(status=value)
return super().form_valid(form)
class SchoolDayDeleteView(LoginRequiredMixin, SuccessMessageMixin, DeleteView):
model = SchoolDay
success_message = 'SchoolDay deleted.'
def get_success_url(self):
return reverse('core:schoolday-list', kwargs={
'year': self.kwargs['year']
})
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['school_year'] = get_object_or_404(
SchoolYear, year=self.kwargs['year']
)
return context
class AttendanceEntryListView(LoginRequiredMixin, ListView):
model = AttendanceEntry
class AttendanceEntryCreateView(LoginRequiredMixin, SuccessMessageMixin, CreateView):
model = AttendanceEntry
success_message = 'Entry created.'
template_name_suffix = '_create_form'
fields = '__all__'
class AttendanceEntryDetailView(LoginRequiredMixin, DetailView):
model = AttendanceEntry
pk_url_kwarg = 'entry_pk'
context_object_name = 'entry'
class AttendanceEntryUpdateView(LoginRequiredMixin, SuccessMessageMixin, UpdateView):
model = AttendanceEntry
pk_url_kwarg = 'entry_pk'
context_object_name = 'entry'
success_message = 'Entry saved.'
form_class = AttendanceEntryForm
def get_success_url(self):
return reverse('core:schoolday-detail', kwargs={
'year': self.kwargs['year'],
'pk': self.kwargs['pk']
})
class AttendanceEntryDeleteView(LoginRequiredMixin, SuccessMessageMixin, DeleteView):
model = AttendanceEntry
pk_url_kwarg = 'entry_pk'
context_object_name = 'entry'
success_message = 'Entry deleted.'
def get_success_url(self):
return reverse('core:schoolday-detail', kwargs={
'year': self.kwargs['year'],
'pk': self.kwargs['pk']
})

View File

@ -4,7 +4,7 @@
<article class="panel"> <article class="panel">
<header class="generic__header"> <header class="generic__header">
<h1>{{component.name}}</h1> <h1>{{component.name}}</h1>
<a href="{% url 'component-update' component.subject.pk component.pk %}" class="action-button">Update Component</a> <a href="{% url 'component-update' component.subject.pk component.pk %}" class="action-button">Edit</a>
</header> </header>
{% if component.finished_grading %} {% if component.finished_grading %}
<section> <section>
@ -74,4 +74,4 @@
{% endif %} {% endif %}
</section> </section>
</article> </article>
{% endblock %} {% endblock %}

View File

@ -3,8 +3,8 @@
{% block content %} {% block content %}
<article class="panel"> <article class="panel">
<div class="generic__header"> <div class="generic__header">
<h1>Update Component</h1> <h1>Edit Component</h1>
<a class="action-button action-delete" href="{% url 'component-delete' component.subject.pk component.pk %}">Delete Component</a> <a class="action-button action-delete" href="{% url 'component-delete' component.subject.pk component.pk %}">Delete</a>
</div> </div>
<section> <section>
<form action="{% url 'component-update' component.subject.pk component.pk %}" method="POST"> <form action="{% url 'component-update' component.subject.pk component.pk %}" method="POST">
@ -16,4 +16,4 @@
</form> </form>
</section> </section>
</article> </article>
{% endblock %} {% endblock %}

View File

@ -1,4 +1,5 @@
import zoneinfo import zoneinfo
from urllib import parse
from django.utils import timezone from django.utils import timezone

View File

@ -106,6 +106,7 @@ figure {
========================================================================== */ ========================================================================== */
ul, ol, dl { ul, ol, dl {
margin-bottom: 1rem; margin-bottom: 1rem;
line-height: 1.3;
} }
dl dt { dl dt {
font-weight: bold; font-weight: bold;
@ -125,6 +126,7 @@ table {
border-collapse: collapse; border-collapse: collapse;
width: 100%; width: 100%;
text-align: left; text-align: left;
margin-bottom: 1rem;
border-bottom: var(--table-border); border-bottom: var(--table-border);
} }
thead { thead {
@ -221,8 +223,13 @@ input[type=submit],
background-color: var(--color-danger); background-color: var(--color-danger);
} }
form progress { form input[type=radio],
display: none; form input[type=checkbox] {
width: 2rem;
height: 2rem;
cursor: pointer;
vertical-align: middle;
margin: 0.25rem;
} }

View File

@ -25,17 +25,17 @@
{% if user.is_authenticated %} {% if user.is_authenticated %}
<form class="nav__search" action="{% url 'search-results' %}" method="GET"> <form class="nav__search" action="{% url 'search-results' %}" method="GET">
<input name="q" type="search" placeholder="Search&hellip;" {% if query %} <input name="q" type="search" placeholder="Search&hellip;" {% if query %}
value="{{query}}" value="{{query}}"
{% endif %}> {% endif %}>
</form> </form>
<menu> <menu>
<li><a href="{% url 'core:schoolyear-list' %}">Years</a></li> <li><a href="{% url 'core:today' %}">Today</a></li>
<li><a href="{% url 'account-detail' user.pk %}">Today</a></li>
<li><a href="{% url 'core:student-list' current_year.year %}">Students</a></li> <li><a href="{% url 'core:student-list' current_year.year %}">Students</a></li>
<li><a href="{% url 'day-list' %}">Attendance</a></li> <li><a href="{% url 'core:schoolday-list' current_year.year %}">Attendance</a></li>
<li><a href="{% url 'core:subject-list' current_year.year %}">Subjects</a></li> <li><a href="{% url 'core:subject-list' current_year.year %}">Subjects</a></li>
</menu> </menu>
<menu class="nav__account"> <menu class="nav__account">
<li><a href="{% url 'core:schoolyear-list' %}">Years</a></li>
<li><a href="{% url 'account-detail' user.pk %}">Profile</a></li> <li><a href="{% url 'account-detail' user.pk %}">Profile</a></li>
<li><a class="action-button" href="{% url 'logout' %}">Logout</a></li> <li><a class="action-button" href="{% url 'logout' %}">Logout</a></li>
</menu> </menu>