update
This commit is contained in:
1 parent
c738c1746a
commit
0504b881fb
30 files changed
+1296
-122
No files matched your search
+61
-3
@@ -10,6 +10,8 @@ from app.models import (
|
||||
Attendance,
|
||||
Result,
|
||||
Library,
|
||||
Marksheet,
|
||||
SubjectMark,
|
||||
)
|
||||
|
||||
|
||||
@@ -39,6 +41,7 @@ class StudentAdmin(BaseUserAdmin):
|
||||
"last_name",
|
||||
"father_name",
|
||||
"mother_name",
|
||||
"guardian_name",
|
||||
"email",
|
||||
"phone",
|
||||
"course",
|
||||
@@ -73,7 +76,7 @@ class StaffAdmin(BaseUserAdmin):
|
||||
|
||||
@admin.register(Course)
|
||||
class CourseAdmin(admin.ModelAdmin):
|
||||
list_display = ("id", "name", "course_type", "duration")
|
||||
list_display = ("id", "name", "level", "course_type", "duration")
|
||||
search_fields = ("name",)
|
||||
list_filter = ("course_type",)
|
||||
|
||||
@@ -93,7 +96,7 @@ class SubjectAdmin(admin.ModelAdmin):
|
||||
|
||||
@admin.register(NewsEvent)
|
||||
class NewsEventAdmin(admin.ModelAdmin):
|
||||
list_display = ("id", "title", "type", "created_at")
|
||||
list_display = ("id", "title", "summary", "type", "created_at")
|
||||
search_fields = ("title", "summary")
|
||||
list_filter = ("type", "created_at")
|
||||
|
||||
@@ -121,4 +124,59 @@ class ResultAdmin(admin.ModelAdmin):
|
||||
|
||||
@admin.register(Library)
|
||||
class LibraryAdmin(admin.ModelAdmin):
|
||||
list_display = ("book_name", "author", "publication_year")
|
||||
list_display = ("book_name", "publication", "publication_year", "available")
|
||||
|
||||
|
||||
class SubjectMarkInline(admin.TabularInline):
|
||||
model = SubjectMark
|
||||
extra = 1
|
||||
fields = (
|
||||
"subject",
|
||||
"obtained_theory_marks",
|
||||
"total_theory_marks",
|
||||
"obtained_practical_marks",
|
||||
"total_practical_marks",
|
||||
"total_marks",
|
||||
)
|
||||
readonly_fields = ("total_marks",)
|
||||
|
||||
|
||||
@admin.register(Marksheet)
|
||||
class MarksheetAdmin(admin.ModelAdmin):
|
||||
inlines = [SubjectMarkInline]
|
||||
list_display = ["student", "course", "total_marks", "obtained_marks", "grade"]
|
||||
readonly_fields = ["total_marks", "obtained_marks", "grade"]
|
||||
|
||||
|
||||
# class SubjectMarkInline(admin.TabularInline):
|
||||
# model = SubjectMark
|
||||
# extra = 1
|
||||
# fields = (
|
||||
# "subject",
|
||||
# "obtained_theory_marks",
|
||||
# "total_theory_marks",
|
||||
# "obtained_practical_marks",
|
||||
# "total_practical_marks",
|
||||
# "total_marks",
|
||||
# )
|
||||
# readonly_fields = ("total_marks",)
|
||||
#
|
||||
#
|
||||
# @admin.register(Marksheet)
|
||||
# class MarksheetAdmin(admin.ModelAdmin):
|
||||
# list_display = ["student", "course", "total_marks", "obtained_marks", "grade"]
|
||||
# list_filter = ["grade", "course"]
|
||||
# search_fields = ["student__first_name", "student__last_name", "course__name"]
|
||||
# readonly_fields = ["total_marks", "obtained_marks", "grade"]
|
||||
# inlines = [SubjectMarkInline]
|
||||
#
|
||||
# fieldsets = (
|
||||
# ("Student Information", {"fields": ("student", "course")}),
|
||||
# (
|
||||
# "Results",
|
||||
# {
|
||||
# "fields": ("total_marks", "obtained_marks", "grade"),
|
||||
# "classes": ("collapse",),
|
||||
# },
|
||||
# ),
|
||||
# )
|
||||
+2
-2
@@ -2,5 +2,5 @@ from django.apps import AppConfig
|
||||
|
||||
|
||||
class AppConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'app'
|
||||
default_auto_field = "django.db.models.BigAutoField"
|
||||
name = "app"
|
||||
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 5.1.4 on 2025-01-08 05:51
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('app', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RenameField(
|
||||
model_name='library',
|
||||
old_name='author',
|
||||
new_name='publication',
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,72 @@
|
||||
# Generated by Django 5.1.4 on 2025-01-08 07:33
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('app', '0002_rename_author_library_publication'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='course',
|
||||
name='level',
|
||||
field=models.CharField(choices=[('basic', 'Basic'), ('primary', 'Primary'), ('secondary', 'Secondary'), ('vocational traning', 'Vocational Traning'), ('higher secondary', 'Higher Secondary'), ('graduation', 'Graduation'), ('post graduation', 'Post Graduation')], max_length=45),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='staff',
|
||||
name='position',
|
||||
field=models.CharField(choices=[('lab Assistant', 'Lab Assistant'), ('librarian', 'Librarian'), ('accountant', 'Accountant'), ('guard', 'Guard'), ('driver', 'Driver'), ('helper', 'Helper'), ('cleaner', 'Cleaner')], max_length=255),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='student',
|
||||
name='father_occupation',
|
||||
field=models.CharField(choices=[('agriculture', 'Agriculture'), ('banker', 'Banker'), ('business', 'Business'), ('doctor', 'Doctor'), ('farmer', 'Farmer'), ('fisherman', 'Fisherman'), ('public service', 'Public Service'), ('private service', 'Private Service'), ('shopkeeper', 'Shopkeeper'), ('driver', 'Driver'), ('worker', 'Worker'), ('N/A', 'N/A')], default='N/A', max_length=45),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='student',
|
||||
name='mother_occupation',
|
||||
field=models.CharField(choices=[('agriculture', 'Agriculture'), ('banker', 'Banker'), ('business', 'Business'), ('doctor', 'Doctor'), ('farmer', 'Farmer'), ('fisherman', 'Fisherman'), ('public service', 'Public Service'), ('private service', 'Private Service'), ('shopkeeper', 'Shopkeeper'), ('driver', 'Driver'), ('houseWife', 'HouseWife'), ('worker', 'Worker'), ('N/A', 'N/A')], default='N/A', max_length=45),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='student',
|
||||
name='relationship_with_student',
|
||||
field=models.CharField(choices=[('father', 'Father'), ('mother', 'Mother'), ('brother', 'Brother'), ('sister', 'Sister'), ('uncle', 'Uncle'), ('aunt', 'Aunt'), ('grandfather', 'Grandfather')], max_length=45),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Certificate',
|
||||
fields=[
|
||||
('id', models.AutoField(primary_key=True, serialize=False)),
|
||||
('title', models.CharField(max_length=255)),
|
||||
('description', models.TextField(blank=True, null=True)),
|
||||
('issue_date', models.DateField(auto_now_add=True)),
|
||||
('course', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='app.course')),
|
||||
('student', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='app.student')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Certificate',
|
||||
'verbose_name_plural': 'Certificate',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Marksheet',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('marks_obtained', models.DecimalField(decimal_places=2, max_digits=5)),
|
||||
('total_marks', models.DecimalField(decimal_places=2, max_digits=5)),
|
||||
('grade', models.CharField(blank=True, max_length=2, null=True)),
|
||||
('exam_date', models.DateField()),
|
||||
('course', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='marksheets', to='app.course')),
|
||||
('student', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='marksheets', to='app.student')),
|
||||
('subject', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='marksheets', to='app.subject')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Marksheet',
|
||||
'verbose_name_plural': 'Marksheets',
|
||||
'unique_together': {('student', 'course', 'subject')},
|
||||
},
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,34 @@
|
||||
# Generated by Django 5.1.4 on 2025-01-08 07:39
|
||||
|
||||
import django.core.validators
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('app', '0003_alter_course_level_alter_staff_position_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='marksheet',
|
||||
name='exam_date',
|
||||
field=models.DateField(help_text='Date of the examination'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='marksheet',
|
||||
name='grade',
|
||||
field=models.CharField(blank=True, choices=[('A+', 'Excellent'), ('A', 'Very Good'), ('B', 'Good'), ('C', 'Average'), ('D', 'Below Average'), ('F', 'Fail')], help_text='Grade assigned based on marks', max_length=2, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='marksheet',
|
||||
name='marks_obtained',
|
||||
field=models.PositiveIntegerField(help_text='Marks obtained by the student', validators=[django.core.validators.MinValueValidator(0)]),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='marksheet',
|
||||
name='total_marks',
|
||||
field=models.PositiveIntegerField(help_text='Total marks for the subject', validators=[django.core.validators.MinValueValidator(1)]),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,19 @@
|
||||
# Generated by Django 5.1.4 on 2025-01-08 07:51
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('app', '0004_alter_marksheet_exam_date_alter_marksheet_grade_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='marksheet',
|
||||
name='subj_result',
|
||||
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='app.result'),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,25 @@
|
||||
# Generated by Django 5.1.4 on 2025-01-08 07:53
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('app', '0005_marksheet_subj_result'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterUniqueTogether(
|
||||
name='marksheet',
|
||||
unique_together={('student', 'course')},
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='marksheet',
|
||||
name='exam_date',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='marksheet',
|
||||
name='subject',
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,46 @@
|
||||
# Generated by Django 5.1.4 on 2025-01-08 08:29
|
||||
|
||||
import django.core.validators
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('app', '0006_alter_marksheet_unique_together_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='marksheet',
|
||||
name='marks_obtained',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='marksheet',
|
||||
name='subj_result',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='marksheet',
|
||||
name='obtained_marks',
|
||||
field=models.PositiveIntegerField(default=0, help_text='Total marks obtained by the student', validators=[django.core.validators.MinValueValidator(0)]),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='marksheet',
|
||||
name='total_marks',
|
||||
field=models.PositiveIntegerField(help_text='Total marks for the course', validators=[django.core.validators.MinValueValidator(1)]),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='SubjectMark',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('marks_obtained', models.PositiveIntegerField(help_text='Marks obtained in this subject', validators=[django.core.validators.MinValueValidator(0)])),
|
||||
('total_marks', models.PositiveIntegerField(help_text='Total marks for this subject', validators=[django.core.validators.MinValueValidator(1)])),
|
||||
('marksheet', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='subject_marks', to='app.marksheet')),
|
||||
('subject', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='subject_marks', to='app.subject')),
|
||||
],
|
||||
options={
|
||||
'unique_together': {('marksheet', 'subject')},
|
||||
},
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,43 @@
|
||||
# Generated by Django 5.1.4 on 2025-01-08 08:42
|
||||
|
||||
from decimal import Decimal
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('app', '0007_remove_marksheet_marks_obtained_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='subjectmark',
|
||||
name='marks_obtained',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='subjectmark',
|
||||
name='obtained_practical_marks',
|
||||
field=models.DecimalField(decimal_places=2, default=Decimal('0.00'), max_digits=5),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='subjectmark',
|
||||
name='obtained_theory_marks',
|
||||
field=models.DecimalField(decimal_places=2, default=Decimal('0.00'), max_digits=5),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='subjectmark',
|
||||
name='total_practical_marks',
|
||||
field=models.DecimalField(decimal_places=2, default=Decimal('20.00'), max_digits=5),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='subjectmark',
|
||||
name='total_theory_marks',
|
||||
field=models.DecimalField(decimal_places=2, default=Decimal('80.00'), max_digits=5),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='subjectmark',
|
||||
name='total_marks',
|
||||
field=models.DecimalField(decimal_places=2, default=Decimal('0.00'), editable=False, max_digits=5),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,19 @@
|
||||
# Generated by Django 5.1.4 on 2025-01-08 08:43
|
||||
|
||||
from decimal import Decimal
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('app', '0008_remove_subjectmark_marks_obtained_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='subjectmark',
|
||||
name='total_marks',
|
||||
field=models.DecimalField(decimal_places=2, default=Decimal('0.00'), max_digits=5),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,19 @@
|
||||
# Generated by Django 5.1.4 on 2025-01-08 08:51
|
||||
|
||||
import django.core.validators
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('app', '0009_alter_subjectmark_total_marks'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='marksheet',
|
||||
name='total_marks',
|
||||
field=models.PositiveIntegerField(default=0, help_text='Total marks for the course', validators=[django.core.validators.MinValueValidator(1)]),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,19 @@
|
||||
# Generated by Django 5.1.4 on 2025-01-08 08:53
|
||||
|
||||
import django.core.validators
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('app', '0010_alter_marksheet_total_marks'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='marksheet',
|
||||
name='total_marks',
|
||||
field=models.PositiveIntegerField(help_text='Total marks for the course', validators=[django.core.validators.MinValueValidator(1)]),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,25 @@
|
||||
# Generated by Django 5.1.4 on 2025-01-08 09:01
|
||||
|
||||
import django.core.validators
|
||||
from decimal import Decimal
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('app', '0011_alter_marksheet_total_marks'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='marksheet',
|
||||
name='obtained_marks',
|
||||
field=models.PositiveIntegerField(default=Decimal('0.00'), editable=False, help_text='Total marks obtained by the student', validators=[django.core.validators.MinValueValidator(0)]),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='marksheet',
|
||||
name='total_marks',
|
||||
field=models.PositiveIntegerField(default=Decimal('0.00'), editable=False, help_text='Total marks for the course', validators=[django.core.validators.MinValueValidator(1)]),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,30 @@
|
||||
# Generated by Django 5.1.4 on 2025-01-08 09:16
|
||||
|
||||
import django.core.validators
|
||||
from decimal import Decimal
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('app', '0012_alter_marksheet_obtained_marks_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='marksheet',
|
||||
name='grade',
|
||||
field=models.CharField(blank=True, choices=[('A+', 'Excellent'), ('A', 'Very Good'), ('B+', 'Good'), ('B', ''), ('C+', 'Average'), ('C', ''), ('D+', 'Below Average'), ('D', 'Fail')], help_text='Grade assigned based on marks', max_length=2, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='marksheet',
|
||||
name='obtained_marks',
|
||||
field=models.PositiveIntegerField(default=Decimal('0.00'), help_text='Total marks obtained by the student', validators=[django.core.validators.MinValueValidator(0)]),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='marksheet',
|
||||
name='total_marks',
|
||||
field=models.PositiveIntegerField(default=Decimal('0.00'), help_text='Total marks for the course', validators=[django.core.validators.MinValueValidator(1)]),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 5.1.4 on 2025-01-08 09:17
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('app', '0013_alter_marksheet_grade_alter_marksheet_obtained_marks_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='marksheet',
|
||||
name='grade',
|
||||
field=models.CharField(blank=True, choices=[('A+', 'Excellent'), ('A', 'Very Good'), ('B+', 'Good'), ('B', 'G'), ('C+', 'Average'), ('C', 'A'), ('D+', 'Below Average'), ('D', 'Fail')], help_text='Grade assigned based on marks', max_length=2, null=True),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 5.1.4 on 2025-01-08 09:21
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('app', '0014_alter_marksheet_grade'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='marksheet',
|
||||
name='grade',
|
||||
field=models.CharField(blank=True, choices=[('A+', 'Outstanding'), ('A', 'Excellent'), ('B+', 'Very Good'), ('B', 'Good'), ('C+', 'Above Average'), ('C', 'Average'), ('D', 'Below Average'), ('E', 'Fail')], help_text='Grade assigned based on marks', max_length=2, null=True),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 5.1.4 on 2025-01-08 09:24
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('app', '0015_alter_marksheet_grade'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='marksheet',
|
||||
name='grade',
|
||||
field=models.CharField(blank=True, choices=[('A+', 'A+'), ('A', 'A'), ('B+', 'B+'), ('B', 'B'), ('C+', 'C+'), ('C', 'C'), ('D', 'D'), ('E', 'E')], help_text='Grade assigned based on marks', max_length=2, null=True),
|
||||
),
|
||||
]
|
||||
+259
-53
@@ -5,6 +5,7 @@ from django.contrib.auth.hashers import make_password
|
||||
import random
|
||||
from decimal import Decimal
|
||||
from datetime import time, timedelta, datetime
|
||||
from django.core.validators import MinValueValidator, MaxValueValidator
|
||||
|
||||
|
||||
# Abstract BaseUser Model
|
||||
@@ -19,7 +20,6 @@ class BaseUser(models.Model):
|
||||
)
|
||||
username = models.CharField(max_length=255, unique=True, blank=True, null=True)
|
||||
password = models.CharField(max_length=255)
|
||||
address = models.CharField(max_length=255)
|
||||
group = models.ManyToManyField(Group, blank=True)
|
||||
user = models.OneToOneField(User, on_delete=models.CASCADE, null=True, blank=True)
|
||||
|
||||
@@ -42,7 +42,6 @@ class BaseUser(models.Model):
|
||||
email=self.email,
|
||||
first_name=self.first_name,
|
||||
last_name=self.last_name,
|
||||
address=self.address,
|
||||
is_staff=True,
|
||||
is_active=self.active_status,
|
||||
password=self.password,
|
||||
@@ -52,7 +51,6 @@ class BaseUser(models.Model):
|
||||
self.user.email = self.email
|
||||
self.user.first_name = self.first_name
|
||||
self.user.last_name = self.last_name
|
||||
self.user.address = self.address
|
||||
self.user.is_active = self.active_status
|
||||
self.user.is_staff = True
|
||||
self.user.password = self.password
|
||||
@@ -103,6 +101,7 @@ class Teacher(BaseUser):
|
||||
class Student(BaseUser):
|
||||
date_of_birth = models.DateField(blank=False)
|
||||
gender = models.CharField(max_length=1, choices=[("M", "Male"), ("F", "Female")])
|
||||
address = models.CharField(max_length=255)
|
||||
course = models.ForeignKey("Course", on_delete=models.CASCADE)
|
||||
academic_year = models.ForeignKey("AcademicYear", on_delete=models.CASCADE)
|
||||
father_name = models.CharField(max_length=100)
|
||||
@@ -111,17 +110,17 @@ class Student(BaseUser):
|
||||
)
|
||||
father_email = models.EmailField(blank=True, null=True)
|
||||
father_occupation_choice = (
|
||||
("Agriculture", "Agriculture"),
|
||||
("Banker", "Banker"),
|
||||
("Business", "Business"),
|
||||
("Doctor", "Doctor"),
|
||||
("Farmer", "Farmer"),
|
||||
("Fisherman", "Fisherman"),
|
||||
("Public Service", "Public Service"),
|
||||
("Private Service", "Private Service"),
|
||||
("Shopkeeper", "Shopkeeper"),
|
||||
("Driver", "Driver"),
|
||||
("Worker", "Worker"),
|
||||
("agriculture", "Agriculture"),
|
||||
("banker", "Banker"),
|
||||
("business", "Business"),
|
||||
("doctor", "Doctor"),
|
||||
("farmer", "Farmer"),
|
||||
("fisherman", "Fisherman"),
|
||||
("public service", "Public Service"),
|
||||
("private service", "Private Service"),
|
||||
("shopkeeper", "Shopkeeper"),
|
||||
("driver", "Driver"),
|
||||
("worker", "Worker"),
|
||||
("N/A", "N/A"),
|
||||
)
|
||||
father_occupation = models.CharField(
|
||||
@@ -136,18 +135,18 @@ class Student(BaseUser):
|
||||
)
|
||||
mother_email = models.EmailField(blank=True, null=True)
|
||||
mother_occupation_choice = (
|
||||
("Agriculture", "Agriculture"),
|
||||
("Banker", "Banker"),
|
||||
("Business", "Business"),
|
||||
("Doctor", "Doctor"),
|
||||
("Farmer", "Farmer"),
|
||||
("Fisherman", "Fisherman"),
|
||||
("Public Service", "Public Service"),
|
||||
("Private Service", "Private Service"),
|
||||
("Shopkeeper", "Shopkeeper"),
|
||||
("Driver", "Driver"),
|
||||
("HouseWife", "HouseWife"),
|
||||
("Worker", "Worker"),
|
||||
("agriculture", "Agriculture"),
|
||||
("banker", "Banker"),
|
||||
("business", "Business"),
|
||||
("doctor", "Doctor"),
|
||||
("farmer", "Farmer"),
|
||||
("fisherman", "Fisherman"),
|
||||
("public service", "Public Service"),
|
||||
("private service", "Private Service"),
|
||||
("shopkeeper", "Shopkeeper"),
|
||||
("driver", "Driver"),
|
||||
("houseWife", "HouseWife"),
|
||||
("worker", "Worker"),
|
||||
("N/A", "N/A"),
|
||||
)
|
||||
mother_occupation = models.CharField(
|
||||
@@ -159,13 +158,13 @@ class Student(BaseUser):
|
||||
)
|
||||
guardian_email = models.EmailField(blank=True, null=True)
|
||||
relationship_choice = (
|
||||
("Father", "Father"),
|
||||
("Mother", "Mother"),
|
||||
("Brother", "Brother"),
|
||||
("Sister", "Sister"),
|
||||
("Uncle", "Uncle"),
|
||||
("Aunt", "Aunt"),
|
||||
("Grandfather", "Grandfather"),
|
||||
("father", "Father"),
|
||||
("mother", "Mother"),
|
||||
("brother", "Brother"),
|
||||
("sister", "Sister"),
|
||||
("uncle", "Uncle"),
|
||||
("aunt", "Aunt"),
|
||||
("grandfather", "Grandfather"),
|
||||
)
|
||||
relationship_with_student = models.CharField(
|
||||
choices=relationship_choice, max_length=45
|
||||
@@ -182,13 +181,13 @@ class Staff(BaseUser):
|
||||
position = models.CharField(
|
||||
max_length=255,
|
||||
choices=[
|
||||
("Lab Assistant", "Lab Assistant"),
|
||||
("Librarian", "Librarian"),
|
||||
("Accountant", "Accountant"),
|
||||
("Guard", "Guard"),
|
||||
("Driver", "Driver"),
|
||||
("Helper", "Helper"),
|
||||
("Cleaner", "Cleaner"),
|
||||
("lab Assistant", "Lab Assistant"),
|
||||
("librarian", "Librarian"),
|
||||
("accountant", "Accountant"),
|
||||
("guard", "Guard"),
|
||||
("driver", "Driver"),
|
||||
("helper", "Helper"),
|
||||
("cleaner", "Cleaner"),
|
||||
],
|
||||
)
|
||||
address = models.CharField(max_length=255)
|
||||
@@ -211,13 +210,13 @@ class Staff(BaseUser):
|
||||
class Course(models.Model):
|
||||
name = models.CharField(max_length=100)
|
||||
level_choice = (
|
||||
("Basic", "Basic"),
|
||||
("Primary", "Primary"),
|
||||
("Secondary", "Secondary"),
|
||||
("Vocational Traning", "Vocational Traning"),
|
||||
("Higher Secondary", "Higher Secondary"),
|
||||
("Graduation", "Graduation"),
|
||||
("Post Graduation", "Post Graduation"),
|
||||
("basic", "Basic"),
|
||||
("primary", "Primary"),
|
||||
("secondary", "Secondary"),
|
||||
("vocational traning", "Vocational Traning"),
|
||||
("higher secondary", "Higher Secondary"),
|
||||
("graduation", "Graduation"),
|
||||
("post graduation", "Post Graduation"),
|
||||
)
|
||||
level = models.CharField(choices=level_choice, max_length=45)
|
||||
course_type = models.CharField(
|
||||
@@ -239,7 +238,7 @@ class AcademicYear(models.Model):
|
||||
year = models.CharField(max_length=255, unique=True)
|
||||
|
||||
def __str__(self):
|
||||
return self.batch
|
||||
return self.year
|
||||
|
||||
class Meta:
|
||||
verbose_name = "Academic Year"
|
||||
@@ -271,15 +270,17 @@ class Subject(models.Model):
|
||||
|
||||
# NewsEvent model
|
||||
class NewsEvent(models.Model):
|
||||
class NewsEventType(models.TextChoices):
|
||||
NEWS = "news", "News"
|
||||
EVENT = "event", "Event"
|
||||
|
||||
title = models.CharField(max_length=255)
|
||||
summary = models.TextField()
|
||||
type = models.CharField(
|
||||
max_length=5, choices=[("news", "News"), ("event", "Event")]
|
||||
)
|
||||
type = models.CharField(max_length=5, choices=NewsEventType.choices)
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.title} ({self.get_type_display()})"
|
||||
return f"{self.title} ({self.type})"
|
||||
|
||||
class Meta:
|
||||
verbose_name = "News/Event"
|
||||
@@ -337,7 +338,7 @@ class Library(models.Model):
|
||||
category = models.CharField(max_length=255)
|
||||
book_name = models.CharField(max_length=255)
|
||||
description = models.CharField(max_length=255)
|
||||
author = models.CharField(max_length=255)
|
||||
publication = models.CharField(max_length=255)
|
||||
publication_year = models.PositiveIntegerField()
|
||||
quantity = models.PositiveIntegerField()
|
||||
available = models.CharField(max_length=1, choices=[("Y", "Yes"), ("N", "NO")])
|
||||
@@ -349,3 +350,208 @@ class Library(models.Model):
|
||||
class Meta:
|
||||
verbose_name = "Library"
|
||||
verbose_name_plural = "Library"
|
||||
|
||||
|
||||
class Certificate(models.Model):
|
||||
id = models.AutoField(primary_key=True)
|
||||
student = models.ForeignKey("Student", on_delete=models.CASCADE)
|
||||
course = models.ForeignKey("Course", on_delete=models.CASCADE)
|
||||
title = models.CharField(max_length=255)
|
||||
description = models.TextField(blank=True, null=True)
|
||||
issue_date = models.DateField(auto_now_add=True)
|
||||
|
||||
class Meta:
|
||||
verbose_name = "Certificate"
|
||||
verbose_name_plural = "Certificate"
|
||||
|
||||
|
||||
class Marksheet(models.Model):
|
||||
student = models.ForeignKey(
|
||||
"Student", on_delete=models.CASCADE, related_name="marksheets"
|
||||
)
|
||||
course = models.ForeignKey(
|
||||
"Course", on_delete=models.CASCADE, related_name="marksheets"
|
||||
)
|
||||
total_marks = models.PositiveIntegerField(
|
||||
validators=[MinValueValidator(1)],
|
||||
default=Decimal("0.00"),
|
||||
help_text="Total marks for the course",
|
||||
# editable=False,
|
||||
)
|
||||
obtained_marks = models.PositiveIntegerField(
|
||||
validators=[MinValueValidator(0)],
|
||||
default=Decimal("0.00"),
|
||||
help_text="Total marks obtained by the student",
|
||||
# editable=False,
|
||||
)
|
||||
grade = models.CharField(
|
||||
max_length=2,
|
||||
choices=[
|
||||
# ("A+", "Outstanding"),
|
||||
# ("A", "Excellent"),
|
||||
# ("B+", "Very Good"),
|
||||
# ("B", "Good"),
|
||||
# ("C+", "Above Average"),
|
||||
# ("C", "Average"),
|
||||
# ("D", "Below Average"),
|
||||
# ("E", "Fail"),
|
||||
("A+", "A+"),
|
||||
("A", "A"),
|
||||
("B+", "B+"),
|
||||
("B", "B"),
|
||||
("C+", "C+"),
|
||||
("C", "C"),
|
||||
("D", "D"),
|
||||
("E", "E"),
|
||||
],
|
||||
blank=True,
|
||||
null=True,
|
||||
help_text="Grade assigned based on marks",
|
||||
)
|
||||
|
||||
class Meta:
|
||||
verbose_name = "Marksheet"
|
||||
verbose_name_plural = "Marksheets"
|
||||
unique_together = ("student", "course")
|
||||
|
||||
def calculate_totals(self):
|
||||
subject_marks = self.subject_marks.all()
|
||||
|
||||
total_marks = sum(
|
||||
subject.total_practical_marks + subject.total_theory_marks
|
||||
for subject in subject_marks
|
||||
) or Decimal("0.00")
|
||||
|
||||
obtained_marks = sum(
|
||||
subject.obtained_practical_marks + subject.obtained_theory_marks
|
||||
for subject in subject_marks
|
||||
) or Decimal("0.00")
|
||||
|
||||
return total_marks, obtained_marks
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
if not self.pk:
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
self.total_marks, self.obtained_marks = self.calculate_totals()
|
||||
|
||||
if self.total_marks > 0:
|
||||
percentage = (self.obtained_marks / self.total_marks) * 100
|
||||
if percentage >= 90:
|
||||
self.grade = "A+"
|
||||
elif percentage >= 80:
|
||||
self.grade = "A"
|
||||
elif percentage >= 70:
|
||||
self.grade = "B+"
|
||||
elif percentage >= 60:
|
||||
self.grade = "B"
|
||||
elif percentage >= 50:
|
||||
self.grade = "C+"
|
||||
elif percentage >= 40:
|
||||
self.grade = "C"
|
||||
elif percentage >= 30:
|
||||
self.grade = "D"
|
||||
else:
|
||||
self.grade = "E"
|
||||
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
def __str__(self):
|
||||
return f"Marksheet: {self.student.first_name} {self.student.last_name}"
|
||||
|
||||
|
||||
class SubjectMark(models.Model):
|
||||
marksheet = models.ForeignKey(
|
||||
Marksheet, on_delete=models.CASCADE, related_name="subject_marks"
|
||||
)
|
||||
subject = models.ForeignKey(
|
||||
"Subject", on_delete=models.CASCADE, related_name="subject_marks"
|
||||
)
|
||||
obtained_practical_marks = models.DecimalField(
|
||||
max_digits=5, decimal_places=2, default=Decimal("0.00")
|
||||
)
|
||||
total_practical_marks = models.DecimalField(
|
||||
max_digits=5, decimal_places=2, default=Decimal("20.00")
|
||||
)
|
||||
obtained_theory_marks = models.DecimalField(
|
||||
max_digits=5, decimal_places=2, default=Decimal("0.00")
|
||||
)
|
||||
total_theory_marks = models.DecimalField(
|
||||
max_digits=5, decimal_places=2, default=Decimal("80.00")
|
||||
)
|
||||
total_marks = models.DecimalField(
|
||||
max_digits=5, decimal_places=2, default=Decimal("0.00")
|
||||
)
|
||||
|
||||
def get_total(self):
|
||||
return Decimal(str(self.obtained_practical_marks or 0)) + Decimal(
|
||||
str(self.obtained_theory_marks or 0)
|
||||
)
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
self.total_marks = self.get_total()
|
||||
super().save(*args, **kwargs)
|
||||
self.marksheet.save()
|
||||
|
||||
class Meta:
|
||||
unique_together = ("marksheet", "subject")
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.subject.name} - {self.marksheet.student.first_name}"
|
||||
|
||||
|
||||
# class Marksheet(models.Model):
|
||||
# student = models.ForeignKey(
|
||||
# "Student", on_delete=models.CASCADE, related_name="marksheets"
|
||||
# )
|
||||
# course = models.ForeignKey(
|
||||
# "Course", on_delete=models.CASCADE, related_name="marksheets"
|
||||
# )
|
||||
# subj_result = models.ForeignKey(
|
||||
# "Result", on_delete=models.CASCADE, related_name="marksheets", null=True
|
||||
# )
|
||||
# marks_obtained = models.PositiveIntegerField(
|
||||
# validators=[MinValueValidator(0)], help_text="Marks obtained by the student"
|
||||
# )
|
||||
# total_marks = models.PositiveIntegerField(
|
||||
# validators=[MinValueValidator(1)], help_text="Total marks for the subject"
|
||||
# )
|
||||
# grade = models.CharField(
|
||||
# max_length=2,
|
||||
# choices=[
|
||||
# ("A+", "Excellent"),
|
||||
# ("A", "Very Good"),
|
||||
# ("B", "Good"),
|
||||
# ("C", "Average"),
|
||||
# ("D", "Below Average"),
|
||||
# ("F", "Fail"),
|
||||
# ],
|
||||
# blank=True,
|
||||
# null=True,
|
||||
# help_text="Grade assigned based on marks",
|
||||
# )
|
||||
#
|
||||
# class Meta:
|
||||
# verbose_name = "Marksheet"
|
||||
# verbose_name_plural = "Marksheets"
|
||||
# unique_together = ("student", "course")
|
||||
#
|
||||
# def save(self, *args, **kwargs):
|
||||
# percentage = (self.marks_obtained / self.total_marks) * 100
|
||||
# if percentage >= 90:
|
||||
# self.grade = "A+"
|
||||
# elif percentage >= 80:
|
||||
# self.grade = "A"
|
||||
# elif percentage >= 70:
|
||||
# self.grade = "B"
|
||||
# elif percentage >= 60:
|
||||
# self.grade = "C"
|
||||
# elif percentage >= 50:
|
||||
# self.grade = "D"
|
||||
# else:
|
||||
# self.grade = "F"
|
||||
#
|
||||
# super().save(*args, **kwargs)
|
||||
#
|
||||
# def __str__(self):
|
||||
# return f"Marksheet: {self.student.first_name} {self.student.last_name}"
|
||||
@@ -4,4 +4,5 @@ from app import views
|
||||
urlpatterns = [
|
||||
path("dashboard", views.dashboard, name="dashboard"),
|
||||
path("studentdashboard", views.studentdashboard, name="studentdashboard"),
|
||||
path("marksheet", views.marksheet, name="marksheet"),
|
||||
]
|
||||
+51
-12
@@ -1,32 +1,71 @@
|
||||
from django.shortcuts import render, get_object_or_404
|
||||
from django.shortcuts import render, redirect, get_object_or_404
|
||||
from django.contrib.admin import site
|
||||
from app.models import Student, NewsEvent, Subject
|
||||
|
||||
from app.models import (
|
||||
Student,
|
||||
NewsEvent,
|
||||
AcademicYear,
|
||||
Subject,
|
||||
Teacher,
|
||||
Staff,
|
||||
Course,
|
||||
Marksheet,
|
||||
SubjectMark,
|
||||
)
|
||||
from django.contrib.auth.decorators import login_required
|
||||
|
||||
|
||||
# Dashboard for admin
|
||||
@login_required(login_url="login")
|
||||
@login_required
|
||||
def dashboard(request):
|
||||
if not request.user.is_superuser:
|
||||
return redirect("studentdashboard")
|
||||
|
||||
total_student = Student.objects.count()
|
||||
total_teacher = Teacher.objects.count()
|
||||
total_staff = Staff.objects.count()
|
||||
total_course = Course.objects.count()
|
||||
total_subjects = Subject.objects.count()
|
||||
context = {
|
||||
**site.each_context(request),
|
||||
"title": "Dashboard",
|
||||
# "breadcrumbs": [{"name": "Dashboard", "url": "dashboard"}],
|
||||
"total_student": total_student,
|
||||
"total_teacher": total_teacher,
|
||||
"total_staff": total_staff,
|
||||
"total_course": total_course,
|
||||
"total_subjects": total_subjects,
|
||||
}
|
||||
return render(request, "dashboard.html", context)
|
||||
|
||||
|
||||
# Student-specific dashboard
|
||||
@login_required
|
||||
def studentdashboard(request):
|
||||
total_subject = Subject.objects.count()
|
||||
student = Student.objects.get(user=request.user)
|
||||
course_name = student.course.name
|
||||
course = student.course
|
||||
total_subjects = Subject.objects.filter(course=course).count()
|
||||
subject = Subject.objects.filter(course=course)
|
||||
|
||||
context = {
|
||||
**site.each_context(request),
|
||||
"title": "Student Dashboard",
|
||||
"total_subject": total_subject,
|
||||
"course_name": course_name,
|
||||
"subject": subject,
|
||||
"total_subjects": total_subjects,
|
||||
}
|
||||
|
||||
if request.user.is_authenticated:
|
||||
news_events = NewsEvent.objects.all()
|
||||
subjects = Subject.objects.all()
|
||||
context["news_events"] = news_events
|
||||
context["subjects"] = subjects
|
||||
|
||||
return render(request, "studentdashboard.html", context)
|
||||
|
||||
|
||||
def marksheet(request):
|
||||
marksheet = Marksheet.objects.first()
|
||||
subject = SubjectMark.objects.filter(marksheet=marksheet)
|
||||
context = {
|
||||
**site.each_context(request),
|
||||
"title": "Marksheet",
|
||||
"marksheet": marksheet,
|
||||
"subject": subject,
|
||||
}
|
||||
|
||||
return render(request, "marksheet.html", context)
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 24 KiB |
@@ -1,63 +1,43 @@
|
||||
|
||||
JAZZMIN_SETTINGS = {
|
||||
# title of the window (Will default to current_admin_site.site_title if absent or None)
|
||||
"site_title": "Student Management System Admin",
|
||||
|
||||
# Title on the login screen (19 chars max) (defaults to current_admin_site.site_header if absent or None)
|
||||
"site_header": "Student Management System",
|
||||
|
||||
# Title on the brand (19 chars max) (defaults to current_admin_site.site_header if absent or None)
|
||||
"site_brand": "SMS",
|
||||
|
||||
# Logo to use for your site, must be present in static files, used for brand on top left
|
||||
"site_logo": "/src/img/logo2.png",
|
||||
|
||||
# CSS classes that are applied to the logo above
|
||||
"site_logo_classes": "img-circle",
|
||||
|
||||
# Relative path to a favicon for your site, will default to site_logo if absent (ideally 32x32 px)
|
||||
"site_icon": None,
|
||||
|
||||
# Welcome text on the login screen
|
||||
"welcome_sign": "Welcome to the Student Management System",
|
||||
|
||||
# Copyright on the footer
|
||||
"copyright": "ADDRSSS",
|
||||
|
||||
# theme
|
||||
|
||||
|
||||
|
||||
# The model admin to search from the search bar, search bar omitted if excluded
|
||||
# "search_model": "auth.User",
|
||||
|
||||
# Field name on user model that contains avatar ImageField/URLField/Charfield or a callable that receives the user
|
||||
"user_avatar": None,
|
||||
|
||||
"version": False,
|
||||
############
|
||||
# Top Menu #
|
||||
############
|
||||
|
||||
# Links to put along the top menu
|
||||
"topmenu_links": [
|
||||
|
||||
# Url that gets reversed (Permissions can be added)
|
||||
{"name": "Home", "url": "admin:index", "permissions": ["auth.view_user"]},
|
||||
|
||||
# external url that opens in a new window (Permissions can be added)
|
||||
# {"name": "Support", "url": "https://github.com/farridav/django-jazzmin/issues", "new_window": True},
|
||||
|
||||
# model admin to link to (Permissions checked against model)
|
||||
# {"model": "auth.User"},
|
||||
|
||||
# App with dropdown menu to all its models pages (Permissions checked against models)
|
||||
# {"app": "books"},
|
||||
],
|
||||
|
||||
#############
|
||||
# User Menu #
|
||||
#############
|
||||
|
||||
# Additional links to include in the user menu on the top right ("app" url type is not allowed)
|
||||
# "usermenu_links": [
|
||||
# {"name": "Support", "url": "https://github.com/farridav/django-jazzmin/issues", "new_window": True},
|
||||
@@ -67,30 +47,30 @@ JAZZMIN_SETTINGS = {
|
||||
#############
|
||||
# Side Menu #
|
||||
#############
|
||||
|
||||
# Whether to display the side menu
|
||||
"show_sidebar": True,
|
||||
|
||||
# Whether to aut expand the menu
|
||||
"navigation_expanded": True,
|
||||
|
||||
# Hide these apps when generating side menu e.g (auth)
|
||||
"hide_apps": [],
|
||||
|
||||
# Hide these models when generating side menu (e.g auth.user)
|
||||
"hide_models": [],
|
||||
|
||||
# List of apps (and/or models) to base side menu ordering off of (does not need to contain all apps/models)
|
||||
"order_with_respect_to": ["auth"],
|
||||
|
||||
|
||||
|
||||
"order_with_respect_to": ["auth", "dashboard"],
|
||||
"custom_links": {
|
||||
"app": [
|
||||
{
|
||||
"name": "Dashboard",
|
||||
"url": "dashboard",
|
||||
"icon": "fas fa-tachometer-alt",
|
||||
},
|
||||
]
|
||||
},
|
||||
#################
|
||||
# Related Modal #
|
||||
#################
|
||||
# Use modals instead of popups
|
||||
"related_modal_active": False,
|
||||
|
||||
#############
|
||||
# UI Tweaks #
|
||||
#############
|
||||
@@ -99,7 +79,6 @@ JAZZMIN_SETTINGS = {
|
||||
"custom_js": None,
|
||||
# Whether to show the UI customizer on the sidebar
|
||||
"show_ui_builder": False,
|
||||
|
||||
###############
|
||||
# Change view #
|
||||
###############
|
||||
@@ -111,10 +90,14 @@ JAZZMIN_SETTINGS = {
|
||||
# - carousel
|
||||
"changeform_format": "horizontal_tabs",
|
||||
# override change forms on a per modeladmin basis
|
||||
"changeform_format_overrides": {"auth.user": "collapsible", "auth.group": "vertical_tabs"},
|
||||
"changeform_format_overrides": {
|
||||
"auth.user": "horizontal_tabs",
|
||||
"auth.group": "vertical_tabs",
|
||||
},
|
||||
}
|
||||
|
||||
JAZZMIN_UI_TWEAKS = {
|
||||
# "footer_fixed": True,
|
||||
"theme": "lumen",
|
||||
# "dark_mode_theme": "cyborg",
|
||||
}
|
||||
@@ -25,26 +25,8 @@ urlpatterns = (
|
||||
[
|
||||
path("admin/", admin.site.urls),
|
||||
path("", RedirectView.as_view(url="/admin/", permanent=False)),
|
||||
path("", include("app.urls")),
|
||||
]
|
||||
+ static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
|
||||
+ static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
||||
)
|
||||
# from django.contrib import admin
|
||||
# from django.urls import path, include
|
||||
#
|
||||
# from django.conf import settings
|
||||
# from django.conf.urls.static import static
|
||||
#
|
||||
#
|
||||
# urlpatterns = (
|
||||
# [
|
||||
# path("admin/", admin.site.urls),
|
||||
# path(
|
||||
# "",
|
||||
# include("app.urls"),
|
||||
# ),
|
||||
# ]
|
||||
# + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
|
||||
# + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
||||
# )
|
||||
|
||||
@@ -0,0 +1,152 @@
|
||||
{% extends "admin/base_site.html" %}
|
||||
{% block content %}
|
||||
<h2 class="col-12">{{ title }}</h2>
|
||||
<p class="col-12">Welcome</p>
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||||
<!--cards-->
|
||||
<div class="row g-4 col-12">
|
||||
<div class="col-12 col-md-6 col-lg-3">
|
||||
<div class="card text-center p-3">
|
||||
<h5>Total Students</h5>
|
||||
<p class="fs-2">{{ total_student }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-md-6 col-lg-3">
|
||||
<div class="card text-center p-3">
|
||||
<h5>Total Staff</h5>
|
||||
<p class="fs-2">{{ total_staff }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-md-6 col-lg-3">
|
||||
<div class="card text-center p-3">
|
||||
<h5>Total Teacher</h5>
|
||||
<p class="fs-2">{{ total_teacher }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-md-6 col-lg-3">
|
||||
<div class="card text-center p-3">
|
||||
<h5>Total Course</h5>
|
||||
<p class="fs-2">{{ total_course }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-md-6 col-lg-3">
|
||||
<div class="card text-center p-3">
|
||||
<h5>Total Subject</h5>
|
||||
<p class="fs-2">{{ total_subjects }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row col-12">
|
||||
<div class="col-12 col-md-6 col-lg-6">
|
||||
<table class="text-center table table-bordered">
|
||||
<thead class="table-dark">
|
||||
<th>S.N</th>
|
||||
<th>Name</th>
|
||||
<th>Course</th>
|
||||
<th>Academic Year</th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<td>1</td>
|
||||
<td>hello</td>
|
||||
<td>DCOM</td>
|
||||
<td>2023</td>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="col-12 col-md-6 col-lg-6">
|
||||
<table class="text-center table table-bordered">
|
||||
<thead class="table-dark">
|
||||
<th>S.N</th>
|
||||
<th>Name</th>
|
||||
<th>Address</th>
|
||||
<th>Phone No</th>
|
||||
<th>Gmail</th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>1</td>
|
||||
<td>hello</td>
|
||||
<td>kohalpur</td>
|
||||
<td>9801230123</td>
|
||||
<td>example@example.com</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Pie Chart -->
|
||||
<div class="row col-12 col-lg-6 chart-container">
|
||||
<canvas id="pieChart"></canvas>
|
||||
</div>
|
||||
<!-- Bar Chart -->
|
||||
<div class="row col-12 col-lg-6 chart-container">
|
||||
<canvas id="barChart"></canvas>
|
||||
</div>
|
||||
<!-- Line Chart -->
|
||||
<div class="row col-12 col-lg-6 chart-container">
|
||||
<canvas id="lineChart"></canvas>
|
||||
</div>
|
||||
<script>
|
||||
// Pie Chart
|
||||
const pieCtx = document.getElementById("pieChart").getContext("2d");
|
||||
new Chart(pieCtx, {
|
||||
type: "pie",
|
||||
data: {
|
||||
labels: ["Category A", "Category B", "Category C"],
|
||||
datasets: [
|
||||
{
|
||||
data: [30, 50, 20],
|
||||
backgroundColor: ["#FF6384", "#36A2EB", "#FFCE56"],
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
// Bar Chart
|
||||
const barCtx = document.getElementById("barChart").getContext("2d");
|
||||
new Chart(barCtx, {
|
||||
type: "bar",
|
||||
data: {
|
||||
labels: ["Category A", "Category B", "Category C"],
|
||||
datasets: [
|
||||
{
|
||||
label: "Values",
|
||||
data: [30, 50, 20],
|
||||
backgroundColor: ["#FF6384", "#36A2EB", "#FFCE56"],
|
||||
},
|
||||
],
|
||||
},
|
||||
options: {
|
||||
scales: {
|
||||
y: {
|
||||
beginAtZero: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// Line Chart
|
||||
const lineCtx = document.getElementById("lineChart").getContext("2d");
|
||||
new Chart(lineCtx, {
|
||||
type: "line",
|
||||
data: {
|
||||
labels: ["January", "February", "March", "April"],
|
||||
datasets: [
|
||||
{
|
||||
label: "Values",
|
||||
data: [10, 30, 20, 40],
|
||||
borderColor: "#36A2EB",
|
||||
fill: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
options: {
|
||||
scales: {
|
||||
y: {
|
||||
beginAtZero: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,144 @@
|
||||
{% extends 'admin/base_site.html' %}
|
||||
{% block content %}
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
margin: 20px;
|
||||
}
|
||||
|
||||
.container {
|
||||
width: 90%;
|
||||
margin: auto;
|
||||
padding: 20px;
|
||||
border: 1px solid #000;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.header {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.header h1,
|
||||
.header h2,
|
||||
.header p {
|
||||
margin: 5px 0;
|
||||
}
|
||||
|
||||
.header img {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
}
|
||||
|
||||
.details {
|
||||
margin-top: 20px;
|
||||
line-height: 1.8;
|
||||
}
|
||||
|
||||
.details span {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
table,
|
||||
th,
|
||||
td {
|
||||
border: 1px solid #000;
|
||||
}
|
||||
|
||||
th,
|
||||
td {
|
||||
text-align: center;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
th {
|
||||
background-color: #f2f2f2;
|
||||
}
|
||||
|
||||
.remarks {
|
||||
margin-top: 20px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.btn-print {
|
||||
display: block;
|
||||
width: 100px;
|
||||
margin: 20px auto;
|
||||
padding: 10px;
|
||||
background-color: #4CAF50;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
@media print {
|
||||
.btn-print {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<h1>SHREE SECONDARY SCHOOL</h1>
|
||||
<p>Kohalpur-5, Banke</p>
|
||||
<p>Estd. 281 BS</p>
|
||||
<h2>GRADE - SHEET</h2>
|
||||
</div>
|
||||
<div class="details">
|
||||
<p>
|
||||
The grade(s) secured by: <span>{{ marksheet.student.first_name }} {{ marksheet.student.first_name }}</span>
|
||||
</p>
|
||||
<p>
|
||||
Date of Birth: <span>
|
||||
{{ marksheet.student.date_of_birth }}
|
||||
<p>
|
||||
In the Examination, {{ marksheet.student.course.name }} of {{ marksheet.student.academic_year }} are given below:
|
||||
</p>
|
||||
</div>
|
||||
<table class="table table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>S.N.</th>
|
||||
<th>Subject</th>
|
||||
<th>Theory</th>
|
||||
<th>Practical</th>
|
||||
<th>Total</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for subject in marksheet.subject_marks.all %}
|
||||
<tr>
|
||||
<td>{{ forloop.counter }}</td>
|
||||
<td>{{ subject.subject.name }}</td>
|
||||
<td>{{ subject.obtained_theory_marks }}</td>
|
||||
<td>{{ subject.obtained_practical_marks }}</td>
|
||||
<td>{{ subject.total_marks }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
<tr>
|
||||
<td colspan="4" style="font-weight: bold; text-align: center;">Grand Total</td>
|
||||
<td>{{ marksheet.obtained_marks }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="remarks">
|
||||
<p>
|
||||
Total Grade Point Average (Grade): <span>{{ marksheet.grade }}</span>
|
||||
</p>
|
||||
<p class="text-sm text-gray-600">
|
||||
Percentage:
|
||||
{{ marksheet.obtained_marks|div:marksheet.total_marks|mul:100|floatformat:2 }}%
|
||||
</p>
|
||||
</div>
|
||||
<a href="#" class="btn-print" onclick="window.print();">Print PDF</a>
|
||||
</div>
|
||||
</body>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,77 @@
|
||||
<!-- templates/marksheet/marksheet_detail.html -->
|
||||
{% extends "admin/base_site.html" %}
|
||||
{% block content %}
|
||||
<div class="container mx-auto p-4">
|
||||
<div class="bg-white shadow-lg rounded-lg p-6">
|
||||
<!-- Student & Course Info -->
|
||||
<div class="mb-6 border-b pb-4">
|
||||
<h1 class="text-2xl font-bold mb-2">Student Marksheet</h1>
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<p class="font-semibold">Student Name:</p>
|
||||
<p>{{ marksheet.student.first_name }} {{ marksheet.student.last_name }}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p class="font-semibold">Course:</p>
|
||||
<p>{{ marksheet.course.name }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Marks Table -->
|
||||
<div class="overflow-x-auto">
|
||||
<table class="w-full table-auto">
|
||||
<thead>
|
||||
<tr class="bg-gray-100">
|
||||
<th class="px-4 py-2 text-left">Subject</th>
|
||||
<th class="px-4 py-2 text-center">Theory Marks</th>
|
||||
<th class="px-4 py-2 text-center">Practical Marks</th>
|
||||
<th class="px-4 py-2 text-center">Total</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for subject_mark in marksheet.subject_marks.all %}
|
||||
<tr class="border-b">
|
||||
<td class="px-4 py-2">{{ subject_mark.subject.name }}</td>
|
||||
<td class="px-4 py-2 text-center">
|
||||
{{ subject_mark.obtained_theory_marks }}/{{
|
||||
subject_mark.total_theory_marks }}
|
||||
</td>
|
||||
<td class="px-4 py-2 text-center">
|
||||
{{ subject_mark.obtained_practical_marks }}/{{
|
||||
subject_mark.total_practical_marks }}
|
||||
</td>
|
||||
<td class="px-4 py-2 text-center">
|
||||
{{ subject_mark.total_marks }}/{{
|
||||
subject_mark.total_practical_marks|add:subject_mark.total_theory_marks
|
||||
}}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr class="bg-gray-50 font-bold">
|
||||
<td class="px-4 py-2">Total</td>
|
||||
<td class="px-4 py-2 text-center" colspan="2"></td>
|
||||
<td class="px-4 py-2 text-center">{{ marksheet.obtained_marks }}/{{ marksheet.total_marks }}</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
<!-- Final Grade -->
|
||||
<div class="mt-6 text-center">
|
||||
<div class="inline-block bg-blue-100 rounded-lg px-6 py-3">
|
||||
<p class="text-lg font-semibold">
|
||||
Final Grade:
|
||||
<span class="text-2xl ml-2 {% if marksheet.grade == 'F' %}text-red-600{% else %}text-green-600{% endif %}">
|
||||
{{ marksheet.grade }}
|
||||
</span>
|
||||
</p>
|
||||
<!--<p class="text-sm text-gray-600">-->
|
||||
<!-- Percentage:-->
|
||||
<!--</p>-->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<a href="#" class="btn-print" onclick="window.print();">Print PDF</a>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,26 @@
|
||||
{% extends "admin/base_site.html" %}
|
||||
{% block content %}
|
||||
<div class="container mx-auto p-4">
|
||||
<h1 class="text-2xl font-bold mb-6">Student Marksheets</h1>
|
||||
<div class="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
|
||||
{% for marksheet in marksheets %}
|
||||
<div class="bg-white rounded-lg shadow-lg p-4">
|
||||
<h2 class="text-xl font-semibold mb-2">{{ marksheet.student.first_name }} {{ marksheet.student.last_name }}</h2>
|
||||
<p class="text-gray-600 mb-2">Course: {{ marksheet.course.name }}</p>
|
||||
<div class="flex justify-between items-center mt-4">
|
||||
<span class="text-sm">
|
||||
Grade:
|
||||
<span class="font-bold {% if marksheet.grade == 'F' %}text-red-600{% else %}text-green-600{% endif %}">
|
||||
{{ marksheet.grade }}
|
||||
</span>
|
||||
</span>
|
||||
<a href="{% url 'marksheetdetails' %}"
|
||||
class="bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600">View Details</a>
|
||||
</div>
|
||||
</div>
|
||||
{% empty %}
|
||||
<div class="col-span-full text-center py-8 text-gray-500">No marksheets available.</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
Whitespace-only changes.
@@ -0,0 +1,83 @@
|
||||
{% extends "admin/base_site.html" %}
|
||||
{% block content %}
|
||||
<h2 class="col-12">{{ title }}</h2>
|
||||
<p class="col-12">Welcome</p>
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||||
<div class="row g-4 col-12">
|
||||
<div class="col-12 col-md-6 col-lg-3">
|
||||
<div class="card text-center p-3">
|
||||
<h5>Course</h5>
|
||||
<p class="fs-2">{{ course_name }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-md-6 col-lg-3">
|
||||
<div class="card text-center p-3">
|
||||
<h5>Current Semester</h5>
|
||||
<p class="fs-2">5</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-md-6 col-lg-3">
|
||||
<div class="card text-center p-3">
|
||||
<h5>Total Subject</h5>
|
||||
<p class="fs-2">{{ total_subjects }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Subject Attendance Bar Chart -->
|
||||
<div class="row col-12 col-lg-6 chart-container">
|
||||
<canvas id="attendanceBarChart"></canvas>
|
||||
</div>
|
||||
<!-- Subject Results Bar Chart -->
|
||||
<div class="row col-12 col-lg-6 chart-container">
|
||||
<canvas id="resultBarChart"></canvas>
|
||||
</div>
|
||||
<script>
|
||||
// Bar Chart for Subject Attendance
|
||||
const attendanceCtx = document.getElementById("attendanceBarChart").getContext("2d");
|
||||
new Chart(attendanceCtx, {
|
||||
type: "bar",
|
||||
data: {
|
||||
labels: ["Math", "Science", "English", "History", "Geography"], // Example subject names
|
||||
datasets: [
|
||||
{
|
||||
label: "Attendance Percentage",
|
||||
data: [90, 80, 85, 75, 95], // Example attendance percentages for each subject
|
||||
backgroundColor: ["#FF6384", "#36A2EB", "#FFCE56", "#4CAF50", "#FF8C00"],
|
||||
},
|
||||
],
|
||||
},
|
||||
options: {
|
||||
scales: {
|
||||
y: {
|
||||
beginAtZero: true,
|
||||
max: 100, // Percentage scale
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// Bar Chart for Subject Results (Example)
|
||||
const resultCtx = document.getElementById("resultBarChart").getContext("2d");
|
||||
new Chart(resultCtx, {
|
||||
type: "bar",
|
||||
data: {
|
||||
labels: ["Math", "Science", "English", "History", "Geography"], // Example subject names
|
||||
datasets: [
|
||||
{
|
||||
label: "Results (Percentage)",
|
||||
data: [88, 75, 80, 70, 92], // Example result percentages for each subject
|
||||
backgroundColor: ["#FF5733", "#33FF57", "#3357FF", "#FF5733", "#FF8C00"],
|
||||
},
|
||||
],
|
||||
},
|
||||
options: {
|
||||
scales: {
|
||||
y: {
|
||||
beginAtZero: true,
|
||||
max: 100, // Percentage scale
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
Whitespace-only changes.
Reference in new issue
Block a user