Merge branch 'release/2.0.0'
This commit is contained in:
commit
a1e7da1d99
@ -25,3 +25,9 @@ class User(AbstractUser):
|
|||||||
choices=TIMEZONE_CHOICES,
|
choices=TIMEZONE_CHOICES,
|
||||||
default=MOUNTAIN
|
default=MOUNTAIN
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
if self.first_name and self.last_name:
|
||||||
|
return f'{self.first_name} {self.last_name}'
|
||||||
|
else:
|
||||||
|
return self.username
|
||||||
|
|||||||
@ -1,72 +1,23 @@
|
|||||||
{% extends 'base.html' %}
|
{% extends 'base.html' %}
|
||||||
{% load static %}
|
|
||||||
|
{% block head_title %}Profile |{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<article class="panel">
|
<article class="detail">
|
||||||
<header>
|
<header class="detail__header">
|
||||||
<h1 class="greeting"><em>Welcome {{user.first_name}} {{user.last_name }}</em>
|
<div>
|
||||||
<br>
|
<h1>{{ user }}</h1>
|
||||||
Here's what's going on today
|
<p><small>Joined: <time datetime="{{ user.date_joined|date:'Y-m-d' }}">{{ user.date_joined|date:'M d Y' }}</time></p>
|
||||||
</h1>
|
</div>
|
||||||
|
<a href="{% url 'account-update' user.pk %}" class="action-button">Edit</a>
|
||||||
</header>
|
</header>
|
||||||
<section>
|
<section class="detail__info">
|
||||||
<h3 class="domain__heading">Birthdays</h3>
|
<dl class="detail__datalist">
|
||||||
<ul>
|
<dt>Username</dt>
|
||||||
{% for student in birthdays %}
|
<dd>{{ user.username }}</dd>
|
||||||
<li><strong><a href="{% url 'student-detail' student.pk %}">{{student}}</a></strong> is turning {{student.age|add:1}} on {{student.dob|date:"M j"}}</li>
|
<dt>Email address</dt>
|
||||||
{% empty %}
|
<dd>{{ user.email }}</dd>
|
||||||
<p>No Birthdays this next week.</p>
|
</dl>
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<h3 class="domain__heading">Today's Assignments</h3>
|
|
||||||
<ul>
|
|
||||||
{% for component in components %}
|
|
||||||
<li>
|
|
||||||
{{component.subject}}, <a href="{% url '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 %}
|
|
||||||
<p><strong><a href="{% url 'day-update' day.pk %}">{{day.date}}</a></strong></p>
|
|
||||||
<table>
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<td>Student</td>
|
|
||||||
<td colspan="2">Status</td>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{% for entry in day.entry_set.all %}
|
|
||||||
<tr>
|
|
||||||
<td>{{entry.student}}</td>
|
|
||||||
<td>{{entry.get_status_display}}</td>
|
|
||||||
<td><a href="{% url 'entry-update' entry.pk %}">Update</a></td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
{% empty %}
|
|
||||||
<p class="greeting">No attendance taken yet: <a href="{% url '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 'component-detail' component.subject.pk component.pk %}">{{component}}</a>
|
|
||||||
</li>
|
|
||||||
{% empty %}
|
|
||||||
<p>Everything is graded to far.</p>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
</section>
|
</section>
|
||||||
</article>
|
</article>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@ -1,23 +0,0 @@
|
|||||||
{% extends 'base.html' %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<section class="panel">
|
|
||||||
<h1>Users</h1>
|
|
||||||
<table>
|
|
||||||
<thead>
|
|
||||||
<th>Username</th>
|
|
||||||
<th>Name</th>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{% for user in user_list %}
|
|
||||||
<tr>
|
|
||||||
<td>{{ user.username }}</td>
|
|
||||||
<td><a href="{% url 'account-detail' user.id %}">{{user.first_name}} {{user.last_name}}</a></td>
|
|
||||||
</tr>
|
|
||||||
{% empty %}
|
|
||||||
<tr><td>No users yet.</td></tr>
|
|
||||||
{% endfor %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</section>
|
|
||||||
{% endblock %}
|
|
||||||
@ -2,10 +2,21 @@ from django.urls import path, include
|
|||||||
from . import views
|
from . import views
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('', views.AccountListView.as_view(), name='account-list'),
|
|
||||||
path('<int:pk>/', include([
|
path('<int:pk>/', include([
|
||||||
path('', views.AccountDetailView.as_view(), name='account-detail'),
|
path(
|
||||||
path('update/', views.AccountUpdateView.as_view(), name='account-update'),
|
'',
|
||||||
path('delete/', views.AccountDeleteView.as_view(), name='account-delete'),
|
views.AccountDetailView.as_view(),
|
||||||
|
name='account-detail'
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
'update/',
|
||||||
|
views.AccountUpdateView.as_view(),
|
||||||
|
name='account-update'
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
'delete/',
|
||||||
|
views.AccountDeleteView.as_view(),
|
||||||
|
name='account-delete'
|
||||||
|
),
|
||||||
])),
|
])),
|
||||||
]
|
]
|
||||||
|
|||||||
@ -12,48 +12,14 @@ from django.contrib.auth.decorators import login_required
|
|||||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
from django.contrib.auth.forms import PasswordChangeForm
|
from django.contrib.auth.forms import PasswordChangeForm
|
||||||
|
|
||||||
from students.models import Student
|
|
||||||
from gradebook.models import Component
|
|
||||||
from attendance.models import Day, Entry
|
|
||||||
|
|
||||||
from .models import User
|
from .models import User
|
||||||
from .forms import AccountUpdateForm
|
from .forms import AccountUpdateForm
|
||||||
|
|
||||||
|
|
||||||
class AccountListView(LoginRequiredMixin, ListView):
|
|
||||||
model = User
|
|
||||||
template_name = 'accounts/account_list.html'
|
|
||||||
|
|
||||||
|
|
||||||
class AccountDetailView(LoginRequiredMixin, DetailView):
|
class AccountDetailView(LoginRequiredMixin, DetailView):
|
||||||
model = User
|
model = User
|
||||||
template_name = 'accounts/account_detail.html'
|
template_name = 'accounts/account_detail.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'] = Day.objects.filter(
|
|
||||||
date=today
|
|
||||||
).prefetch_related('entry_set', 'entry_set__student')
|
|
||||||
|
|
||||||
context['ungraded_components'] = Component.objects.filter(
|
|
||||||
due_date__lte=today,
|
|
||||||
finished_grading=False
|
|
||||||
).select_related('subject')
|
|
||||||
|
|
||||||
return context
|
|
||||||
|
|
||||||
|
|
||||||
class AccountUpdateView(LoginRequiredMixin, UpdateView):
|
class AccountUpdateView(LoginRequiredMixin, UpdateView):
|
||||||
model = User
|
model = User
|
||||||
|
|||||||
@ -1,6 +0,0 @@
|
|||||||
from django.contrib import admin
|
|
||||||
|
|
||||||
from .models import Day, Entry
|
|
||||||
|
|
||||||
admin.site.register(Day)
|
|
||||||
admin.site.register(Entry)
|
|
||||||
@ -1,6 +0,0 @@
|
|||||||
from django.apps import AppConfig
|
|
||||||
|
|
||||||
|
|
||||||
class AttendanceConfig(AppConfig):
|
|
||||||
default_auto_field = 'django.db.models.BigAutoField'
|
|
||||||
name = 'attendance'
|
|
||||||
@ -1,24 +0,0 @@
|
|||||||
from django import forms
|
|
||||||
from django.utils import timezone
|
|
||||||
from .models import Day, Entry
|
|
||||||
|
|
||||||
from students.models import Student
|
|
||||||
|
|
||||||
|
|
||||||
class DayForm(forms.ModelForm):
|
|
||||||
class Meta:
|
|
||||||
model = Day
|
|
||||||
fields = ('date',)
|
|
||||||
widgets = {
|
|
||||||
'date': forms.DateInput(attrs = {
|
|
||||||
'type': 'date',
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
|
|
||||||
class EntryForm(forms.ModelForm):
|
|
||||||
class Meta:
|
|
||||||
model = Entry
|
|
||||||
fields = ('day', 'student', 'status')
|
|
||||||
widgets = {
|
|
||||||
'student': forms.HiddenInput()
|
|
||||||
}
|
|
||||||
@ -1,39 +0,0 @@
|
|||||||
# Generated by Django 3.2.7 on 2021-09-01 15:26
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
import django.db.models.deletion
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
initial = True
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('students', '0001_initial'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='Day',
|
|
||||||
fields=[
|
|
||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
('date', models.DateField()),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'ordering': ('-date',),
|
|
||||||
},
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='Entry',
|
|
||||||
fields=[
|
|
||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
('status', models.CharField(choices=[('P', 'Present'), ('T', 'Tardy'), ('A', 'Absent')], default='P', max_length=1)),
|
|
||||||
('day', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='attendance.day')),
|
|
||||||
('student', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='students.student')),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'verbose_name_plural': 'entries',
|
|
||||||
'ordering': ('student',),
|
|
||||||
},
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@ -1,33 +0,0 @@
|
|||||||
from django.db import models
|
|
||||||
from students.models import Student
|
|
||||||
|
|
||||||
class Day(models.Model):
|
|
||||||
class Meta:
|
|
||||||
ordering = ('-date',)
|
|
||||||
|
|
||||||
date = models.DateField()
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return f"{self.date}"
|
|
||||||
|
|
||||||
class Entry(models.Model):
|
|
||||||
class Meta:
|
|
||||||
verbose_name_plural = 'entries'
|
|
||||||
ordering = ('student',)
|
|
||||||
|
|
||||||
STATUS_CHOICES = [
|
|
||||||
('P', 'Present'),
|
|
||||||
('T', 'Tardy'),
|
|
||||||
('A', 'Absent'),
|
|
||||||
]
|
|
||||||
|
|
||||||
day = models.ForeignKey(Day, on_delete=models.CASCADE)
|
|
||||||
student = models.ForeignKey(Student, on_delete=models.CASCADE)
|
|
||||||
status = models.CharField(
|
|
||||||
max_length=1,
|
|
||||||
choices=STATUS_CHOICES,
|
|
||||||
default='P'
|
|
||||||
)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return f"{self.day} | {self.student} | {self.status}"
|
|
||||||
@ -1,13 +0,0 @@
|
|||||||
{% extends "base.html" %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<article class="panel">
|
|
||||||
<h1>Delete {{day}}</h1>
|
|
||||||
<form method="post" action="{% url 'day-delete' day.pk %}">
|
|
||||||
{% csrf_token %}
|
|
||||||
<p>
|
|
||||||
<input class="action-button action-delete" type="submit" value="Confirm Delete {{day}}"> or <a href="{% url 'day-detail' day.pk %}">cancel</a>
|
|
||||||
</p>
|
|
||||||
</form>
|
|
||||||
</article>
|
|
||||||
{% endblock %}
|
|
||||||
@ -1,34 +0,0 @@
|
|||||||
{% extends "base.html" %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<article class="panel">
|
|
||||||
<form action="{% url 'day-create' %}" method="POST">
|
|
||||||
{% csrf_token %}
|
|
||||||
<header>
|
|
||||||
<h1>Take Attendance</h1>
|
|
||||||
{{form.as_p}}
|
|
||||||
</header>
|
|
||||||
<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>{{student.full_name}}</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>
|
|
||||||
<input class="action-button" type="submit" value="Save attendance"> or <a href="{% url 'day-list' %}">cancel</a>
|
|
||||||
</form>
|
|
||||||
</article>
|
|
||||||
{% endblock %}
|
|
||||||
@ -1,34 +0,0 @@
|
|||||||
{% extends "base.html" %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<article class="panel">
|
|
||||||
<form action="{% url 'day-update' day.pk %}" method="POST">
|
|
||||||
{% csrf_token %}
|
|
||||||
<header>
|
|
||||||
<h1>Take Attendance</h1>
|
|
||||||
{{form.as_p}}
|
|
||||||
</header>
|
|
||||||
<table>
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<td>Student</td>
|
|
||||||
<td>Present</td>
|
|
||||||
<td>Tardy</td>
|
|
||||||
<td>Absent</td>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{% for entry in day.entry_set.all %}
|
|
||||||
<tr>
|
|
||||||
<td>{{entry.student.full_name}}</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>
|
|
||||||
<input class="action-button" type="submit" value="Save changes"> or <a href="{% url 'day-list' %}">cancel</a>
|
|
||||||
</form>
|
|
||||||
</article>
|
|
||||||
{% endblock %}
|
|
||||||
@ -1,51 +0,0 @@
|
|||||||
{% extends "base.html" %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<article class="panel">
|
|
||||||
<h1>Attendance</h1>
|
|
||||||
<p>
|
|
||||||
<a href="{% url 'day-create' %}" class="action-button">Take attendance</a>
|
|
||||||
</p>
|
|
||||||
<section>
|
|
||||||
{% for day in day_list %}
|
|
||||||
<h4><a href="{% url 'day-update' day.pk %}">{{day.date}}</a></h4>
|
|
||||||
<table>
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<td>Student</td>
|
|
||||||
<td colspan="2">Status</td>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{% for entry in day.entry_set.all %}
|
|
||||||
<tr>
|
|
||||||
<td>{{entry.student}}</td>
|
|
||||||
<td>{{entry.get_status_display}}</td>
|
|
||||||
<td><a href="{% url 'entry-update' entry.pk %}">Update</a></td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
{% empty %}
|
|
||||||
<p>No attendance taken yet.</p>
|
|
||||||
{% endfor %}
|
|
||||||
</section>
|
|
||||||
<section class="pagination">
|
|
||||||
<span class="step-links">
|
|
||||||
{% if page_obj.has_previous %}
|
|
||||||
<a class="minor-action-button" href="?page=1">« first</a>
|
|
||||||
<a class="minor-action-button" href="?page={{ page_obj.previous_page_number }}">‹ previous</a>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<span class="current">
|
|
||||||
Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}.
|
|
||||||
</span>
|
|
||||||
|
|
||||||
{% if page_obj.has_next %}
|
|
||||||
<a class="minor-action-button" href="?page={{ page_obj.next_page_number }}">next ›</a>
|
|
||||||
<a class="minor-action-button" href="?page={{ page_obj.paginator.num_pages }}">last »</a>
|
|
||||||
{% endif %}
|
|
||||||
</span>
|
|
||||||
</section>
|
|
||||||
</article>
|
|
||||||
{% endblock %}
|
|
||||||
@ -1,13 +0,0 @@
|
|||||||
{% extends "base.html" %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<article class="panel">
|
|
||||||
<h1>Delete {{entry}}</h1>
|
|
||||||
<form method="post" action="{% url 'entry-delete' entry.pk %}">
|
|
||||||
{% csrf_token %}
|
|
||||||
<p>
|
|
||||||
<input class="action-button action-delete" type="submit" value="Confirm Delete {{entry}}"> or <a href="{% url 'day-detail' entry.day.pk %}">cancel</a>
|
|
||||||
</p>
|
|
||||||
</form>
|
|
||||||
</article>
|
|
||||||
{% endblock %}
|
|
||||||
@ -1,20 +0,0 @@
|
|||||||
{% extends "base.html" %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<article class="panel">
|
|
||||||
<div class="generic__header">
|
|
||||||
<h1>Update Entry</h1>
|
|
||||||
<a class="action-button action-delete" href="{% url 'entry-delete' entry.pk %}">Delete {{entry}}</a>
|
|
||||||
</div>
|
|
||||||
<p>For <strong>{{student}}</strong></p>
|
|
||||||
<section>
|
|
||||||
<form action="{% url 'entry-update' entry.pk %}" method="POST">
|
|
||||||
{% csrf_token %}
|
|
||||||
{{form.as_p}}
|
|
||||||
<p>
|
|
||||||
<input class="action-button" type="submit" value="Save changes"> or <a href="{% url 'student-detail' entry.student.pk %}">cancel</a>
|
|
||||||
</p>
|
|
||||||
</form>
|
|
||||||
</section>
|
|
||||||
</article>
|
|
||||||
{% endblock %}
|
|
||||||
@ -1,3 +0,0 @@
|
|||||||
from django.test import TestCase
|
|
||||||
|
|
||||||
# Create your tests here.
|
|
||||||
@ -1,20 +0,0 @@
|
|||||||
from django.urls import path, include
|
|
||||||
from . import views
|
|
||||||
|
|
||||||
urlpatterns = [
|
|
||||||
path('days/', views.DayListView.as_view(), name='day-list'),
|
|
||||||
path('days/new/', views.DayCreateView.as_view(), name='day-create'),
|
|
||||||
path('days/<int:pk>/', include([
|
|
||||||
path('', views.DayDetailView.as_view(), name='day-detail'),
|
|
||||||
path('update/', views.DayUpdateView.as_view(), name='day-update'),
|
|
||||||
path('delete/', views.DayDeleteView.as_view(), name='day-delete'),
|
|
||||||
])),
|
|
||||||
|
|
||||||
path('entries/', views.EntryListView.as_view(), name='entry-list'),
|
|
||||||
path('entries/new/', views.EntryCreateView.as_view(), name='entry-create'),
|
|
||||||
path('entries/<int:pk>/', include([
|
|
||||||
path('', views.EntryDetailView.as_view(), name='entry-detail'),
|
|
||||||
path('update/', views.EntryUpdateView.as_view(), name='entry-update'),
|
|
||||||
path('delete/', views.EntryDeleteView.as_view(), name='entry-delete'),
|
|
||||||
])),
|
|
||||||
]
|
|
||||||
@ -1,98 +0,0 @@
|
|||||||
from django.shortcuts import render
|
|
||||||
from django.http import HttpResponseRedirect
|
|
||||||
from django.urls import reverse_lazy, reverse
|
|
||||||
from django.views.generic.base import TemplateView
|
|
||||||
from django.views.generic.edit import FormView, CreateView, UpdateView, DeleteView
|
|
||||||
from django.views.generic.detail import DetailView
|
|
||||||
from django.views.generic.list import ListView
|
|
||||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
|
||||||
from django.utils import timezone
|
|
||||||
|
|
||||||
from django.db.models import Prefetch, Subquery, Count, Sum, F, Q, Value
|
|
||||||
from django.db.models.functions import Length, Upper
|
|
||||||
|
|
||||||
from students.models import Student
|
|
||||||
from .models import Day, Entry
|
|
||||||
from .forms import DayForm, EntryForm
|
|
||||||
|
|
||||||
|
|
||||||
# Days
|
|
||||||
class DayListView(LoginRequiredMixin, ListView):
|
|
||||||
model = Day
|
|
||||||
paginate_by = 7
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
object_list = Day.objects.all().prefetch_related('entry_set', 'entry_set__student')
|
|
||||||
return object_list
|
|
||||||
|
|
||||||
class DayCreateView(LoginRequiredMixin, CreateView):
|
|
||||||
model = Day
|
|
||||||
template_name_suffix = '_create_form'
|
|
||||||
form_class = DayForm
|
|
||||||
success_url = reverse_lazy('profile-detail')
|
|
||||||
|
|
||||||
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()
|
|
||||||
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]
|
|
||||||
Entry.objects.create(
|
|
||||||
day=form.instance,
|
|
||||||
student=Student.objects.get(pk=s),
|
|
||||||
status=value,
|
|
||||||
)
|
|
||||||
return super().form_valid(form)
|
|
||||||
|
|
||||||
class DayDetailView(LoginRequiredMixin, DetailView):
|
|
||||||
model = Day
|
|
||||||
|
|
||||||
class DayUpdateView(LoginRequiredMixin, UpdateView):
|
|
||||||
model = Day
|
|
||||||
form_class = DayForm
|
|
||||||
success_url = reverse_lazy('day-list')
|
|
||||||
|
|
||||||
def form_valid(self, form):
|
|
||||||
form.save()
|
|
||||||
for key, value in self.request.POST.items():
|
|
||||||
if 'student' in key:
|
|
||||||
s = key.split('_')[1]
|
|
||||||
Entry.objects.filter(day=self.object, student=s).update(status=value)
|
|
||||||
return super().form_valid(form)
|
|
||||||
|
|
||||||
class DayDeleteView(LoginRequiredMixin, DeleteView):
|
|
||||||
model = Day
|
|
||||||
success_url = reverse_lazy('day-list')
|
|
||||||
|
|
||||||
|
|
||||||
# Entries
|
|
||||||
class EntryListView(LoginRequiredMixin, ListView):
|
|
||||||
model = Entry
|
|
||||||
|
|
||||||
class EntryCreateView(LoginRequiredMixin, CreateView):
|
|
||||||
model = Entry
|
|
||||||
template_name_suffix = '_create_form'
|
|
||||||
fields = ('__all__')
|
|
||||||
|
|
||||||
class EntryDetailView(LoginRequiredMixin, DetailView):
|
|
||||||
model = Entry
|
|
||||||
|
|
||||||
class EntryUpdateView(LoginRequiredMixin, UpdateView):
|
|
||||||
model = Entry
|
|
||||||
form_class = EntryForm
|
|
||||||
success_url = reverse_lazy('day-list')
|
|
||||||
|
|
||||||
class EntryDeleteView(LoginRequiredMixin, DeleteView):
|
|
||||||
model = Entry
|
|
||||||
success_url = reverse_lazy('day-list')
|
|
||||||
@ -1,3 +1,23 @@
|
|||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
|
|
||||||
# Register your models here.
|
from .models import (
|
||||||
|
SchoolYear,
|
||||||
|
StudentTag,
|
||||||
|
Student,
|
||||||
|
Subject,
|
||||||
|
Tag,
|
||||||
|
Component,
|
||||||
|
Score,
|
||||||
|
SchoolDay,
|
||||||
|
AttendanceEntry,
|
||||||
|
)
|
||||||
|
|
||||||
|
admin.site.register(SchoolYear)
|
||||||
|
admin.site.register(StudentTag)
|
||||||
|
admin.site.register(Student)
|
||||||
|
admin.site.register(Subject)
|
||||||
|
admin.site.register(Tag)
|
||||||
|
admin.site.register(Component)
|
||||||
|
admin.site.register(Score)
|
||||||
|
admin.site.register(SchoolDay)
|
||||||
|
admin.site.register(AttendanceEntry)
|
||||||
|
|||||||
8
src/core/context_processors.py
Normal file
8
src/core/context_processors.py
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
from .models import SchoolYear
|
||||||
|
from django.shortcuts import get_object_or_404
|
||||||
|
|
||||||
|
|
||||||
|
def current_year(request):
|
||||||
|
return {
|
||||||
|
'current_year': SchoolYear.objects.latest('year')
|
||||||
|
}
|
||||||
@ -16,22 +16,56 @@ 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',
|
||||||
)
|
'allergies',
|
||||||
|
'tags'
|
||||||
|
]
|
||||||
labels = {
|
labels = {
|
||||||
'student_id': 'Student ID',
|
'student_id': 'Student ID',
|
||||||
'dob': 'DOB',
|
'dob': 'DOB'
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class ComponentCreateForm(forms.ModelForm):
|
||||||
|
class Meta:
|
||||||
|
model = Component
|
||||||
|
fields = [
|
||||||
|
'name',
|
||||||
|
'category',
|
||||||
|
'due_date',
|
||||||
|
'grade_total'
|
||||||
|
]
|
||||||
|
widgets = {
|
||||||
|
'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()
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
# Generated by Django 4.0.5 on 2022-06-29 18:50
|
# Generated by Django 4.0.5 on 2022-07-28 20:46
|
||||||
|
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
@ -9,16 +9,41 @@ class Migration(migrations.Migration):
|
|||||||
initial = True
|
initial = True
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('contenttypes', '0002_remove_content_type_name'),
|
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Component',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('name', models.CharField(max_length=50)),
|
||||||
|
('category', models.CharField(choices=[('QUIZ', 'Quiz'), ('ASSIGNMENT', 'Assignment'), ('TEST', 'Test')], default='ASSIGNMENT', max_length=255)),
|
||||||
|
('due_date', models.DateField()),
|
||||||
|
('grade_total', models.PositiveIntegerField()),
|
||||||
|
('finished_grading', models.BooleanField(default=False)),
|
||||||
|
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||||
|
('updated_at', models.DateTimeField(auto_now=True)),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'ordering': ['due_date'],
|
||||||
|
},
|
||||||
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='SchoolYear',
|
name='SchoolYear',
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
('start_date', models.DateField()),
|
('year', models.PositiveIntegerField(unique=True)),
|
||||||
('end_date', models.DateField()),
|
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||||
|
('updated_at', models.DateTimeField(auto_now=True)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='StudentTag',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('name', models.CharField(max_length=255)),
|
||||||
|
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||||
|
('updated_at', models.DateTimeField(auto_now=True)),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
@ -26,6 +51,8 @@ class Migration(migrations.Migration):
|
|||||||
fields=[
|
fields=[
|
||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
('name', models.CharField(max_length=50)),
|
('name', models.CharField(max_length=50)),
|
||||||
|
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||||
|
('updated_at', models.DateTimeField(auto_now=True)),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'ordering': ['name'],
|
'ordering': ['name'],
|
||||||
@ -37,21 +64,14 @@ class Migration(migrations.Migration):
|
|||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
('name', models.CharField(max_length=250)),
|
('name', models.CharField(max_length=250)),
|
||||||
('description', models.CharField(blank=True, max_length=250)),
|
('description', models.CharField(blank=True, max_length=250)),
|
||||||
|
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||||
|
('updated_at', models.DateTimeField(auto_now=True)),
|
||||||
('school_year', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='core.schoolyear')),
|
('school_year', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='core.schoolyear')),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'ordering': ['name'],
|
'ordering': ['name'],
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
|
||||||
name='StudentTag',
|
|
||||||
fields=[
|
|
||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
('tag', models.SlugField()),
|
|
||||||
('object_id', models.PositiveIntegerField()),
|
|
||||||
('content_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='contenttypes.contenttype')),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='Student',
|
name='Student',
|
||||||
fields=[
|
fields=[
|
||||||
@ -61,44 +81,58 @@ class Migration(migrations.Migration):
|
|||||||
('last_name', models.CharField(max_length=50)),
|
('last_name', models.CharField(max_length=50)),
|
||||||
('address', models.TextField(blank=True)),
|
('address', models.TextField(blank=True)),
|
||||||
('dob', models.DateField()),
|
('dob', models.DateField()),
|
||||||
|
('allergies', models.CharField(blank=True, max_length=255)),
|
||||||
|
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||||
|
('updated_at', models.DateTimeField(auto_now=True)),
|
||||||
('school_year', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='core.schoolyear')),
|
('school_year', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='core.schoolyear')),
|
||||||
|
('tags', models.ManyToManyField(blank=True, to='core.studenttag')),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'ordering': ['student_id', 'first_name'],
|
'ordering': ['student_id', 'first_name'],
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Score',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('value', models.PositiveIntegerField()),
|
||||||
|
('component', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='core.component')),
|
||||||
|
('student', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='core.student')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'ordering': ['student'],
|
||||||
|
},
|
||||||
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='SchoolDay',
|
name='SchoolDay',
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
('date', models.DateField()),
|
('date', models.DateField()),
|
||||||
|
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||||
|
('updated_at', models.DateTimeField(auto_now=True)),
|
||||||
('school_year', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='core.schoolyear')),
|
('school_year', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='core.schoolyear')),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'ordering': ['-date'],
|
'ordering': ['-date'],
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
migrations.AddField(
|
||||||
name='Component',
|
model_name='component',
|
||||||
fields=[
|
name='subject',
|
||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='core.subject'),
|
||||||
('name', models.CharField(max_length=50)),
|
),
|
||||||
('category', models.CharField(choices=[('QUIZ', 'Quiz'), ('ASSIGNMENT', 'Assignment'), ('TEST', 'Test')], default='ASSIGNMENT', max_length=255)),
|
migrations.AddField(
|
||||||
('due_date', models.DateField()),
|
model_name='component',
|
||||||
('grade_total', models.PositiveIntegerField()),
|
name='tags',
|
||||||
('finished_grading', models.BooleanField(default=False)),
|
field=models.ManyToManyField(blank=True, to='core.tag'),
|
||||||
('subject', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='core.subject')),
|
|
||||||
('tags', models.ManyToManyField(blank=True, to='core.tag')),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'ordering': ['due_date'],
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='AttendanceEntry',
|
name='AttendanceEntry',
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
('status', models.CharField(choices=[('P', 'Present'), ('T', 'Tardy'), ('A', 'Absent')], default='P', max_length=1)),
|
('status', models.CharField(choices=[('P', 'Present'), ('T', 'Tardy'), ('A', 'Absent')], default='P', max_length=1)),
|
||||||
|
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||||
|
('updated_at', models.DateTimeField(auto_now=True)),
|
||||||
('school_day', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='core.schoolday')),
|
('school_day', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='core.schoolday')),
|
||||||
('student', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='core.student')),
|
('student', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='core.student')),
|
||||||
],
|
],
|
||||||
@ -107,8 +141,4 @@ class Migration(migrations.Migration):
|
|||||||
'ordering': ['student'],
|
'ordering': ['student'],
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
migrations.AddIndex(
|
|
||||||
model_name='studenttag',
|
|
||||||
index=models.Index(fields=['content_type', 'object_id'], name='core_studen_content_a7305d_idx'),
|
|
||||||
),
|
|
||||||
]
|
]
|
||||||
|
|||||||
@ -1,18 +0,0 @@
|
|||||||
# Generated by Django 4.0.5 on 2022-06-29 20:35
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('core', '0001_initial'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='schoolyear',
|
|
||||||
name='start_date',
|
|
||||||
field=models.DateField(unique_for_year=True),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@ -1,27 +0,0 @@
|
|||||||
# Generated by Django 4.0.5 on 2022-06-29 20:47
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('core', '0002_alter_schoolyear_start_date'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.RemoveField(
|
|
||||||
model_name='schoolyear',
|
|
||||||
name='end_date',
|
|
||||||
),
|
|
||||||
migrations.RemoveField(
|
|
||||||
model_name='schoolyear',
|
|
||||||
name='start_date',
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='schoolyear',
|
|
||||||
name='year',
|
|
||||||
field=models.PositiveIntegerField(default=2021),
|
|
||||||
preserve_default=False,
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@ -1,18 +0,0 @@
|
|||||||
# Generated by Django 4.0.5 on 2022-06-29 20:48
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('core', '0003_remove_schoolyear_end_date_and_more'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='schoolyear',
|
|
||||||
name='year',
|
|
||||||
field=models.PositiveIntegerField(unique=True),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@ -1,104 +0,0 @@
|
|||||||
# Generated by Django 4.0.5 on 2022-06-29 21:27
|
|
||||||
|
|
||||||
import datetime
|
|
||||||
from django.db import migrations, models
|
|
||||||
from django.utils.timezone import utc
|
|
||||||
import django.utils.timezone
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('core', '0004_alter_schoolyear_year'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='attendanceentry',
|
|
||||||
name='created_at',
|
|
||||||
field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now),
|
|
||||||
preserve_default=False,
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='attendanceentry',
|
|
||||||
name='updated_at',
|
|
||||||
field=models.DateTimeField(auto_now=True),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='component',
|
|
||||||
name='created_at',
|
|
||||||
field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now),
|
|
||||||
preserve_default=False,
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='component',
|
|
||||||
name='updated_at',
|
|
||||||
field=models.DateTimeField(auto_now=True),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='schoolday',
|
|
||||||
name='created_at',
|
|
||||||
field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now),
|
|
||||||
preserve_default=False,
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='schoolday',
|
|
||||||
name='updated_at',
|
|
||||||
field=models.DateTimeField(auto_now=True),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='schoolyear',
|
|
||||||
name='created_at',
|
|
||||||
field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now),
|
|
||||||
preserve_default=False,
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='schoolyear',
|
|
||||||
name='updated_at',
|
|
||||||
field=models.DateTimeField(auto_now=True),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='student',
|
|
||||||
name='created_at',
|
|
||||||
field=models.DateTimeField(auto_now_add=True, default=datetime.datetime(2022, 6, 29, 21, 26, 47, 547231, tzinfo=utc)),
|
|
||||||
preserve_default=False,
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='student',
|
|
||||||
name='updated_at',
|
|
||||||
field=models.DateTimeField(auto_now=True),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='studenttag',
|
|
||||||
name='created_at',
|
|
||||||
field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now),
|
|
||||||
preserve_default=False,
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='studenttag',
|
|
||||||
name='updated_at',
|
|
||||||
field=models.DateTimeField(auto_now=True),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='subject',
|
|
||||||
name='created_at',
|
|
||||||
field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now),
|
|
||||||
preserve_default=False,
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='subject',
|
|
||||||
name='updated_at',
|
|
||||||
field=models.DateTimeField(auto_now=True),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='tag',
|
|
||||||
name='created_at',
|
|
||||||
field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now),
|
|
||||||
preserve_default=False,
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='tag',
|
|
||||||
name='updated_at',
|
|
||||||
field=models.DateTimeField(auto_now=True),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@ -1,26 +0,0 @@
|
|||||||
# Generated by Django 4.0.5 on 2022-06-30 20:03
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
import django.db.models.deletion
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('core', '0005_attendanceentry_created_at_and_more'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='Score',
|
|
||||||
fields=[
|
|
||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
('value', models.PositiveIntegerField()),
|
|
||||||
('component', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='core.component')),
|
|
||||||
('student', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='core.student')),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'ordering': ['student'],
|
|
||||||
},
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@ -5,6 +5,9 @@ from django.contrib.contenttypes.models import ContentType
|
|||||||
from django.contrib.contenttypes.fields import (
|
from django.contrib.contenttypes.fields import (
|
||||||
GenericForeignKey, GenericRelation
|
GenericForeignKey, GenericRelation
|
||||||
)
|
)
|
||||||
|
from django.db.models import (
|
||||||
|
Exists, OuterRef, Prefetch, Subquery, Count, Sum, Avg, F, Q, Value
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class SchoolYear(models.Model):
|
class SchoolYear(models.Model):
|
||||||
@ -27,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):
|
||||||
@ -66,8 +61,9 @@ class Student(models.Model):
|
|||||||
last_name = models.CharField(max_length=50)
|
last_name = models.CharField(max_length=50)
|
||||||
address = models.TextField(blank=True)
|
address = models.TextField(blank=True)
|
||||||
dob = models.DateField()
|
dob = models.DateField()
|
||||||
|
allergies = models.CharField(max_length=255, blank=True)
|
||||||
|
|
||||||
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)
|
||||||
@ -89,7 +85,7 @@ class Student(models.Model):
|
|||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return reverse('core:student-detail', kwargs={
|
return reverse('core:student-detail', kwargs={
|
||||||
'year': self.school_year.year,
|
'year': self.school_year.year,
|
||||||
'student_pk': self.pk
|
'pk': self.pk
|
||||||
})
|
})
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
@ -114,7 +110,10 @@ class Subject(models.Model):
|
|||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return reverse('subject-detail', kwargs={'pk': self.pk})
|
return reverse('core:subject-detail', kwargs={
|
||||||
|
'year': self.school_year.year,
|
||||||
|
'pk': self.pk
|
||||||
|
})
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ['name']
|
ordering = ['name']
|
||||||
@ -180,7 +179,11 @@ class Component(models.Model):
|
|||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return reverse('component-detail', kwargs={'pk': self.pk})
|
return reverse('core:component-detail', kwargs={
|
||||||
|
'year': self.school_year.year,
|
||||||
|
'pk': self.subject.pk,
|
||||||
|
'component_pk': self.pk
|
||||||
|
})
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ['due_date']
|
ordering = ['due_date']
|
||||||
@ -203,7 +206,11 @@ class Score(models.Model):
|
|||||||
return f'{self.student} scored: {self.value} / {self.component.grade_total}'
|
return f'{self.student} scored: {self.value} / {self.component.grade_total}'
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return reverse('score-detail', kwargs={'pk': self.pk})
|
return reverse('core:component-detail', kwargs={
|
||||||
|
'year': self.component.subject.school_year.year,
|
||||||
|
'pk': self.component.subject.pk,
|
||||||
|
'component_pk': self.component.pk
|
||||||
|
})
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ['student']
|
ordering = ['student']
|
||||||
@ -222,6 +229,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}'
|
||||||
|
|
||||||
@ -251,8 +264,15 @@ 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.school_day} | {self.student} | {self.status}"
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name_plural = 'entries'
|
verbose_name_plural = 'entries'
|
||||||
|
|||||||
31
src/core/templates/core/attendanceentry_confirm_delete.html
Normal file
31
src/core/templates/core/attendanceentry_confirm_delete.html
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
{% 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' 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">
|
||||||
|
<h1>Delete Attendanceentry</h1>
|
||||||
|
</header>
|
||||||
|
<form method="POST" action="{% url 'core:entry-delete' entry.school_day.school_year.year entry.school_day.pk entry.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:schoolday-detail' entry.school_day.school_year.year entry.school_day.pk %}">cancel</a>
|
||||||
|
</p>
|
||||||
|
</form>
|
||||||
|
</article>
|
||||||
|
{% endblock %}
|
||||||
12
src/core/templates/core/attendanceentry_create_form.html
Normal file
12
src/core/templates/core/attendanceentry_create_form.html
Normal 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 %}
|
||||||
33
src/core/templates/core/attendanceentry_detail.html
Normal file
33
src/core/templates/core/attendanceentry_detail.html
Normal 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 %}
|
||||||
33
src/core/templates/core/attendanceentry_form.html
Normal file
33
src/core/templates/core/attendanceentry_form.html
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
{% 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' 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 %}
|
||||||
16
src/core/templates/core/attendanceentry_list.html
Normal file
16
src/core/templates/core/attendanceentry_list.html
Normal 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 %}
|
||||||
36
src/core/templates/core/component_confirm_delete.html
Normal file
36
src/core/templates/core/component_confirm_delete.html
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
{% load helpers %}
|
||||||
|
|
||||||
|
{% block head_title %}{{ component.name }} | {% endblock head_title %}
|
||||||
|
|
||||||
|
{% block breadcrumbs %}
|
||||||
|
<div class="breadcrumbs">
|
||||||
|
<menu>
|
||||||
|
<li><strong><a href="{% url 'core:schoolyear-detail' component.subject.school_year.year %}">{{ component.subject.school_year.year }}</a></strong></li>
|
||||||
|
<span>›</span>
|
||||||
|
<li><a href="{% url 'core:subject-list' component.subject.school_year.year %}">Subjects</a></li>
|
||||||
|
<span>›</span>
|
||||||
|
<li><a href="{% url 'core:subject-detail' component.subject.school_year.year component.subject.pk %}">{{ component.subject.name }}</a></li>
|
||||||
|
<span>›</span>
|
||||||
|
<li><a href="{% url 'core:component-detail' component.subject.school_year.year component.subject.pk component.pk %}">{{ component.name }}</a></li>
|
||||||
|
</menu>
|
||||||
|
</div>
|
||||||
|
{% endblock breadcrumbs %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<article class="form">
|
||||||
|
<header class="form__header">
|
||||||
|
<h1>Delete Component</h1>
|
||||||
|
<p>
|
||||||
|
<a href="{% url 'core:component-delete' component.subject.school_year.year component.subject.pk component.pk %}" class="action-button action-delete">Delete</a>
|
||||||
|
</p>
|
||||||
|
</header>
|
||||||
|
<form method="POST" action="{% url 'core:component-delete' component.subject.school_year.year component.subject.pk component.pk %}">
|
||||||
|
{% csrf_token %}
|
||||||
|
{{ form.as_p }}
|
||||||
|
<p>
|
||||||
|
<input type="submit" value="Delete"> or <a href="{% url 'core:component-detail' component.subject.school_year.year component.subject.pk component.pk %}">cancel</a>
|
||||||
|
</p>
|
||||||
|
</form>
|
||||||
|
</article>
|
||||||
|
{% endblock %}
|
||||||
28
src/core/templates/core/component_create_form.html
Normal file
28
src/core/templates/core/component_create_form.html
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
|
{% block head_title %}New component | {% 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.name }}</a></li>
|
||||||
|
</menu>
|
||||||
|
</div>
|
||||||
|
{% endblock breadcrumbs %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<article class="form">
|
||||||
|
<h1>+ New Component</h1>
|
||||||
|
<form method="POST" action="{% url 'core:component-create' school_year.year subject.pk %}">
|
||||||
|
{% csrf_token %}
|
||||||
|
{{ form.as_p }}
|
||||||
|
<p>
|
||||||
|
<input type="submit" value="Create"> or <a href="{% url 'core:subject-detail' school_year.year subject.pk %}">cancel</a>
|
||||||
|
</p>
|
||||||
|
</form>
|
||||||
|
</article>
|
||||||
|
{% endblock %}
|
||||||
88
src/core/templates/core/component_detail.html
Normal file
88
src/core/templates/core/component_detail.html
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
{% load helpers %}
|
||||||
|
|
||||||
|
{% block head_title %}{{ component.name }} | {% endblock head_title %}
|
||||||
|
|
||||||
|
{% block breadcrumbs %}
|
||||||
|
<div class="breadcrumbs">
|
||||||
|
<menu>
|
||||||
|
<li><strong><a href="{% url 'core:schoolyear-detail' component.subject.school_year.year %}">{{ component.subject.school_year.year }}</a></strong></li>
|
||||||
|
<span>›</span>
|
||||||
|
<li><a href="{% url 'core:subject-list' component.subject.school_year.year %}">Subjects</a></li>
|
||||||
|
<span>›</span>
|
||||||
|
<li><a href="{% url 'core:subject-detail' component.subject.school_year.year component.subject.pk %}">{{ component.subject.name }}</a></li>
|
||||||
|
</menu>
|
||||||
|
</div>
|
||||||
|
{% endblock breadcrumbs %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<article class="detail">
|
||||||
|
<header class="detail__header">
|
||||||
|
<div>
|
||||||
|
<h1>{{component.name}}   -   {{ component.get_category_display }}{% if component.finished_grading %}   —   <span class="tag tag__success">✓ Graded</span>{% endif %}</h1>
|
||||||
|
<p><small>Added: <time datetime="{{ component.created_at|date:'Y-m-d' }}">{{ component.created_at|date:'M d Y' }}</time><br>
|
||||||
|
Last updated: <time datetime="{{ component.updated_at|date:'Y-m-d' }}">{{ component.updated_at|date:'M d Y' }}</time></small></p>
|
||||||
|
</div>
|
||||||
|
<a href="{% url 'core:component-update' component.subject.school_year.year component.subject.pk component.pk %}" class="action-button">Edit</a>
|
||||||
|
</header>
|
||||||
|
{% if component.tags.count > 0 %}
|
||||||
|
<section>
|
||||||
|
<span>
|
||||||
|
{% for tag in component.tags.all %}
|
||||||
|
<a class="tag tag__info" href="{% url 'core:tag-detail' component.subject.school_year.year tag.pk %}">{{tag.name}}</a>
|
||||||
|
{% endfor %}
|
||||||
|
</span>
|
||||||
|
</section>
|
||||||
|
{% endif %}
|
||||||
|
<section class="detail__info">
|
||||||
|
<dl class="detail__datalist">
|
||||||
|
<dt>Due Date</dt>
|
||||||
|
<dd>{{component.due_date}}</dd>
|
||||||
|
<dt>Category</dt>
|
||||||
|
<dd>{{component.get_category_display}}</dd>
|
||||||
|
<dt>Grade Total</dt>
|
||||||
|
<dd>{{component.grade_total}}</dd>
|
||||||
|
</dl>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<header class="list__header">
|
||||||
|
<div class="list__title">
|
||||||
|
<h2>Scores</h2>
|
||||||
|
<a class="action-button" href="{% url 'core:component-manager' component.subject.school_year.year component.subject.pk component.pk %}">Enter Scores →</a>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Student</th>
|
||||||
|
<th colspan="2">Score</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for score in component.score_set.all %}
|
||||||
|
<tr>
|
||||||
|
<td><a href="{% url 'core:student-detail' component.subject.school_year.year score.student.pk %}">{{score.student.student_id}} — {{score.student}}</a></td>
|
||||||
|
<td>{{score.value}} / {{component.grade_total}}</td>
|
||||||
|
<td><a href="{% url 'core:score-update' component.subject.school_year.year score.pk %}">Edit</a></td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
<tr>
|
||||||
|
<td><strong>Avg. Score</strong></td>
|
||||||
|
<td colspan="2"><strong>{{component.grade_avg_pre|floatformat:2}} / {{component.grade_total}}</strong></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</section>
|
||||||
|
{% if scoreless %}
|
||||||
|
<section>
|
||||||
|
|
||||||
|
<h3>Scoreless</h3>
|
||||||
|
<ul>
|
||||||
|
{% for student in scoreless %}
|
||||||
|
<li>{{student}}</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
{% endif %}
|
||||||
|
</article>
|
||||||
|
{% endblock %}
|
||||||
36
src/core/templates/core/component_form.html
Normal file
36
src/core/templates/core/component_form.html
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
{% load helpers %}
|
||||||
|
|
||||||
|
{% block head_title %}{{ component.name }} | {% endblock head_title %}
|
||||||
|
|
||||||
|
{% block breadcrumbs %}
|
||||||
|
<div class="breadcrumbs">
|
||||||
|
<menu>
|
||||||
|
<li><strong><a href="{% url 'core:schoolyear-detail' component.subject.school_year.year %}">{{ component.subject.school_year.year }}</a></strong></li>
|
||||||
|
<span>›</span>
|
||||||
|
<li><a href="{% url 'core:subject-list' component.subject.school_year.year %}">Subjects</a></li>
|
||||||
|
<span>›</span>
|
||||||
|
<li><a href="{% url 'core:subject-detail' component.subject.school_year.year component.subject.pk %}">{{ component.subject.name }}</a></li>
|
||||||
|
<span>›</span>
|
||||||
|
<li><a href="{% url 'core:component-detail' component.subject.school_year.year component.subject.pk component.pk %}">{{ component.name }}</a></li>
|
||||||
|
</menu>
|
||||||
|
</div>
|
||||||
|
{% endblock breadcrumbs %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<article class="form">
|
||||||
|
<header class="form__header">
|
||||||
|
<h1>Edit Component</h1>
|
||||||
|
<p>
|
||||||
|
<a href="{% url 'core:component-delete' component.subject.school_year.year component.subject.pk component.pk %}" class="action-button action-delete">Delete</a>
|
||||||
|
</p>
|
||||||
|
</header>
|
||||||
|
<form method="POST" action="{% url 'core:component-update' component.subject.school_year.year component.subject.pk component.pk %}">
|
||||||
|
{% csrf_token %}
|
||||||
|
{{ form.as_p }}
|
||||||
|
<p>
|
||||||
|
<input type="submit" value="Save changes"> or <a href="{% url 'core:component-detail' component.subject.school_year.year component.subject.pk component.pk %}">cancel</a>
|
||||||
|
</p>
|
||||||
|
</form>
|
||||||
|
</article>
|
||||||
|
{% endblock %}
|
||||||
16
src/core/templates/core/component_list.html
Normal file
16
src/core/templates/core/component_list.html
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<h1>Components</h1>
|
||||||
|
<table>
|
||||||
|
<tbody>
|
||||||
|
{% for component in component_list %}
|
||||||
|
<tr>
|
||||||
|
<dt>{{ component }}</dt>
|
||||||
|
</tr>
|
||||||
|
{% empty %}
|
||||||
|
<tr>No components yet.</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
{% endblock %}
|
||||||
56
src/core/templates/core/component_manager.html
Normal file
56
src/core/templates/core/component_manager.html
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
{% load helpers %}
|
||||||
|
|
||||||
|
{% block head_title %}Enter Scores {{ component.name }} | {% endblock head_title %}
|
||||||
|
|
||||||
|
{% block breadcrumbs %}
|
||||||
|
<div class="breadcrumbs">
|
||||||
|
<menu>
|
||||||
|
<li><strong><a href="{% url 'core:schoolyear-detail' component.subject.school_year.year %}">{{ component.subject.school_year.year }}</a></strong></li>
|
||||||
|
<span>›</span>
|
||||||
|
<li><a href="{% url 'core:subject-list' component.subject.school_year.year %}">Subjects</a></li>
|
||||||
|
<span>›</span>
|
||||||
|
<li><a href="{% url 'core:subject-detail' component.subject.school_year.year component.subject.pk %}">{{ component.subject.name }}</a></li>
|
||||||
|
<span>›</span>
|
||||||
|
<li><a href="{% url 'core:component-detail' component.subject.school_year.year component.subject.pk component.pk %}">{{ component.name }}</a></li>
|
||||||
|
</menu>
|
||||||
|
</div>
|
||||||
|
{% endblock breadcrumbs %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<article class="form">
|
||||||
|
<h1>{{component}}</h1>
|
||||||
|
<section>
|
||||||
|
<form action="{% url 'core:component-manager' component.subject.school_year.year component.subject.pk component.pk %}" method="POST">
|
||||||
|
{% csrf_token %}
|
||||||
|
<h3>Enter Scores</h3>
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Student</th>
|
||||||
|
<th>Score</th>
|
||||||
|
{% if formset.errors %}
|
||||||
|
<th>Errors</th>
|
||||||
|
{% endif %}
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for student in student_list %}
|
||||||
|
<tr>
|
||||||
|
<td>{{student.full_name}}</td>
|
||||||
|
<td>
|
||||||
|
<input type="number" name="student_{{student.pk}}" min="0" max="{{component.grade_total}}" value="{{student.cscore}}">
|
||||||
|
  /   {{component.grade_total}}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
{{form.as_p}}
|
||||||
|
<p>
|
||||||
|
<input class="action-button" type="submit" value="Save changes"> or <a href="{% url 'core:component-detail' component.subject.school_year.year component.subject.pk component.pk %}">cancel</a>
|
||||||
|
</p>
|
||||||
|
</form>
|
||||||
|
</section>
|
||||||
|
</article>
|
||||||
|
{% endblock %}
|
||||||
9
src/core/templates/core/home.html
Normal file
9
src/core/templates/core/home.html
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
|
{% block head_title %}Grades & Attendance Management Software |{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<article>
|
||||||
|
<h1>Grades and Attendance Management Software</h1>
|
||||||
|
</article>
|
||||||
|
{% endblock %}
|
||||||
29
src/core/templates/core/schoolday_confirm_delete.html
Normal file
29
src/core/templates/core/schoolday_confirm_delete.html
Normal 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 %}
|
||||||
46
src/core/templates/core/schoolday_create_form.html
Normal file
46
src/core/templates/core/schoolday_create_form.html
Normal 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.student_id }}   /   {{ 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 %}
|
||||||
46
src/core/templates/core/schoolday_detail.html
Normal file
46
src/core/templates/core/schoolday_detail.html
Normal 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 %}
|
||||||
53
src/core/templates/core/schoolday_form.html
Normal file
53
src/core/templates/core/schoolday_form.html
Normal 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.student_id }}   /   {{ 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 %}
|
||||||
54
src/core/templates/core/schoolday_list.html
Normal file
54
src/core/templates/core/schoolday_list.html
Normal 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 →</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 %}
|
||||||
@ -1,12 +1,14 @@
|
|||||||
{% extends 'base.html' %}
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h1>+ New Schoolyear</h1>
|
<article class="form">
|
||||||
<form method="POST" action="{% url 'core:schoolyear-create' %}">
|
<h1>+ New School year</h1>
|
||||||
{% csrf_token %}
|
<form method="POST" action="{% url 'core:schoolyear-create' %}">
|
||||||
{{ form.as_p }}
|
{% csrf_token %}
|
||||||
<p>
|
{{ form.as_p }}
|
||||||
<input type="submit" value="Create"> or <a href="{% url 'core:schoolyear-list' %}">cancel</a>
|
<p>
|
||||||
</p>
|
<input type="submit" value="Create"> or <a href="{% url 'core:schoolyear-list' %}">cancel</a>
|
||||||
</form>
|
</p>
|
||||||
|
</form>
|
||||||
|
</article>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@ -1,34 +1,31 @@
|
|||||||
{% 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 %}
|
|
||||||
<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>
|
||||||
{% endif %}
|
|
||||||
</header>
|
</header>
|
||||||
<div class="tools">
|
<section class="tools">
|
||||||
<a href="{% url 'core:student-list' schoolyear.year %}" class="tool">
|
<a href="{% url 'core:student-list' schoolyear.year %}" class="tool">
|
||||||
<h3>Students</h3>
|
<h3>Students</h3>
|
||||||
<p>Tool Description</p>
|
<p>Tool Description</p>
|
||||||
<span>→</span>
|
<span>→</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>→</span>
|
<span>→</span>
|
||||||
</a>
|
</a>
|
||||||
<a href="" class="tool">
|
<a href="{% url 'core:subject-list' schoolyear.year %}" class="tool">
|
||||||
<h3>Subjects</h3>
|
<h3>Subjects</h3>
|
||||||
<p>Tool Description</p>
|
<p>Tool Description</p>
|
||||||
<span>→</span>
|
<span>→</span>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</section>
|
||||||
</article>
|
</article>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@ -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 %}
|
||||||
|
|||||||
@ -8,38 +8,21 @@
|
|||||||
<header class="list__header">
|
<header class="list__header">
|
||||||
<div class="list__title">
|
<div class="list__title">
|
||||||
<h1>School Years</h1>
|
<h1>School Years</h1>
|
||||||
{% if perms.core.can_add_schoolyear %}
|
|
||||||
<a href="{% url 'core:schoolyear-create' %}" class="action-button">+ New Year</a>
|
<a href="{% url 'core:schoolyear-create' %}" class="action-button">+ New Year</a>
|
||||||
{% endif %}
|
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<table class="schoolyears list__table">
|
<section class="schoolyears__list">
|
||||||
<thead>
|
{% for schoolyear in schoolyear_list %}
|
||||||
<tr>
|
<a href="{% url 'core:schoolyear-detail' schoolyear.year %}" class="schoolyear">
|
||||||
<th>Created</th>
|
<h2>{{ schoolyear.year }}</h2>
|
||||||
<th>Year</th>
|
<h5>Students: ({{ schoolyear.student__count }})   Subjects: ({{ schoolyear.subject__count }})</h5>
|
||||||
<th>Students</th>
|
<span>→</span>
|
||||||
<th>Components</th>
|
</a>
|
||||||
<th>Last Updated</th>
|
{% empty %}
|
||||||
</tr>
|
<h3>No school years yet</h3>
|
||||||
</thead>
|
{% endfor %}
|
||||||
<tbody class="schoolyears__list">
|
</section>
|
||||||
{% for schoolyear in schoolyear_list %}
|
|
||||||
<tr class="schoolyear has-link" onclick="document.location='{% url 'core:schoolyear-detail' schoolyear.year %}'">
|
|
||||||
<td>{{ schoolyear.created_at|date:'m/d/Y' }}</td>
|
|
||||||
<td><h5>{{ schoolyear.year }}</h5></td>
|
|
||||||
<td></td>
|
|
||||||
<td></td>
|
|
||||||
<td></td>
|
|
||||||
</tr>
|
|
||||||
{% empty %}
|
|
||||||
<tr>
|
|
||||||
<td colspan="4">No schoolyears yet.</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
{% include 'core/partials/pagination.html' %}
|
{% include 'core/partials/pagination.html' %}
|
||||||
</article>
|
</article>
|
||||||
|
|
||||||
|
|||||||
31
src/core/templates/core/score_confirm_delete.html
Normal file
31
src/core/templates/core/score_confirm_delete.html
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block head_title %}Delete Score {{ score.pk }} | {% 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:subject-list' school_year.year %}">Subjects</a></li>
|
||||||
|
<span>›</span>
|
||||||
|
<li><a href="{% url 'core:subject-detail' school_year.year score.component.subject.pk %}">{{ score.component.subject.name }}</a></li>
|
||||||
|
<span>›</span>
|
||||||
|
<li><a href="{% url 'core:component-detail' school_year.year score.component.subject.pk score.component.pk %}">{{ score.component.name }}</a></li>
|
||||||
|
</menu>
|
||||||
|
</div>
|
||||||
|
{% endblock breadcrumbs %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<article class="form">
|
||||||
|
<h1>Delete Score</h1>
|
||||||
|
<form method="POST" action="{% url 'core:score-delete' school_year.year score.pk %}">
|
||||||
|
{% csrf_token %}
|
||||||
|
<p>Are you sure you want to delete "{{ score }}"?</p>
|
||||||
|
{{ form.as_p }}
|
||||||
|
<p>
|
||||||
|
<input type="submit" value="Delete" class="action-button action-delete"> or <a href="{% url 'core:component-detail' school_year.year score.component.subject.pk score.component.pk %}">cancel</a>
|
||||||
|
</p>
|
||||||
|
</form>
|
||||||
|
</article>
|
||||||
|
{% endblock %}
|
||||||
12
src/core/templates/core/score_create_form.html
Normal file
12
src/core/templates/core/score_create_form.html
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<h1>+ New Score</h1>
|
||||||
|
<form method="POST" action="{% url 'core:score-create' %}">
|
||||||
|
{% csrf_token %}
|
||||||
|
{{ form.as_p }}
|
||||||
|
<p>
|
||||||
|
<input type="submit" value="Create"> or <a href="{% url 'core:score-list' %}">cancel</a>
|
||||||
|
</p>
|
||||||
|
</form>
|
||||||
|
{% endblock %}
|
||||||
10
src/core/templates/core/score_detail.html
Normal file
10
src/core/templates/core/score_detail.html
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<h1>Score</h1>
|
||||||
|
<p>
|
||||||
|
<a href="{% url 'core:score-update' score.pk %}">Edit</a>
|
||||||
|
<a href="{% url 'core:score-delete' score.pk %}">Delete</a>
|
||||||
|
</p>
|
||||||
|
<p>{{ score }}</p>
|
||||||
|
{% endblock %}
|
||||||
39
src/core/templates/core/score_form.html
Normal file
39
src/core/templates/core/score_form.html
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block head_title %}Edit score {{ score.pk }} | {% 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:subject-list' school_year.year %}">Subjects</a></li>
|
||||||
|
<span>›</span>
|
||||||
|
<li><a href="{% url 'core:subject-detail' school_year.year score.component.subject.pk %}">{{ score.component.subject.name }}</a></li>
|
||||||
|
<span>›</span>
|
||||||
|
<li><a href="{% url 'core:component-detail' school_year.year score.component.subject.pk score.component.pk %}">{{ score.component.name }}</a></li>
|
||||||
|
</menu>
|
||||||
|
</div>
|
||||||
|
{% endblock breadcrumbs %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<article class="form">
|
||||||
|
<header class="form__header">
|
||||||
|
<div>
|
||||||
|
<h1>Edit Score</h1>
|
||||||
|
<h2>{{ score.component.subject }}— <em>{{ score.component.get_category_display }}</em>: {{ score.component }}</h2>
|
||||||
|
</div>
|
||||||
|
<p><a href="{% url 'core:score-delete' school_year.year score.pk %}" class="action-button action-delete">Delete</a></p>
|
||||||
|
</header>
|
||||||
|
<section>
|
||||||
|
<form action="{% url 'core:score-update' school_year.year score.pk %}" method="POST">
|
||||||
|
{% csrf_token %}
|
||||||
|
<h3>{{ score.student }}</h3>
|
||||||
|
{{ form.as_p }}
|
||||||
|
<p>
|
||||||
|
<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>
|
||||||
|
</form>
|
||||||
|
</section>
|
||||||
|
</article>
|
||||||
|
{% endblock %}
|
||||||
16
src/core/templates/core/score_list.html
Normal file
16
src/core/templates/core/score_list.html
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<h1>Scores</h1>
|
||||||
|
<table>
|
||||||
|
<tbody>
|
||||||
|
{% for score in score_list %}
|
||||||
|
<tr>
|
||||||
|
<dt>{{ score }}</dt>
|
||||||
|
</tr>
|
||||||
|
{% empty %}
|
||||||
|
<tr>No scores yet.</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
{% endblock %}
|
||||||
@ -1,7 +1,7 @@
|
|||||||
{% extends 'base.html' %}
|
{% extends 'base.html' %}
|
||||||
{% load helpers %}
|
{% load helpers %}
|
||||||
|
|
||||||
{% block head_title %}Student {{ student.student_id }} | {% endblock head_title %}
|
{% block head_title %}{{ student.student_id }} / {{ student.full_name }} | {% endblock head_title %}
|
||||||
|
|
||||||
{% block breadcrumbs %}
|
{% block breadcrumbs %}
|
||||||
<div class="breadcrumbs">
|
<div class="breadcrumbs">
|
||||||
@ -23,77 +23,87 @@
|
|||||||
</div>
|
</div>
|
||||||
<a href="{% url 'core:student-update' student.school_year.year student.pk %}" class="action-button">Edit</a>
|
<a href="{% url 'core:student-update' student.school_year.year student.pk %}" class="action-button">Edit</a>
|
||||||
</header>
|
</header>
|
||||||
<section class="student__details">
|
<section class="detail__info">
|
||||||
<dl>
|
<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>
|
||||||
<dd>{{ student.age }}</dd>
|
<dd>{{ student.age }}</dd>
|
||||||
|
<dt>Allergies</dt>
|
||||||
|
<dd>{% if student.allergies %}<span class="tag tag__warning">{{ student.allergies }}</span>{% endif %}</dd>
|
||||||
{% if student.address %}
|
{% if student.address %}
|
||||||
<dt>Address</dt>
|
<dt>Address</dt>
|
||||||
<dd>
|
<dd>
|
||||||
<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"><em>{{subject}}</em></td>
|
<td class="grade"><h5>{{ subject }}</h5> {{ subject.description }}</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>
|
<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 %}
|
||||||
<h4>{{subject.grouper}}</h4>
|
<div class="student__component">
|
||||||
<table>
|
<h4>{{ subject.grouper }}</h4>
|
||||||
<thead>
|
<table>
|
||||||
<tr>
|
<thead>
|
||||||
<td>Due Date</td>
|
<tr>
|
||||||
<td>Component</td>
|
<th>Due Date</th>
|
||||||
<td>Category</td>
|
<th>Component</th>
|
||||||
<td>Score</td>
|
<th>Category</th>
|
||||||
<td>Total</td>
|
<th>Score</th>
|
||||||
<td colspan="2">Percentage</td>
|
<th>Total</th>
|
||||||
</tr>
|
<th colspan="2">Percentage</th>
|
||||||
</thead>
|
</tr>
|
||||||
<tbody>
|
</thead>
|
||||||
{% for score in subject.list %}
|
<tbody>
|
||||||
<tr>
|
{% for score in subject.list %}
|
||||||
<td>{{score.component.due_date}}</td>
|
<tr>
|
||||||
<td><a href="{% url 'component-detail' score.component.subject.pk score.component.pk %}">{{score.component}}</a></td>
|
<td>{{ score.component.due_date }}</td>
|
||||||
<td>{{score.component.get_category_display}}</td>
|
<td>{{ score.component }}</td>
|
||||||
<td>{{score.value}}</td>
|
<td>{{ score.component.get_category_display }}</td>
|
||||||
<td>{{score.component.grade_total}}</td>
|
<td>{{ score.value }}</td>
|
||||||
<td>{{score.grade_as_percentage}}%</td>
|
<td>{{ score.component.grade_total }}</td>
|
||||||
<td><a href="{% url 'score-update' score.pk %}?return_to={{request.get_full_path}}">Change score</a></td>
|
<td>{{ score.grade_as_percentage }}%</td>
|
||||||
</tr>
|
<td><a href="{% url 'core:score-update' student.school_year.year score.pk %}">Edit</a></td>
|
||||||
{% endfor %}
|
</tr>
|
||||||
</tbody>
|
{% endfor %}
|
||||||
</table>
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
{% empty %}
|
{% empty %}
|
||||||
<p>No components graded yet.</p>
|
<p>No components graded yet.</p>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
@ -109,15 +119,14 @@
|
|||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Date</td>
|
<th colspan="2">Date</th>
|
||||||
<td colspan="2">Status</td>
|
|
||||||
</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>
|
||||||
|
|||||||
@ -1,12 +1,29 @@
|
|||||||
{% extends 'base.html' %}
|
{% extends 'base.html' %}
|
||||||
|
{% load helpers %}
|
||||||
|
|
||||||
|
{% block head_title %}Edit Student {{ student.student_id }} | {% endblock head_title %}
|
||||||
|
|
||||||
|
{% block breadcrumbs %}
|
||||||
|
<div class="breadcrumbs">
|
||||||
|
<menu>
|
||||||
|
<li><strong><a href="{% url 'core:schoolyear-detail' student.school_year.year %}">{{ student.school_year.year }}</a></strong></li>
|
||||||
|
<span>›</span>
|
||||||
|
<li><a href="{% url 'core:student-list' student.school_year.year %}">Students</a></li>
|
||||||
|
<span>›</span>
|
||||||
|
<li><a href="{% url 'core:student-detail' student.school_year.year student.pk %}">{{ student.full_name }}</a></li>
|
||||||
|
</menu>
|
||||||
|
</div>
|
||||||
|
{% endblock breadcrumbs %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h1>Update Student</h1>
|
<article class="form">
|
||||||
<form method="POST" action="{% url 'core:student-update' student.pk %}">
|
<h1>Edit Student</h1>
|
||||||
{% csrf_token %}
|
<form method="POST" action="{% url 'core:student-update' student.school_year.year student.pk %}">
|
||||||
{{ form.as_p }}
|
{% csrf_token %}
|
||||||
<p>
|
{{ form.as_p }}
|
||||||
<input type="submit" value="Save changes"> or <a href="{% url 'core:student-detail' student.pk %}">cancel</a>
|
<p>
|
||||||
</p>
|
<input type="submit" value="Save changes"> or <a href="{% url 'core:student-detail' student.school_year.year student.pk %}">cancel</a>
|
||||||
</form>
|
</p>
|
||||||
|
</form>
|
||||||
|
</article>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@ -18,13 +18,16 @@
|
|||||||
<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 →</a>
|
<a href="{% url 'core:stag-list' school_year.year %}">Student Tags →</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. ↕</a></th>
|
<th><a href="?order_by=record_num&sort=asc">Student No. ↕</a></th>
|
||||||
<th>Name</th>
|
<th>Name</th>
|
||||||
|
<th>Age</th>
|
||||||
|
<th>Birthday</th>
|
||||||
|
<th>Allergies</th>
|
||||||
<th>Tags</th>
|
<th>Tags</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
@ -32,12 +35,19 @@
|
|||||||
{% 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>{{ student.age }}</td>
|
||||||
|
<td>{{ student.dob }}</td>
|
||||||
|
<td>{% if student.allergies %}<span class="tag tag__warning">{{ student.allergies }}</span>{% endif %}</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="6">No students yet.</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|||||||
33
src/core/templates/core/studenttag_confirm_delete.html
Normal file
33
src/core/templates/core/studenttag_confirm_delete.html
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
|
{% block head_title %}Delete 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>
|
||||||
|
<span>›</span>
|
||||||
|
<li><a href="{% url 'core:stag-detail' school_year.year tag.pk %}">{{ tag }}</a></li>
|
||||||
|
</menu>
|
||||||
|
</div>
|
||||||
|
{% endblock breadcrumbs %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<article class="form">
|
||||||
|
<header class="form__header">
|
||||||
|
<h1>Delete Tag</h1>
|
||||||
|
</header>
|
||||||
|
<form method="POST" action="{% url 'core:stag-delete' school_year.year tag.pk %}">
|
||||||
|
{% csrf_token %}
|
||||||
|
<p>Are you sure you want to delete "{{ tag }}"?</p>
|
||||||
|
{{ form.as_p }}
|
||||||
|
<p>
|
||||||
|
<input type="submit" value="Delete" class="action-delete"> or <a href="{% url 'core:stag-update' school_year.year tag.pk %}">cancel</a>
|
||||||
|
</p>
|
||||||
|
</form>
|
||||||
|
</article>
|
||||||
|
{% endblock %}
|
||||||
28
src/core/templates/core/studenttag_create_form.html
Normal file
28
src/core/templates/core/studenttag_create_form.html
Normal 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 %}
|
||||||
50
src/core/templates/core/studenttag_detail.html
Normal file
50
src/core/templates/core/studenttag_detail.html
Normal 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. ↕</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 %}
|
||||||
33
src/core/templates/core/studenttag_form.html
Normal file
33
src/core/templates/core/studenttag_form.html
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
{% 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">
|
||||||
|
<header class="form__header">
|
||||||
|
<h1>Edit Tag</h1>
|
||||||
|
<p>
|
||||||
|
<a href="{% url 'core:stag-delete' school_year.year tag.pk %}" class="action-button action-delete">Delete</a>
|
||||||
|
</p>
|
||||||
|
</header>
|
||||||
|
<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 %}
|
||||||
32
src/core/templates/core/studenttag_list.html
Normal file
32
src/core/templates/core/studenttag_list.html
Normal 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 %}
|
||||||
13
src/core/templates/core/subject_confirm_delete.html
Normal file
13
src/core/templates/core/subject_confirm_delete.html
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<h1>Delete Subject</h1>
|
||||||
|
<form method="POST" action="{% url 'core:subject-delete' subject.pk %}">
|
||||||
|
{% csrf_token %}
|
||||||
|
<p>Are you sure you want to delete "{{ subject }}"?</p>
|
||||||
|
{{ form.as_p }}
|
||||||
|
<p>
|
||||||
|
<input type="submit" value="Delete"> or <a href="{% url 'core:subject-detail' subject.pk %}">cancel</a>
|
||||||
|
</p>
|
||||||
|
</form>
|
||||||
|
{% endblock %}
|
||||||
28
src/core/templates/core/subject_create_form.html
Normal file
28
src/core/templates/core/subject_create_form.html
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
|
{% block head_title %}New Subject | {% 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:subject-list' school_year.year %}">Subjects</a></li>
|
||||||
|
</menu>
|
||||||
|
</div>
|
||||||
|
{% endblock breadcrumbs %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<article class="form">
|
||||||
|
<header class="form__header">
|
||||||
|
<h1>+ New Subject</h1>
|
||||||
|
</header>
|
||||||
|
<form method="POST" action="{% url 'core:subject-create' school_year.year %}">
|
||||||
|
{% csrf_token %}
|
||||||
|
{{ form.as_p }}
|
||||||
|
<p>
|
||||||
|
<input type="submit" value="Create"> or <a href="{% url 'core:subject-list' school_year.year %}">cancel</a>
|
||||||
|
</p>
|
||||||
|
</form>
|
||||||
|
</article>
|
||||||
|
{% endblock %}
|
||||||
62
src/core/templates/core/subject_detail.html
Normal file
62
src/core/templates/core/subject_detail.html
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load helpers %}
|
||||||
|
|
||||||
|
{% block head_title %}{{ 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>
|
||||||
|
</menu>
|
||||||
|
</div>
|
||||||
|
{% endblock breadcrumbs %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<article class="detail">
|
||||||
|
<header class="detail__header">
|
||||||
|
<div>
|
||||||
|
<h1>{{ subject.name }}</h1>
|
||||||
|
<h5>{{ subject.description }}</h5>
|
||||||
|
<p><small>Added: <time datetime="{{ subject.created_at|date:'Y-m-d' }}">{{ subject.created_at|date:'M d Y' }}</time><br>
|
||||||
|
Last updated: <time datetime="{{ subject.updated_at|date:'Y-m-d' }}">{{ subject.updated_at|date:'M d Y' }}</time></small></p>
|
||||||
|
</div>
|
||||||
|
<a href="{% url 'core:subject-update' subject.school_year.year subject.pk %}" class="action-button">Edit</a>
|
||||||
|
</header>
|
||||||
|
<section>
|
||||||
|
<header class="list__header">
|
||||||
|
<div class="list__title">
|
||||||
|
<h3>Components</h3>
|
||||||
|
<a href="{% url 'core:component-create' subject.school_year.year subject.pk %}" class="action-button">+ New component</a>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<td>Due Date</td>
|
||||||
|
<td>Description</td>
|
||||||
|
<td>Category</td>
|
||||||
|
<td>Grade Total</td>
|
||||||
|
<td>Avg Score</td>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for component in subject.component_set.all %}
|
||||||
|
<tr class="component has-link" onclick="document.location='{% url 'core:component-detail' subject.school_year.year subject.pk component.pk %}'">
|
||||||
|
<td>{{component.due_date}}</td>
|
||||||
|
<td>{{component.name}}</td>
|
||||||
|
<td>{{component.get_category_display}}</td>
|
||||||
|
<td>{{component.grade_total}}</td>
|
||||||
|
<td>{{component.grade_avg_pre|floatformat:2}}</td>
|
||||||
|
</tr>
|
||||||
|
{% empty %}
|
||||||
|
<tr>
|
||||||
|
<td colspan="5">No components yet.</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</section>
|
||||||
|
</article>
|
||||||
|
{% endblock %}
|
||||||
30
src/core/templates/core/subject_form.html
Normal file
30
src/core/templates/core/subject_form.html
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
{% 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 %}
|
||||||
|
<article class="form">
|
||||||
|
<header>
|
||||||
|
<h1>Edit Subject</h1>
|
||||||
|
</header>
|
||||||
|
<form method="POST" action="{% url 'core:subject-update' subject.school_year.year subject.pk %}">
|
||||||
|
{% csrf_token %}
|
||||||
|
{{ form.as_p }}
|
||||||
|
<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 %}
|
||||||
48
src/core/templates/core/subject_list.html
Normal file
48
src/core/templates/core/subject_list.html
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load static %}
|
||||||
|
|
||||||
|
{% block head_title %}Subjects | {% 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>Subjects</h1>
|
||||||
|
<a href="{% url 'core:subject-create' school_year.year %}" class="action-button">+ New Subject</a>
|
||||||
|
</div>
|
||||||
|
<a href="{% url 'core:tag-list' school_year.year %}">Tags →</a>
|
||||||
|
</header>
|
||||||
|
<table class="list__table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>Components</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for subject in subject_list %}
|
||||||
|
<tr class="subject has-link" onclick="document.location='{% url 'core:subject-detail' school_year.year subject.pk %}'">
|
||||||
|
<td>
|
||||||
|
<h5>{{ subject.name }}</h5>
|
||||||
|
<small>{{ subject.description }}</small>
|
||||||
|
</td>
|
||||||
|
<td>{{ subject.component__count }}</td>
|
||||||
|
</tr>
|
||||||
|
{% empty %}
|
||||||
|
<tr>
|
||||||
|
<td colspan="3">No subjects yet.</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
{% include 'core/partials/pagination.html' %}
|
||||||
|
</article>
|
||||||
|
{% endblock %}
|
||||||
33
src/core/templates/core/tag_confirm_delete.html
Normal file
33
src/core/templates/core/tag_confirm_delete.html
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
|
{% block head_title %}Delete 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:subject-list' school_year.year %}">Subjects</a></li>
|
||||||
|
<span>›</span>
|
||||||
|
<li><a href="{% url 'core:tag-list' school_year.year %}">Tags</a></li>
|
||||||
|
<span>›</span>
|
||||||
|
<li><a href="{% url 'core:tag-detail' school_year.year tag.pk %}">{{ tag }}</a></li>
|
||||||
|
</menu>
|
||||||
|
</div>
|
||||||
|
{% endblock breadcrumbs %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<article class="form">
|
||||||
|
<header class="form__header">
|
||||||
|
<h1>Delete Tag</h1>
|
||||||
|
</header>
|
||||||
|
<form method="POST" action="{% url 'core:tag-delete' school_year.year tag.pk %}">
|
||||||
|
{% csrf_token %}
|
||||||
|
<p>Are you sure you want to delete "{{ tag }}"?</p>
|
||||||
|
{{ form.as_p }}
|
||||||
|
<p>
|
||||||
|
<input type="submit" value="Delete" class="action-delete"> or <a href="{% url 'core:tag-update' school_year.year tag.pk %}">cancel</a>
|
||||||
|
</p>
|
||||||
|
</form>
|
||||||
|
</article>
|
||||||
|
{% endblock %}
|
||||||
28
src/core/templates/core/tag_create_form.html
Normal file
28
src/core/templates/core/tag_create_form.html
Normal 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:subject-list' school_year.year %}">Subjects</a></li>
|
||||||
|
<span>›</span>
|
||||||
|
<li><a href="{% url 'core:tag-list' school_year.year %}">Tags</a></li>
|
||||||
|
</menu>
|
||||||
|
</div>
|
||||||
|
{% endblock breadcrumbs %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<article class="form">
|
||||||
|
<h1>+ New Tag</h1>
|
||||||
|
<form method="POST" action="{% url 'core:tag-create' school_year.year %}">
|
||||||
|
{% csrf_token %}
|
||||||
|
{{ form.as_p }}
|
||||||
|
<p>
|
||||||
|
<input type="submit" value="Create"> or <a href="{% url 'core:tag-list' school_year.year %}">cancel</a>
|
||||||
|
</p>
|
||||||
|
</form>
|
||||||
|
</article>
|
||||||
|
{% endblock %}
|
||||||
50
src/core/templates/core/tag_detail.html
Normal file
50
src/core/templates/core/tag_detail.html
Normal 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:subject-list' school_year.year %}">Subjects</a></li>
|
||||||
|
<span>›</span>
|
||||||
|
<li><a href="{% url 'core:tag-list' school_year.year %}">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:tag-update' school_year.year tag.pk %}" class="action-button">Edit</a>
|
||||||
|
</header>
|
||||||
|
<section>
|
||||||
|
<h3>Subjects with this tag</h3>
|
||||||
|
<table class="list__table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Subject</th>
|
||||||
|
<th>Name</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for component in tag.component_set.all %}
|
||||||
|
<tr class="has-link" onclick="document.location='{% url 'core:component-detail' school_year.year component.subject.pk component.pk %}'">
|
||||||
|
<td>{{ component.subject.name }}</td>
|
||||||
|
<td>{{ component }}</td>
|
||||||
|
</tr>
|
||||||
|
{% empty %}
|
||||||
|
<tr>
|
||||||
|
<td colspan="2">No components tagged yet.</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</section>
|
||||||
|
</article>
|
||||||
|
{% endblock %}
|
||||||
35
src/core/templates/core/tag_form.html
Normal file
35
src/core/templates/core/tag_form.html
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
{% 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:subject-list' school_year.year %}">Subjects</a></li>
|
||||||
|
<span>›</span>
|
||||||
|
<li><a href="{% url 'core:tag-list' school_year.year %}">Tags</a></li>
|
||||||
|
<span>›</span>
|
||||||
|
<li><a href="{% url 'core:tag-detail' school_year.year tag.pk %}">{{ tag }}</a></li>
|
||||||
|
</menu>
|
||||||
|
</div>
|
||||||
|
{% endblock breadcrumbs %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<article class="form">
|
||||||
|
<header class="form__header">
|
||||||
|
<h1>Edit Tag</h1>
|
||||||
|
<p>
|
||||||
|
<a href="{% url 'core:tag-delete' school_year.year tag.pk %}" class="action-button action-delete">Delete</a>
|
||||||
|
</p>
|
||||||
|
</header>
|
||||||
|
<form method="POST" action="{% url 'core:tag-update' school_year.year tag.pk %}">
|
||||||
|
{% csrf_token %}
|
||||||
|
{{ form.as_p }}
|
||||||
|
<p>
|
||||||
|
<input type="submit" value="Save changes"> or <a href="{% url 'core:tag-detail' school_year.year tag.pk %}">cancel</a>
|
||||||
|
</p>
|
||||||
|
</form>
|
||||||
|
</article>
|
||||||
|
{% endblock %}
|
||||||
32
src/core/templates/core/tag_list.html
Normal file
32
src/core/templates/core/tag_list.html
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load helpers %}
|
||||||
|
|
||||||
|
{% block head_title %}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:subject-list' school_year.year %}">Subjects</a></li>
|
||||||
|
</menu>
|
||||||
|
</div>
|
||||||
|
{% endblock breadcrumbs %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<article class="list">
|
||||||
|
<header class="list__header">
|
||||||
|
<div class="list__title">
|
||||||
|
<h1>Tags</h1>
|
||||||
|
<a href="{% url 'core:tag-create' school_year.year %}" class="action-button">+ New Tag</a>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<section>
|
||||||
|
{% for tag in tag_list %}
|
||||||
|
<a href="{% url 'core:tag-detail' school_year.year tag.pk %}" class="tag tag__info">{{ tag }}</a>
|
||||||
|
{% empty %}
|
||||||
|
<p>No tags yet.</p>
|
||||||
|
{% endfor %}
|
||||||
|
</section>
|
||||||
|
</article>
|
||||||
|
{% endblock %}
|
||||||
@ -1,19 +1,18 @@
|
|||||||
{% extends 'base.html' %}
|
{% extends 'base.html' %}
|
||||||
{% load static %}
|
{% load static %}
|
||||||
|
|
||||||
|
{% block head_title %}Today |{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<article class="panel">
|
<article class="panel">
|
||||||
<header>
|
<header>
|
||||||
<h1 class="greeting"><em>Welcome {{profile.user.first_name}} {{profile.user.last_name }}</em>
|
<h1>Here's what's going on today</h1>
|
||||||
<br>
|
|
||||||
Here's what's going on today
|
|
||||||
</h1>
|
|
||||||
</header>
|
</header>
|
||||||
<section>
|
<section>
|
||||||
<h3 class="domain__heading">Birthdays</h3>
|
<h3 class="domain__heading">Birthdays this week</h3>
|
||||||
<ul>
|
<ul>
|
||||||
{% for student in birthdays %}
|
{% for student in birthdays %}
|
||||||
<li><strong><a href="{% url 'student-detail' student.pk %}">{{student}}</a></strong> is turning {{student.age|add:1}} on {{student.dob|date:"M j"}}</li>
|
<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 %}
|
{% empty %}
|
||||||
<p>No Birthdays this next week.</p>
|
<p>No Birthdays this next week.</p>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
@ -24,7 +23,7 @@
|
|||||||
<ul>
|
<ul>
|
||||||
{% for component in components %}
|
{% for component in components %}
|
||||||
<li>
|
<li>
|
||||||
{{component.subject}}, <a href="{% url 'component-detail' component.subject.pk component.pk %}">{{component}}</a>
|
{{component.subject}}, <a href="{% url 'core:component-detail' component.subject.pk component.pk %}">{{component}}</a>
|
||||||
</li>
|
</li>
|
||||||
{% empty %}
|
{% empty %}
|
||||||
<p>Nothing for today.</p>
|
<p>Nothing for today.</p>
|
||||||
@ -34,7 +33,7 @@
|
|||||||
<section>
|
<section>
|
||||||
<h3 class="domain__heading">Today's Attendance</h3>
|
<h3 class="domain__heading">Today's Attendance</h3>
|
||||||
{% for day in attendance %}
|
{% for day in attendance %}
|
||||||
<p><strong><a href="{% url 'day-update' day.pk %}">{{day.date}}</a></strong></p>
|
<h4><a href="{% url 'core:schoolday-update' current_year.year day.pk %}">{{day.date}}</a></h4>
|
||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
@ -43,17 +42,17 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for entry in day.entry_set.all %}
|
{% for entry in day.attendanceentry_set.all %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{entry.student}}</td>
|
<td>{{entry.student}}</td>
|
||||||
<td>{{entry.get_status_display}}</td>
|
<td>{{entry.get_status_display}}</td>
|
||||||
<td><a href="{% url 'entry-update' entry.pk %}">Update</a></td>
|
<td><a href="{% url 'core:entry-update' current_year.year entry.school_day.pk entry.pk %}">Edit</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
{% empty %}
|
{% empty %}
|
||||||
<p class="greeting">No attendance taken yet: <a href="{% url 'day-create' %}" class="action-button">Take attendance</a></p>
|
<p class="greeting">No attendance taken yet: <a href="{% url 'core:schoolday-create' current_year.year %}" class="action-button">Take attendance →</a></p>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</section>
|
</section>
|
||||||
<section>
|
<section>
|
||||||
@ -61,7 +60,7 @@
|
|||||||
<ul>
|
<ul>
|
||||||
{% for component in ungraded_components %}
|
{% for component in ungraded_components %}
|
||||||
<li>
|
<li>
|
||||||
{{component.subject}}, <a href="{% url 'component-detail' component.subject.pk component.pk %}">{{component}}</a>
|
{{component.subject}}, <a href="{% url 'core:component-detail' current_year.year component.subject.pk component.pk %}">{{component}}</a>
|
||||||
</li>
|
</li>
|
||||||
{% empty %}
|
{% empty %}
|
||||||
<p>Everything is graded to far.</p>
|
<p>Everything is graded to far.</p>
|
||||||
227
src/core/urls.py
227
src/core/urls.py
@ -2,6 +2,8 @@ from django.urls import path, include
|
|||||||
from . import views
|
from . import views
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
|
path('', views.HomeView.as_view(), name='home'),
|
||||||
|
|
||||||
# SchoolYears
|
# SchoolYears
|
||||||
path('years/', include([
|
path('years/', include([
|
||||||
path(
|
path(
|
||||||
@ -25,6 +27,7 @@ urlpatterns = [
|
|||||||
views.SchoolYearUpdateView.as_view(),
|
views.SchoolYearUpdateView.as_view(),
|
||||||
name='schoolyear-update'
|
name='schoolyear-update'
|
||||||
),
|
),
|
||||||
|
path('today/', views.TodayView.as_view(), name='today'),
|
||||||
|
|
||||||
# Students
|
# Students
|
||||||
path('students/', include([
|
path('students/', include([
|
||||||
@ -38,7 +41,7 @@ urlpatterns = [
|
|||||||
views.StudentCreateView.as_view(),
|
views.StudentCreateView.as_view(),
|
||||||
name='student-create'
|
name='student-create'
|
||||||
),
|
),
|
||||||
path('<int:student_pk>/', include([
|
path('<int:pk>/', include([
|
||||||
path(
|
path(
|
||||||
'',
|
'',
|
||||||
views.StudentDetailView.as_view(),
|
views.StudentDetailView.as_view(),
|
||||||
@ -55,6 +58,228 @@ 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
|
||||||
|
path('subjects/', include([
|
||||||
|
path(
|
||||||
|
'',
|
||||||
|
views.SubjectListView.as_view(),
|
||||||
|
name='subject-list'
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
'new/',
|
||||||
|
views.SubjectCreateView.as_view(),
|
||||||
|
name='subject-create'
|
||||||
|
),
|
||||||
|
path('<int:pk>/', include([
|
||||||
|
path(
|
||||||
|
'',
|
||||||
|
views.SubjectDetailView.as_view(),
|
||||||
|
name='subject-detail'
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
'update/',
|
||||||
|
views.SubjectUpdateView.as_view(),
|
||||||
|
name='subject-update'
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
'delete/',
|
||||||
|
views.SubjectDeleteView.as_view(),
|
||||||
|
name='subject-delete'
|
||||||
|
),
|
||||||
|
|
||||||
|
# Components
|
||||||
|
path('components/', include([
|
||||||
|
path(
|
||||||
|
'',
|
||||||
|
views.ComponentListView.as_view(),
|
||||||
|
name='component-list'
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
'new/',
|
||||||
|
views.ComponentCreateView.as_view(),
|
||||||
|
name='component-create'
|
||||||
|
),
|
||||||
|
path('<int:component_pk>/', include([
|
||||||
|
path(
|
||||||
|
'',
|
||||||
|
views.ComponentDetailView.as_view(),
|
||||||
|
name='component-detail'
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
'update/',
|
||||||
|
views.ComponentUpdateView.as_view(),
|
||||||
|
name='component-update'
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
'delete/',
|
||||||
|
views.ComponentDeleteView.as_view(),
|
||||||
|
name='component-delete'
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
'manage/',
|
||||||
|
views.ComponentManagerView.as_view(),
|
||||||
|
name='component-manager'
|
||||||
|
),
|
||||||
|
])),
|
||||||
|
])),
|
||||||
|
])),
|
||||||
|
|
||||||
|
# Tags
|
||||||
|
path('tags/', include([
|
||||||
|
path(
|
||||||
|
'',
|
||||||
|
views.TagListView.as_view(),
|
||||||
|
name='tag-list'
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
'new/',
|
||||||
|
views.TagCreateView.as_view(),
|
||||||
|
name='tag-create'
|
||||||
|
),
|
||||||
|
path('<int:tag_pk>/', include([
|
||||||
|
path(
|
||||||
|
'',
|
||||||
|
views.TagDetailView.as_view(),
|
||||||
|
name='tag-detail'
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
'update/',
|
||||||
|
views.TagUpdateView.as_view(),
|
||||||
|
name='tag-update'
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
'delete/',
|
||||||
|
views.TagDeleteView.as_view(),
|
||||||
|
name='tag-delete'
|
||||||
|
),
|
||||||
|
])),
|
||||||
|
])),
|
||||||
|
])),
|
||||||
|
|
||||||
|
# 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
|
||||||
|
path('scores/', include([
|
||||||
|
path(
|
||||||
|
'',
|
||||||
|
views.ScoreListView.as_view(),
|
||||||
|
name='score-list'
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
'new/',
|
||||||
|
views.ScoreCreateView.as_view(),
|
||||||
|
name='score-create'
|
||||||
|
),
|
||||||
|
path('<int:pk>/', include([
|
||||||
|
path(
|
||||||
|
'',
|
||||||
|
views.ScoreDetailView.as_view(),
|
||||||
|
name='score-detail'
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
'update/',
|
||||||
|
views.ScoreUpdateView.as_view(),
|
||||||
|
name='score-update'
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
'delete/',
|
||||||
|
views.ScoreDeleteView.as_view(),
|
||||||
|
name='score-delete'
|
||||||
|
),
|
||||||
|
])),
|
||||||
])),
|
])),
|
||||||
])),
|
])),
|
||||||
])),
|
])),
|
||||||
|
|||||||
@ -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
|
||||||
@ -33,28 +34,94 @@ from .models import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
from .forms import (
|
from .forms import (
|
||||||
SchoolYearCreateForm
|
StudentForm,
|
||||||
|
SchoolYearCreateForm,
|
||||||
|
ComponentCreateForm,
|
||||||
|
SchoolDayForm,
|
||||||
|
AttendanceEntryForm
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# SEARCH
|
||||||
|
# # Look up Q objects for combining different fields in a single query
|
||||||
|
# from django.db.models import Q
|
||||||
|
# people = Person.objects.filter(Q(first_name__contains=query) | Q(last_name__contains=query)
|
||||||
|
# restaurants = Restaurant.objects.filter(restaurant_name__contains=query)
|
||||||
|
# pizzas = Pizza.objects.filter(pizza_name__contains=query)
|
||||||
|
|
||||||
class SchoolYearListView(ListView):
|
# Then combine the results, if you want
|
||||||
|
|
||||||
|
# from itertools import chain
|
||||||
|
# results = chain(people, restaurants, pizzas)
|
||||||
|
|
||||||
|
|
||||||
|
class HomeView(TemplateView):
|
||||||
|
template_name = 'core/home.html'
|
||||||
|
|
||||||
|
|
||||||
|
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(
|
||||||
|
school_year__year=self.kwargs['year'],
|
||||||
|
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(
|
||||||
|
subject__school_year__year=self.kwargs['year'],
|
||||||
|
due_date__lte=today,
|
||||||
|
finished_grading=False
|
||||||
|
).select_related('subject')
|
||||||
|
|
||||||
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
class SchoolYearListView(LoginRequiredMixin, ListView):
|
||||||
model = SchoolYear
|
model = SchoolYear
|
||||||
|
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 SchoolYearDetailView(DetailView):
|
class SchoolYearCreateView(
|
||||||
model = SchoolYear
|
LoginRequiredMixin, SuccessMessageMixin, CreateView
|
||||||
slug_url_kwarg = 'year'
|
):
|
||||||
slug_field = 'year'
|
|
||||||
|
|
||||||
|
|
||||||
class SchoolYearCreateView(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 SchoolYearUpdateView(SuccessMessageMixin, UpdateView):
|
class SchoolYearDetailView(LoginRequiredMixin, DetailView):
|
||||||
|
model = SchoolYear
|
||||||
|
slug_url_kwarg = 'year'
|
||||||
|
slug_field = 'year'
|
||||||
|
|
||||||
|
|
||||||
|
class SchoolYearUpdateView(
|
||||||
|
LoginRequiredMixin, SuccessMessageMixin, UpdateView
|
||||||
|
):
|
||||||
model = SchoolYear
|
model = SchoolYear
|
||||||
slug_url_kwarg = 'year'
|
slug_url_kwarg = 'year'
|
||||||
slug_field = 'year'
|
slug_field = 'year'
|
||||||
@ -62,7 +129,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
|
||||||
|
|
||||||
@ -80,12 +147,35 @@ class StudentListView(ListView):
|
|||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
class StudentDetailView(DetailView):
|
class StudentCreateView(LoginRequiredMixin, SuccessMessageMixin, CreateView):
|
||||||
model = Student
|
model = Student
|
||||||
pk_url_kwarg = 'student_pk'
|
success_message = 'Student created.'
|
||||||
|
template_name_suffix = '_create_form'
|
||||||
|
form_class = StudentForm
|
||||||
|
|
||||||
|
def form_valid(self, form):
|
||||||
|
form.instance.school_year = get_object_or_404(
|
||||||
|
SchoolYear, year=self.kwargs['year']
|
||||||
|
)
|
||||||
|
return super().form_valid(form)
|
||||||
|
|
||||||
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']
|
||||||
|
)
|
||||||
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
class StudentDetailView(LoginRequiredMixin, DetailView):
|
||||||
|
model = Student
|
||||||
|
|
||||||
|
def get_context_data(self, **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'
|
||||||
@ -116,37 +206,619 @@ class StudentDetailView(DetailView):
|
|||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
class StudentCreateView(SuccessMessageMixin, CreateView):
|
class StudentUpdateView(LoginRequiredMixin, SuccessMessageMixin, UpdateView):
|
||||||
model = Student
|
model = Student
|
||||||
success_message = 'Student created.'
|
|
||||||
template_name_suffix = '_create_form'
|
|
||||||
fields = [
|
|
||||||
'student_id',
|
|
||||||
'first_name',
|
|
||||||
'last_name',
|
|
||||||
'address',
|
|
||||||
'dob',
|
|
||||||
]
|
|
||||||
|
|
||||||
def form_valid(self, form):
|
|
||||||
form.instance.school_year = get_object_or_404(SchoolYear, year=self.kwargs['year'])
|
|
||||||
return super().form_valid(form)
|
|
||||||
|
|
||||||
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 StudentUpdateView(SuccessMessageMixin, UpdateView):
|
|
||||||
model = Student
|
|
||||||
pk_url_kwarg = 'student_pk'
|
|
||||||
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
|
||||||
pk_url_kwarg = 'student_pk'
|
|
||||||
success_message = 'Student deleted.'
|
success_message = 'Student deleted.'
|
||||||
success_url = reverse_lazy('student-list')
|
success_url = reverse_lazy('student-list')
|
||||||
|
|
||||||
|
|
||||||
|
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_queryset(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']
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
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 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
|
||||||
|
paginate_by = 50
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
queryset = Subject.objects.filter(
|
||||||
|
school_year__year=self.kwargs['year']
|
||||||
|
).annotate(
|
||||||
|
models.Count('component')
|
||||||
|
).order_by('name')
|
||||||
|
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 SubjectCreateView(LoginRequiredMixin, SuccessMessageMixin, CreateView):
|
||||||
|
model = Subject
|
||||||
|
success_message = 'Subject created.'
|
||||||
|
template_name_suffix = '_create_form'
|
||||||
|
fields = [
|
||||||
|
'name',
|
||||||
|
'description'
|
||||||
|
]
|
||||||
|
|
||||||
|
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 form_valid(self, form):
|
||||||
|
form.instance.school_year = get_object_or_404(
|
||||||
|
SchoolYear, year=self.kwargs['year']
|
||||||
|
)
|
||||||
|
return super().form_valid(form)
|
||||||
|
|
||||||
|
|
||||||
|
class SubjectDetailView(LoginRequiredMixin, DetailView):
|
||||||
|
model = Subject
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
queryset = Subject.objects.filter(
|
||||||
|
pk=self.kwargs.get(self.pk_url_kwarg)
|
||||||
|
).select_related(
|
||||||
|
'school_year'
|
||||||
|
).prefetch_related(
|
||||||
|
Prefetch(
|
||||||
|
'component_set',
|
||||||
|
queryset=Component.objects.prefetch_related(
|
||||||
|
'score_set'
|
||||||
|
).annotate(
|
||||||
|
grade_avg_pre=Avg('score__value')
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return queryset
|
||||||
|
|
||||||
|
|
||||||
|
class SubjectUpdateView(LoginRequiredMixin, SuccessMessageMixin, UpdateView):
|
||||||
|
model = Subject
|
||||||
|
success_message = 'Subject 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
|
||||||
|
|
||||||
|
|
||||||
|
class SubjectDeleteView(LoginRequiredMixin, SuccessMessageMixin, DeleteView):
|
||||||
|
model = Subject
|
||||||
|
success_message = 'Subject deleted.'
|
||||||
|
success_url = reverse_lazy('subject-list')
|
||||||
|
|
||||||
|
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 TagListView(LoginRequiredMixin, ListView):
|
||||||
|
model = Tag
|
||||||
|
|
||||||
|
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 TagCreateView(
|
||||||
|
LoginRequiredMixin, SuccessMessageMixin, CreateView
|
||||||
|
):
|
||||||
|
model = Tag
|
||||||
|
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:tag-list', kwargs={
|
||||||
|
'year': self.kwargs['year']
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
class TagDetailView(LoginRequiredMixin, DetailView):
|
||||||
|
model = Tag
|
||||||
|
pk_url_kwarg = 'tag_pk'
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
queryset = Tag.objects.filter(
|
||||||
|
pk=self.kwargs.get(self.pk_url_kwarg)
|
||||||
|
).prefetch_related(
|
||||||
|
Prefetch(
|
||||||
|
'component_set',
|
||||||
|
queryset=Component.objects.filter(
|
||||||
|
subject__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 TagUpdateView(
|
||||||
|
LoginRequiredMixin, SuccessMessageMixin, UpdateView
|
||||||
|
):
|
||||||
|
model = Tag
|
||||||
|
pk_url_kwarg = 'tag_pk'
|
||||||
|
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:tag-list', kwargs={
|
||||||
|
'year': self.kwargs['year']
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
class TagDeleteView(
|
||||||
|
LoginRequiredMixin, SuccessMessageMixin, DeleteView
|
||||||
|
):
|
||||||
|
model = Tag
|
||||||
|
pk_url_kwarg = 'tag_pk'
|
||||||
|
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:tag-list', kwargs={
|
||||||
|
'year': self.kwargs['year']
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
class ComponentListView(LoginRequiredMixin, ListView):
|
||||||
|
model = Component
|
||||||
|
|
||||||
|
|
||||||
|
class ComponentCreateView(LoginRequiredMixin, SuccessMessageMixin, CreateView):
|
||||||
|
model = Component
|
||||||
|
success_message = 'Component created.'
|
||||||
|
template_name_suffix = '_create_form'
|
||||||
|
form_class = ComponentCreateForm
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super().get_context_data(**kwargs)
|
||||||
|
context['school_year'] = get_object_or_404(
|
||||||
|
SchoolYear, year=self.kwargs['year']
|
||||||
|
)
|
||||||
|
context['subject'] = get_object_or_404(
|
||||||
|
Subject, pk=self.kwargs['pk']
|
||||||
|
)
|
||||||
|
return context
|
||||||
|
|
||||||
|
def form_valid(self, form):
|
||||||
|
form.instance.school_year = get_object_or_404(
|
||||||
|
SchoolYear, year=self.kwargs['year']
|
||||||
|
)
|
||||||
|
form.instance.subject = get_object_or_404(
|
||||||
|
Subject, pk=self.kwargs['pk']
|
||||||
|
)
|
||||||
|
return super().form_valid(form)
|
||||||
|
|
||||||
|
|
||||||
|
class ComponentDetailView(LoginRequiredMixin, DetailView):
|
||||||
|
model = Component
|
||||||
|
pk_url_kwarg = 'component_pk'
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
queryset = Component.objects.filter(
|
||||||
|
pk=self.kwargs.get(self.pk_url_kwarg)
|
||||||
|
).prefetch_related(
|
||||||
|
Prefetch(
|
||||||
|
'score_set',
|
||||||
|
queryset=Score.objects.select_related('student')
|
||||||
|
),
|
||||||
|
'tags'
|
||||||
|
).annotate(
|
||||||
|
grade_avg_pre=Avg('score__value')
|
||||||
|
)
|
||||||
|
return queryset
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super().get_context_data(**kwargs)
|
||||||
|
cscores = Score.objects.filter(
|
||||||
|
component=self.object,
|
||||||
|
student=OuterRef('pk')
|
||||||
|
)
|
||||||
|
context['scoreless'] = Student.objects.filter(
|
||||||
|
school_year__year=self.kwargs['year']
|
||||||
|
).exclude(
|
||||||
|
score__in=cscores
|
||||||
|
)
|
||||||
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
class ComponentUpdateView(LoginRequiredMixin, SuccessMessageMixin, UpdateView):
|
||||||
|
model = Component
|
||||||
|
pk_url_kwarg = 'component_pk'
|
||||||
|
success_message = 'Component saved.'
|
||||||
|
fields = '__all__'
|
||||||
|
|
||||||
|
def get_success_url(self):
|
||||||
|
return reverse('core:component-detail', kwargs={
|
||||||
|
'year': self.object.subject.school_year.year,
|
||||||
|
'pk': self.object.subject.pk,
|
||||||
|
'component_pk': self.object.pk
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
class ComponentDeleteView(LoginRequiredMixin, SuccessMessageMixin, DeleteView):
|
||||||
|
model = Component
|
||||||
|
pk_url_kwarg = 'component_pk'
|
||||||
|
success_message = 'Component deleted.'
|
||||||
|
success_url = reverse_lazy('core:component-list')
|
||||||
|
|
||||||
|
|
||||||
|
class ComponentManagerView(LoginRequiredMixin, UpdateView):
|
||||||
|
model = Component
|
||||||
|
pk_url_kwarg = 'component_pk'
|
||||||
|
template_name_suffix = '_manager'
|
||||||
|
fields = ['finished_grading']
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super().get_context_data(**kwargs)
|
||||||
|
cscores = Score.objects.filter(
|
||||||
|
component=self.object,
|
||||||
|
student=OuterRef('pk')
|
||||||
|
)
|
||||||
|
context['student_list'] = Student.objects.filter(
|
||||||
|
school_year__year=self.kwargs['year']
|
||||||
|
).annotate(
|
||||||
|
cscore=Subquery(cscores.values('value')),
|
||||||
|
cscore_pk=Subquery(cscores.values('pk'))
|
||||||
|
)
|
||||||
|
return context
|
||||||
|
|
||||||
|
def get_success_url(self):
|
||||||
|
return reverse('core:component-detail', kwargs={
|
||||||
|
'year': self.object.subject.school_year.year,
|
||||||
|
'pk': self.object.subject.pk,
|
||||||
|
'component_pk': self.object.pk
|
||||||
|
})
|
||||||
|
|
||||||
|
def form_valid(self, form):
|
||||||
|
form.save()
|
||||||
|
for key, value in self.request.POST.items():
|
||||||
|
if 'student' in key and value:
|
||||||
|
s_pk = key.split('_')[1]
|
||||||
|
obj, created = Score.objects.update_or_create(
|
||||||
|
component=self.object,
|
||||||
|
student=Student.objects.get(pk=s_pk),
|
||||||
|
defaults={'value': value}
|
||||||
|
)
|
||||||
|
return super().form_valid(form)
|
||||||
|
|
||||||
|
|
||||||
|
class ScoreListView(LoginRequiredMixin, ListView):
|
||||||
|
model = Score
|
||||||
|
|
||||||
|
|
||||||
|
class ScoreCreateView(LoginRequiredMixin, SuccessMessageMixin, CreateView):
|
||||||
|
model = Score
|
||||||
|
success_message = 'Score created.'
|
||||||
|
template_name_suffix = '_create_form'
|
||||||
|
fields = '__all__'
|
||||||
|
|
||||||
|
|
||||||
|
class ScoreDetailView(LoginRequiredMixin, DetailView):
|
||||||
|
model = Score
|
||||||
|
|
||||||
|
|
||||||
|
class ScoreUpdateView(LoginRequiredMixin, SuccessMessageMixin, UpdateView):
|
||||||
|
model = Score
|
||||||
|
success_message = 'Score saved.'
|
||||||
|
fields = [
|
||||||
|
'component',
|
||||||
|
'value'
|
||||||
|
]
|
||||||
|
|
||||||
|
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 ScoreDeleteView(LoginRequiredMixin, SuccessMessageMixin, DeleteView):
|
||||||
|
model = Score
|
||||||
|
success_message = 'Score deleted.'
|
||||||
|
|
||||||
|
def get_success_url(self):
|
||||||
|
return reverse('core:schoolyear-detail', 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 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.filter(
|
||||||
|
school_year__year=self.kwargs['year']
|
||||||
|
)
|
||||||
|
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['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']
|
||||||
|
})
|
||||||
|
|||||||
32184
src/db.json
Normal file
32184
src/db.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,12 +0,0 @@
|
|||||||
from django.contrib import admin
|
|
||||||
from .models import (
|
|
||||||
Tag,
|
|
||||||
Subject,
|
|
||||||
Component,
|
|
||||||
Score,
|
|
||||||
)
|
|
||||||
|
|
||||||
admin.site.register(Tag)
|
|
||||||
admin.site.register(Subject)
|
|
||||||
admin.site.register(Component)
|
|
||||||
admin.site.register(Score)
|
|
||||||
@ -1,6 +0,0 @@
|
|||||||
from django.apps import AppConfig
|
|
||||||
|
|
||||||
|
|
||||||
class GradebookConfig(AppConfig):
|
|
||||||
default_auto_field = 'django.db.models.BigAutoField'
|
|
||||||
name = 'gradebook'
|
|
||||||
@ -1,43 +0,0 @@
|
|||||||
from django import forms
|
|
||||||
from .models import Component, Score, Tag
|
|
||||||
|
|
||||||
from students.models import Student
|
|
||||||
|
|
||||||
class ComponentForm(forms.ModelForm):
|
|
||||||
class Meta:
|
|
||||||
model = Component
|
|
||||||
fields = (
|
|
||||||
'name',
|
|
||||||
'category',
|
|
||||||
'due_date',
|
|
||||||
'grade_total',
|
|
||||||
)
|
|
||||||
widgets = {
|
|
||||||
'due_date': forms.DateInput(attrs = {
|
|
||||||
'type': 'date'
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
|
|
||||||
class ComponentUpdateForm(forms.ModelForm):
|
|
||||||
class Meta:
|
|
||||||
model = Component
|
|
||||||
fields = (
|
|
||||||
'subject',
|
|
||||||
'name',
|
|
||||||
'category',
|
|
||||||
'due_date',
|
|
||||||
'grade_total',
|
|
||||||
'tags',
|
|
||||||
)
|
|
||||||
widgets = {
|
|
||||||
'due_date': forms.DateInput(attrs = {
|
|
||||||
'type': 'date'
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
|
|
||||||
class TagForm(forms.ModelForm):
|
|
||||||
class Meta:
|
|
||||||
model = Tag
|
|
||||||
fields = (
|
|
||||||
'name',
|
|
||||||
)
|
|
||||||
@ -1,69 +0,0 @@
|
|||||||
# Generated by Django 3.2.7 on 2021-09-01 15:26
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
import django.db.models.deletion
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
initial = True
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('students', '0001_initial'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='Component',
|
|
||||||
fields=[
|
|
||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
('name', models.CharField(max_length=50)),
|
|
||||||
('category', models.CharField(choices=[('QZ', 'Quiz'), ('AS', 'Assignment'), ('TS', 'Test')], default='AS', max_length=2)),
|
|
||||||
('due_date', models.DateField()),
|
|
||||||
('grade_total', models.PositiveIntegerField()),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'ordering': ['due_date'],
|
|
||||||
},
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='Subject',
|
|
||||||
fields=[
|
|
||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
('name', models.CharField(max_length=250)),
|
|
||||||
('description', models.CharField(blank=True, max_length=250)),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'ordering': ['name'],
|
|
||||||
},
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='Tag',
|
|
||||||
fields=[
|
|
||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
('name', models.CharField(max_length=50)),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='Score',
|
|
||||||
fields=[
|
|
||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
('value', models.PositiveIntegerField()),
|
|
||||||
('component', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='gradebook.component')),
|
|
||||||
('student', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='students.student')),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'ordering': ('student',),
|
|
||||||
},
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='component',
|
|
||||||
name='subject',
|
|
||||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='gradebook.subject'),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='component',
|
|
||||||
name='tags',
|
|
||||||
field=models.ManyToManyField(blank=True, to='gradebook.Tag'),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@ -1,18 +0,0 @@
|
|||||||
# Generated by Django 3.2.7 on 2021-09-16 23:21
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('gradebook', '0001_initial'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='component',
|
|
||||||
name='finished_grading',
|
|
||||||
field=models.BooleanField(default=False),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@ -1,100 +0,0 @@
|
|||||||
from datetime import datetime, date
|
|
||||||
from django.db import models
|
|
||||||
from django.urls import reverse
|
|
||||||
|
|
||||||
from django.db.models import Count, Sum, Avg, F, Value
|
|
||||||
from django.db.models.functions import Length, Upper
|
|
||||||
|
|
||||||
from students.models import Student
|
|
||||||
|
|
||||||
class Tag(models.Model):
|
|
||||||
name = models.CharField(max_length=50)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self.name
|
|
||||||
|
|
||||||
def get_absolute_url(self):
|
|
||||||
return reverse('tag-detail', kwargs={'pk': self.pk})
|
|
||||||
|
|
||||||
|
|
||||||
class Subject(models.Model):
|
|
||||||
class Meta:
|
|
||||||
ordering = ['name']
|
|
||||||
|
|
||||||
name = models.CharField(max_length=250)
|
|
||||||
description = models.CharField(max_length=250, blank=True)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self.name
|
|
||||||
|
|
||||||
def get_absolute_url(self):
|
|
||||||
return reverse('subject-detail', kwargs={'pk': self.pk})
|
|
||||||
|
|
||||||
|
|
||||||
class Component(models.Model):
|
|
||||||
class Meta:
|
|
||||||
ordering = ['due_date']
|
|
||||||
|
|
||||||
CATEGORY_CHOICES = [
|
|
||||||
('QZ', 'Quiz'),
|
|
||||||
('AS', 'Assignment'),
|
|
||||||
('TS', 'Test'),
|
|
||||||
]
|
|
||||||
|
|
||||||
subject = models.ForeignKey(Subject, on_delete=models.CASCADE)
|
|
||||||
name = models.CharField(max_length=50)
|
|
||||||
category = models.CharField(
|
|
||||||
max_length = 2,
|
|
||||||
choices = CATEGORY_CHOICES,
|
|
||||||
default='AS',
|
|
||||||
)
|
|
||||||
due_date = models.DateField()
|
|
||||||
grade_total = models.PositiveIntegerField()
|
|
||||||
tags = models.ManyToManyField(Tag, blank=True)
|
|
||||||
finished_grading = models.BooleanField(default=False)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def is_due(self):
|
|
||||||
if self.due_date < date.today():
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
return False
|
|
||||||
|
|
||||||
@property
|
|
||||||
def grade_avg(self):
|
|
||||||
avg = Score.objects.filter(component=self.pk).aggregate(
|
|
||||||
Avg('value')
|
|
||||||
)
|
|
||||||
if avg['value__avg'] is not None:
|
|
||||||
return round(avg['value__avg'], 2)
|
|
||||||
else:
|
|
||||||
return "No scores yet."
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self.name
|
|
||||||
|
|
||||||
def get_absolute_url(self):
|
|
||||||
return reverse('component-detail', kwargs={'pk': self.pk})
|
|
||||||
|
|
||||||
|
|
||||||
class Score(models.Model):
|
|
||||||
class Meta:
|
|
||||||
ordering = ('student',)
|
|
||||||
|
|
||||||
component = models.ForeignKey(Component, on_delete=models.CASCADE)
|
|
||||||
student = models.ForeignKey(Student, on_delete=models.CASCADE)
|
|
||||||
value = models.PositiveIntegerField()
|
|
||||||
|
|
||||||
@property
|
|
||||||
def grade(self):
|
|
||||||
return f"{self.value} / {self.component.grade_total}"
|
|
||||||
|
|
||||||
@property
|
|
||||||
def grade_as_percentage(self):
|
|
||||||
return round(self.value / self.component.grade_total * 100, 2)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return f"{self.student} scored: {self.value} / {self.component.grade_total}"
|
|
||||||
|
|
||||||
def get_absolute_url(self):
|
|
||||||
return reverse('score-detail', kwargs={'pk': self.pk})
|
|
||||||
@ -1,13 +0,0 @@
|
|||||||
{% extends "base.html" %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<article class="panel">
|
|
||||||
<h1>Delete {{component}}</h1>
|
|
||||||
<form method="post" action="{% url 'component-delete' component.subject.pk component.pk %}">
|
|
||||||
{% csrf_token %}
|
|
||||||
<p>
|
|
||||||
<input class="action-button action-delete" type="submit" value="Confirm Delete {{component}}"> or <a href="{% url 'component-detail' component.subject.pk component.pk %}">cancel</a>
|
|
||||||
</p>
|
|
||||||
</form>
|
|
||||||
</article>
|
|
||||||
{% endblock %}
|
|
||||||
@ -1,17 +0,0 @@
|
|||||||
{% extends "base.html" %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<article class="panel">
|
|
||||||
<h1>{{subject}}</h1>
|
|
||||||
<h2>Create Component</h2>
|
|
||||||
<section>
|
|
||||||
<form action="{% url 'component-create' subject.pk %}" method="POST">
|
|
||||||
{% csrf_token %}
|
|
||||||
{{form.as_p}}
|
|
||||||
<p>
|
|
||||||
<input class="action-button" type="submit" value="Create component"> or <a href="{% url 'subject-detail' subject.pk %}">cancel</a>
|
|
||||||
</p>
|
|
||||||
</form>
|
|
||||||
</section>
|
|
||||||
</article>
|
|
||||||
{% endblock %}
|
|
||||||
@ -1,77 +0,0 @@
|
|||||||
{% extends "base.html" %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<article class="panel">
|
|
||||||
<header class="generic__header">
|
|
||||||
<h1>{{component.name}}</h1>
|
|
||||||
<a href="{% url 'component-update' component.subject.pk component.pk %}" class="action-button">Update Component</a>
|
|
||||||
</header>
|
|
||||||
{% if component.finished_grading %}
|
|
||||||
<section>
|
|
||||||
<p>
|
|
||||||
<span class="component__grade--graded">✓ Graded</span>
|
|
||||||
</p>
|
|
||||||
</section>
|
|
||||||
{% endif %}
|
|
||||||
{% if component.tags.count > 0 %}
|
|
||||||
<section>
|
|
||||||
<span>
|
|
||||||
{% for tag in component.tags.all %}
|
|
||||||
<a class="tag__item" href="{% url 'tag-detail' tag.pk %}">{{tag.name}}</a>
|
|
||||||
{% endfor %}
|
|
||||||
</span>
|
|
||||||
</section>
|
|
||||||
{% endif %}
|
|
||||||
<section>
|
|
||||||
<dl>
|
|
||||||
<dt>Due Date</dt>
|
|
||||||
<dd>{{component.due_date}}</dd>
|
|
||||||
<dt>Description</dt>
|
|
||||||
<dd>{{component.name}}</dd>
|
|
||||||
<dt>Category</dt>
|
|
||||||
<dd>{{component.get_category_display}}</dd>
|
|
||||||
<dt>Grade Total</dt>
|
|
||||||
<dd>{{component.grade_total}}</dd>
|
|
||||||
</dl>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<h3>Scores</h3>
|
|
||||||
<p>
|
|
||||||
<a class="action-button" href="{% url 'component-manager' component.subject.pk component.pk %}">Bulk Edit Scores</a>
|
|
||||||
</p>
|
|
||||||
<table>
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<td>Student</td>
|
|
||||||
<td colspan="2">Score</td>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{% for score in component.score_set.all %}
|
|
||||||
<tr>
|
|
||||||
<td><a href="{% url 'student-detail' score.student.pk %}">{{score.student.student_id}} — {{score.student}}</a></td>
|
|
||||||
<td>{{score.value}}</td>
|
|
||||||
<td><a href="{% url 'score-update' score.pk %}">Edit score</a></td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
<tr>
|
|
||||||
<td><strong>Avg Score</strong></td>
|
|
||||||
<td><strong>{{component.grade_avg_pre|floatformat:2}}</strong></td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
{% if scoreless %}
|
|
||||||
<section>
|
|
||||||
|
|
||||||
<h3>Scoreless</h3>
|
|
||||||
<ul>
|
|
||||||
{% for student in scoreless %}
|
|
||||||
<li>{{student}}</li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
</section>
|
|
||||||
{% endif %}
|
|
||||||
</section>
|
|
||||||
</article>
|
|
||||||
{% endblock %}
|
|
||||||
@ -1,19 +0,0 @@
|
|||||||
{% extends "base.html" %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<article class="panel">
|
|
||||||
<div class="generic__header">
|
|
||||||
<h1>Update Component</h1>
|
|
||||||
<a class="action-button action-delete" href="{% url 'component-delete' component.subject.pk component.pk %}">Delete Component</a>
|
|
||||||
</div>
|
|
||||||
<section>
|
|
||||||
<form action="{% url 'component-update' component.subject.pk component.pk %}" method="POST">
|
|
||||||
{% csrf_token %}
|
|
||||||
{{form.as_p}}
|
|
||||||
<p>
|
|
||||||
<input class="action-button" type="submit" value="Save changes"> or <a href="{% url 'component-detail' component.subject.pk component.pk %}">cancel</a>
|
|
||||||
</p>
|
|
||||||
</form>
|
|
||||||
</section>
|
|
||||||
</article>
|
|
||||||
{% endblock %}
|
|
||||||
@ -1,41 +0,0 @@
|
|||||||
{% extends "base.html" %}
|
|
||||||
{% load gradebook_filters %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<article class="panel">
|
|
||||||
<h1>{{component}}, <em>{{component.subject}}</em></h1>
|
|
||||||
<section>
|
|
||||||
<form action="{% url 'component-manager' component.subject.pk component.pk %}" method="POST">
|
|
||||||
{% csrf_token %}
|
|
||||||
<h3>Enter Scores</h3>
|
|
||||||
<table>
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<td>Out of:</td>
|
|
||||||
<td>{{component.grade_total}}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>Student</td>
|
|
||||||
<td>Score</td>
|
|
||||||
{% if formset.errors %}
|
|
||||||
<td>Errors</td>
|
|
||||||
{% endif %}
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{% for student in student_list %}
|
|
||||||
<tr>
|
|
||||||
<td>{{student.full_name}}</td>
|
|
||||||
<td><input type="number" name="student_{{student.pk}}" min="0" max="{{component.grade_total}}" value="{{student.cscore}}"></td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
{{form.as_p}}
|
|
||||||
<p>
|
|
||||||
<input class="action-button" type="submit" value="Save changes"> or <a href="{% url 'component-detail' component.subject.pk component.pk %}">cancel</a>
|
|
||||||
</p>
|
|
||||||
</form>
|
|
||||||
</section>
|
|
||||||
</article>
|
|
||||||
{% endblock %}
|
|
||||||
@ -1,13 +0,0 @@
|
|||||||
{% extends "base.html" %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<article class="panel">
|
|
||||||
<h1>Delete {{score}}</h1>
|
|
||||||
<form method="post" action="{% url 'score-delete' score.pk %}">
|
|
||||||
{% csrf_token %}
|
|
||||||
<p>
|
|
||||||
<input class="action-button action-delete" type="submit" value="Confirm Delete {{score}}"> or <a href="{% url 'score-detail' score.pk %}">cancel</a>
|
|
||||||
</p>
|
|
||||||
</form>
|
|
||||||
</article>
|
|
||||||
{% endblock %}
|
|
||||||
@ -1,16 +0,0 @@
|
|||||||
{% extends "base.html" %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<article class="panel">
|
|
||||||
<h1>Create Score</h1>
|
|
||||||
<section>
|
|
||||||
<form action="{% url 'score-create' %}" method="POST">
|
|
||||||
{% csrf_token %}
|
|
||||||
{{form.as_p}}
|
|
||||||
<p>
|
|
||||||
<input class="action-button" type="submit" value="Create Score"> or <a href="{% url 'subject-list' %}">cancel</a>
|
|
||||||
</p>
|
|
||||||
</form>
|
|
||||||
</section>
|
|
||||||
</article>
|
|
||||||
{% endblock %}
|
|
||||||
@ -1,19 +0,0 @@
|
|||||||
{% extends "base.html" %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<article class="panel">
|
|
||||||
<h1>Update Score</h1>
|
|
||||||
<h2>{{score.component.subject}}— <em>{{score.component.get_category_display}}</em>: {{score.component}}</h2>
|
|
||||||
<section>
|
|
||||||
<form action="{% url 'score-update' score.pk %}" method="POST">
|
|
||||||
{% csrf_token %}
|
|
||||||
<input type="hidden" name="next" value="{{next}}">
|
|
||||||
<h3>{{score.student}}</h3>
|
|
||||||
{{form.as_p}}
|
|
||||||
<p>
|
|
||||||
<input class="action-button" type="submit" value="Save changes"> or <a href="{% url 'student-detail' score.student.pk %}">cancel</a>
|
|
||||||
</p>
|
|
||||||
</form>
|
|
||||||
</section>
|
|
||||||
</article>
|
|
||||||
{% endblock %}
|
|
||||||
@ -1,83 +0,0 @@
|
|||||||
{% extends "base.html" %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<article class="panel">
|
|
||||||
<h1>Search Results</h1>
|
|
||||||
{% if student_list.count > 0 %}
|
|
||||||
<section>
|
|
||||||
<h3>Students</h3>
|
|
||||||
<ul>
|
|
||||||
{% for student in student_list %}
|
|
||||||
<li class="student">
|
|
||||||
<a class="student__li" href="{% url 'student-detail' student.pk %}">{{student.student_id}} — {{student.full_name}}</a>
|
|
||||||
{% if student.sit %}
|
|
||||||
<span class="student__attribute">SIT: {{student.get_sit_display}}</span>
|
|
||||||
{% endif %}
|
|
||||||
{% if student.iep_behavioral %}
|
|
||||||
<span class="student__attribute">IEP behavioral</span>
|
|
||||||
{% endif %}
|
|
||||||
{% if student.iep_math %}
|
|
||||||
<span class="student__attribute">IEP math</span>
|
|
||||||
{% endif %}
|
|
||||||
{% if student.iep_ela %}
|
|
||||||
<span class="student__attribute">IEP ELA</span>
|
|
||||||
{% endif %}
|
|
||||||
{% if student.parent__count > 0 %}
|
|
||||||
<br>Parents:
|
|
||||||
{% for parent in student.parent_set.all %}
|
|
||||||
<a href="{% url 'parent-detail' parent.pk %}">{{parent.full_name}}</a>{% if not forloop.last %},{% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
{% endif %}
|
|
||||||
</li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
</section>
|
|
||||||
{% endif %}
|
|
||||||
{% if component_list.count > 0 %}
|
|
||||||
<section>
|
|
||||||
<h3>Components</h3>
|
|
||||||
<ul class="search__results">
|
|
||||||
<li class="search__result">
|
|
||||||
<strong>Subject</strong>
|
|
||||||
<strong>Component</strong>
|
|
||||||
<strong>Due Date</strong>
|
|
||||||
<strong>Tags</strong>
|
|
||||||
</li>
|
|
||||||
<hr>
|
|
||||||
{% for component in component_list %}
|
|
||||||
<li class="search__result">
|
|
||||||
{{component.subject}}
|
|
||||||
<a href="{% url 'component-detail' component.subject.pk component.pk %}">{{component}}</a>
|
|
||||||
<span>{{component.due_date}}</span>
|
|
||||||
<span>
|
|
||||||
{% for tag in component.tags.all %}
|
|
||||||
<a class="tag__item" href="{% url 'tag-detail' tag.pk %}">{{tag.name}}</a>
|
|
||||||
{% endfor %}
|
|
||||||
</span>
|
|
||||||
</li>
|
|
||||||
{% empty %}
|
|
||||||
<p>No components by that name were found.</p>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
</section>
|
|
||||||
{% endif %}
|
|
||||||
{% if message_list.count > 0 %}
|
|
||||||
<section>
|
|
||||||
<h3>Messages</h3>
|
|
||||||
<ul class="search__results">
|
|
||||||
{% for message in message_list %}
|
|
||||||
<li class="search__mresult">
|
|
||||||
<p>
|
|
||||||
<a href="{% url 'thread-detail' message.thread.pk %}">{{message.thread.subject}}</a><br>
|
|
||||||
{{message.content|truncatewords:25}}<br>
|
|
||||||
<a class="" href="{% url 'thread-detail' message.thread.pk %}">Read more →</a>
|
|
||||||
</p>
|
|
||||||
</li>
|
|
||||||
{% empty %}
|
|
||||||
<p>No components by that name were found.</p>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
</section>
|
|
||||||
{% endif %}
|
|
||||||
</article>
|
|
||||||
{% endblock %}
|
|
||||||
@ -1,13 +0,0 @@
|
|||||||
{% extends "base.html" %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<article class="panel">
|
|
||||||
<h1>Delete {{subject}} Subject</h1>
|
|
||||||
<form method="post" action="{% url 'subject-delete' subject.pk %}">
|
|
||||||
{% csrf_token %}
|
|
||||||
<p>
|
|
||||||
<input class="action-button action-delete" type="submit" value="Confirm Delete {{subject}}"> or <a href="{% url 'subject-list' %}">cancel</a>
|
|
||||||
</p>
|
|
||||||
</form>
|
|
||||||
</article>
|
|
||||||
{% endblock %}
|
|
||||||
@ -1,16 +0,0 @@
|
|||||||
{% extends "base.html" %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<article class="panel">
|
|
||||||
<h1>Create Subject</h1>
|
|
||||||
<section>
|
|
||||||
<form action="{% url 'subject-create' %}" method="POST">
|
|
||||||
{% csrf_token %}
|
|
||||||
{{form.as_p}}
|
|
||||||
<p>
|
|
||||||
<input class="action-button" type="submit" value="Create Subject"> or <a href="{% url 'subject-list' %}">cancel</a>
|
|
||||||
</p>
|
|
||||||
</form>
|
|
||||||
</section>
|
|
||||||
</article>
|
|
||||||
{% endblock %}
|
|
||||||
@ -1,41 +0,0 @@
|
|||||||
{% extends "base.html" %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<article class="panel">
|
|
||||||
<div class="generic__header">
|
|
||||||
<h1>{{subject.name}}</h1>
|
|
||||||
<a class="action-button" href="{% url 'subject-update' subject.pk %}">Update subject details</a>
|
|
||||||
</div>
|
|
||||||
{% if subject.description %}
|
|
||||||
<span>{{subject.description}}</span>
|
|
||||||
{% endif %}
|
|
||||||
<section>
|
|
||||||
<h3>Syllabus</h3>
|
|
||||||
<p>
|
|
||||||
<a href="{% url 'component-create' subject.pk %}" class="action-button">+ New component</a>
|
|
||||||
</p>
|
|
||||||
<table>
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<td>Due Date</td>
|
|
||||||
<td>Description</td>
|
|
||||||
<td>Category</td>
|
|
||||||
<td>Grade Total</td>
|
|
||||||
<td>Avg Score</td>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{% for component in subject.component_set.all %}
|
|
||||||
<tr>
|
|
||||||
<td>{{component.due_date}}</td>
|
|
||||||
<td><a href="{% url 'component-detail' subject.pk component.pk %}">{{component.name}}</a></td>
|
|
||||||
<td>{{component.get_category_display}}</td>
|
|
||||||
<td>{{component.grade_total}}</td>
|
|
||||||
<td>{{component.grade_avg_pre|floatformat:2}}</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</section>
|
|
||||||
</article>
|
|
||||||
{% endblock %}
|
|
||||||
@ -1,19 +0,0 @@
|
|||||||
{% extends "base.html" %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<article class="panel">
|
|
||||||
<div class="generic__header">
|
|
||||||
<h1>Update Subject</h1>
|
|
||||||
<a class="action-button action-delete" href="{% url 'subject-delete' subject.pk %}">Delete subject</a>
|
|
||||||
</div>
|
|
||||||
<section>
|
|
||||||
<form action="{% url 'subject-update' subject.pk %}" method="POST">
|
|
||||||
{% csrf_token %}
|
|
||||||
{{form.as_p}}
|
|
||||||
<p>
|
|
||||||
<input class="action-button" type="submit" value="Save changes"> or <a href="{% url 'subject-detail' subject.pk %}">cancel</a>
|
|
||||||
</p>
|
|
||||||
</form>
|
|
||||||
</section>
|
|
||||||
</article>
|
|
||||||
{% endblock %}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user