update
This commit is contained in:
1 parent
c738c1746a
commit
0504b881fb
30 files changed
+1297
-123
No files matched your search
+61
-3
@@ -10,6 +10,8 @@ from app.models import (
|
|||||||
Attendance,
|
Attendance,
|
||||||
Result,
|
Result,
|
||||||
Library,
|
Library,
|
||||||
|
Marksheet,
|
||||||
|
SubjectMark,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -39,6 +41,7 @@ class StudentAdmin(BaseUserAdmin):
|
|||||||
"last_name",
|
"last_name",
|
||||||
"father_name",
|
"father_name",
|
||||||
"mother_name",
|
"mother_name",
|
||||||
|
"guardian_name",
|
||||||
"email",
|
"email",
|
||||||
"phone",
|
"phone",
|
||||||
"course",
|
"course",
|
||||||
@@ -73,7 +76,7 @@ class StaffAdmin(BaseUserAdmin):
|
|||||||
|
|
||||||
@admin.register(Course)
|
@admin.register(Course)
|
||||||
class CourseAdmin(admin.ModelAdmin):
|
class CourseAdmin(admin.ModelAdmin):
|
||||||
list_display = ("id", "name", "course_type", "duration")
|
list_display = ("id", "name", "level", "course_type", "duration")
|
||||||
search_fields = ("name",)
|
search_fields = ("name",)
|
||||||
list_filter = ("course_type",)
|
list_filter = ("course_type",)
|
||||||
|
|
||||||
@@ -93,7 +96,7 @@ class SubjectAdmin(admin.ModelAdmin):
|
|||||||
|
|
||||||
@admin.register(NewsEvent)
|
@admin.register(NewsEvent)
|
||||||
class NewsEventAdmin(admin.ModelAdmin):
|
class NewsEventAdmin(admin.ModelAdmin):
|
||||||
list_display = ("id", "title", "type", "created_at")
|
list_display = ("id", "title", "summary", "type", "created_at")
|
||||||
search_fields = ("title", "summary")
|
search_fields = ("title", "summary")
|
||||||
list_filter = ("type", "created_at")
|
list_filter = ("type", "created_at")
|
||||||
|
|
||||||
@@ -121,4 +124,59 @@ class ResultAdmin(admin.ModelAdmin):
|
|||||||
|
|
||||||
@admin.register(Library)
|
@admin.register(Library)
|
||||||
class LibraryAdmin(admin.ModelAdmin):
|
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):
|
class AppConfig(AppConfig):
|
||||||
default_auto_field = 'django.db.models.BigAutoField'
|
default_auto_field = "django.db.models.BigAutoField"
|
||||||
name = 'app'
|
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
|
import random
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
from datetime import time, timedelta, datetime
|
from datetime import time, timedelta, datetime
|
||||||
|
from django.core.validators import MinValueValidator, MaxValueValidator
|
||||||
|
|
||||||
|
|
||||||
# Abstract BaseUser Model
|
# Abstract BaseUser Model
|
||||||
@@ -19,7 +20,6 @@ class BaseUser(models.Model):
|
|||||||
)
|
)
|
||||||
username = models.CharField(max_length=255, unique=True, blank=True, null=True)
|
username = models.CharField(max_length=255, unique=True, blank=True, null=True)
|
||||||
password = models.CharField(max_length=255)
|
password = models.CharField(max_length=255)
|
||||||
address = models.CharField(max_length=255)
|
|
||||||
group = models.ManyToManyField(Group, blank=True)
|
group = models.ManyToManyField(Group, blank=True)
|
||||||
user = models.OneToOneField(User, on_delete=models.CASCADE, null=True, 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,
|
email=self.email,
|
||||||
first_name=self.first_name,
|
first_name=self.first_name,
|
||||||
last_name=self.last_name,
|
last_name=self.last_name,
|
||||||
address=self.address,
|
|
||||||
is_staff=True,
|
is_staff=True,
|
||||||
is_active=self.active_status,
|
is_active=self.active_status,
|
||||||
password=self.password,
|
password=self.password,
|
||||||
@@ -52,7 +51,6 @@ class BaseUser(models.Model):
|
|||||||
self.user.email = self.email
|
self.user.email = self.email
|
||||||
self.user.first_name = self.first_name
|
self.user.first_name = self.first_name
|
||||||
self.user.last_name = self.last_name
|
self.user.last_name = self.last_name
|
||||||
self.user.address = self.address
|
|
||||||
self.user.is_active = self.active_status
|
self.user.is_active = self.active_status
|
||||||
self.user.is_staff = True
|
self.user.is_staff = True
|
||||||
self.user.password = self.password
|
self.user.password = self.password
|
||||||
@@ -103,6 +101,7 @@ class Teacher(BaseUser):
|
|||||||
class Student(BaseUser):
|
class Student(BaseUser):
|
||||||
date_of_birth = models.DateField(blank=False)
|
date_of_birth = models.DateField(blank=False)
|
||||||
gender = models.CharField(max_length=1, choices=[("M", "Male"), ("F", "Female")])
|
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)
|
course = models.ForeignKey("Course", on_delete=models.CASCADE)
|
||||||
academic_year = models.ForeignKey("AcademicYear", on_delete=models.CASCADE)
|
academic_year = models.ForeignKey("AcademicYear", on_delete=models.CASCADE)
|
||||||
father_name = models.CharField(max_length=100)
|
father_name = models.CharField(max_length=100)
|
||||||
@@ -111,17 +110,17 @@ class Student(BaseUser):
|
|||||||
)
|
)
|
||||||
father_email = models.EmailField(blank=True, null=True)
|
father_email = models.EmailField(blank=True, null=True)
|
||||||
father_occupation_choice = (
|
father_occupation_choice = (
|
||||||
("Agriculture", "Agriculture"),
|
("agriculture", "Agriculture"),
|
||||||
("Banker", "Banker"),
|
("banker", "Banker"),
|
||||||
("Business", "Business"),
|
("business", "Business"),
|
||||||
("Doctor", "Doctor"),
|
("doctor", "Doctor"),
|
||||||
("Farmer", "Farmer"),
|
("farmer", "Farmer"),
|
||||||
("Fisherman", "Fisherman"),
|
("fisherman", "Fisherman"),
|
||||||
("Public Service", "Public Service"),
|
("public service", "Public Service"),
|
||||||
("Private Service", "Private Service"),
|
("private service", "Private Service"),
|
||||||
("Shopkeeper", "Shopkeeper"),
|
("shopkeeper", "Shopkeeper"),
|
||||||
("Driver", "Driver"),
|
("driver", "Driver"),
|
||||||
("Worker", "Worker"),
|
("worker", "Worker"),
|
||||||
("N/A", "N/A"),
|
("N/A", "N/A"),
|
||||||
)
|
)
|
||||||
father_occupation = models.CharField(
|
father_occupation = models.CharField(
|
||||||
@@ -136,18 +135,18 @@ class Student(BaseUser):
|
|||||||
)
|
)
|
||||||
mother_email = models.EmailField(blank=True, null=True)
|
mother_email = models.EmailField(blank=True, null=True)
|
||||||
mother_occupation_choice = (
|
mother_occupation_choice = (
|
||||||
("Agriculture", "Agriculture"),
|
("agriculture", "Agriculture"),
|
||||||
("Banker", "Banker"),
|
("banker", "Banker"),
|
||||||
("Business", "Business"),
|
("business", "Business"),
|
||||||
("Doctor", "Doctor"),
|
("doctor", "Doctor"),
|
||||||
("Farmer", "Farmer"),
|
("farmer", "Farmer"),
|
||||||
("Fisherman", "Fisherman"),
|
("fisherman", "Fisherman"),
|
||||||
("Public Service", "Public Service"),
|
("public service", "Public Service"),
|
||||||
("Private Service", "Private Service"),
|
("private service", "Private Service"),
|
||||||
("Shopkeeper", "Shopkeeper"),
|
("shopkeeper", "Shopkeeper"),
|
||||||
("Driver", "Driver"),
|
("driver", "Driver"),
|
||||||
("HouseWife", "HouseWife"),
|
("houseWife", "HouseWife"),
|
||||||
("Worker", "Worker"),
|
("worker", "Worker"),
|
||||||
("N/A", "N/A"),
|
("N/A", "N/A"),
|
||||||
)
|
)
|
||||||
mother_occupation = models.CharField(
|
mother_occupation = models.CharField(
|
||||||
@@ -159,13 +158,13 @@ class Student(BaseUser):
|
|||||||
)
|
)
|
||||||
guardian_email = models.EmailField(blank=True, null=True)
|
guardian_email = models.EmailField(blank=True, null=True)
|
||||||
relationship_choice = (
|
relationship_choice = (
|
||||||
("Father", "Father"),
|
("father", "Father"),
|
||||||
("Mother", "Mother"),
|
("mother", "Mother"),
|
||||||
("Brother", "Brother"),
|
("brother", "Brother"),
|
||||||
("Sister", "Sister"),
|
("sister", "Sister"),
|
||||||
("Uncle", "Uncle"),
|
("uncle", "Uncle"),
|
||||||
("Aunt", "Aunt"),
|
("aunt", "Aunt"),
|
||||||
("Grandfather", "Grandfather"),
|
("grandfather", "Grandfather"),
|
||||||
)
|
)
|
||||||
relationship_with_student = models.CharField(
|
relationship_with_student = models.CharField(
|
||||||
choices=relationship_choice, max_length=45
|
choices=relationship_choice, max_length=45
|
||||||
@@ -182,13 +181,13 @@ class Staff(BaseUser):
|
|||||||
position = models.CharField(
|
position = models.CharField(
|
||||||
max_length=255,
|
max_length=255,
|
||||||
choices=[
|
choices=[
|
||||||
("Lab Assistant", "Lab Assistant"),
|
("lab Assistant", "Lab Assistant"),
|
||||||
("Librarian", "Librarian"),
|
("librarian", "Librarian"),
|
||||||
("Accountant", "Accountant"),
|
("accountant", "Accountant"),
|
||||||
("Guard", "Guard"),
|
("guard", "Guard"),
|
||||||
("Driver", "Driver"),
|
("driver", "Driver"),
|
||||||
("Helper", "Helper"),
|
("helper", "Helper"),
|
||||||
("Cleaner", "Cleaner"),
|
("cleaner", "Cleaner"),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
address = models.CharField(max_length=255)
|
address = models.CharField(max_length=255)
|
||||||
@@ -211,13 +210,13 @@ class Staff(BaseUser):
|
|||||||
class Course(models.Model):
|
class Course(models.Model):
|
||||||
name = models.CharField(max_length=100)
|
name = models.CharField(max_length=100)
|
||||||
level_choice = (
|
level_choice = (
|
||||||
("Basic", "Basic"),
|
("basic", "Basic"),
|
||||||
("Primary", "Primary"),
|
("primary", "Primary"),
|
||||||
("Secondary", "Secondary"),
|
("secondary", "Secondary"),
|
||||||
("Vocational Traning", "Vocational Traning"),
|
("vocational traning", "Vocational Traning"),
|
||||||
("Higher Secondary", "Higher Secondary"),
|
("higher secondary", "Higher Secondary"),
|
||||||
("Graduation", "Graduation"),
|
("graduation", "Graduation"),
|
||||||
("Post Graduation", "Post Graduation"),
|
("post graduation", "Post Graduation"),
|
||||||
)
|
)
|
||||||
level = models.CharField(choices=level_choice, max_length=45)
|
level = models.CharField(choices=level_choice, max_length=45)
|
||||||
course_type = models.CharField(
|
course_type = models.CharField(
|
||||||
@@ -239,7 +238,7 @@ class AcademicYear(models.Model):
|
|||||||
year = models.CharField(max_length=255, unique=True)
|
year = models.CharField(max_length=255, unique=True)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.batch
|
return self.year
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = "Academic Year"
|
verbose_name = "Academic Year"
|
||||||
@@ -271,15 +270,17 @@ class Subject(models.Model):
|
|||||||
|
|
||||||
# NewsEvent model
|
# NewsEvent model
|
||||||
class NewsEvent(models.Model):
|
class NewsEvent(models.Model):
|
||||||
|
class NewsEventType(models.TextChoices):
|
||||||
|
NEWS = "news", "News"
|
||||||
|
EVENT = "event", "Event"
|
||||||
|
|
||||||
title = models.CharField(max_length=255)
|
title = models.CharField(max_length=255)
|
||||||
summary = models.TextField()
|
summary = models.TextField()
|
||||||
type = models.CharField(
|
type = models.CharField(max_length=5, choices=NewsEventType.choices)
|
||||||
max_length=5, choices=[("news", "News"), ("event", "Event")]
|
|
||||||
)
|
|
||||||
created_at = models.DateTimeField(auto_now_add=True)
|
created_at = models.DateTimeField(auto_now_add=True)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f"{self.title} ({self.get_type_display()})"
|
return f"{self.title} ({self.type})"
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = "News/Event"
|
verbose_name = "News/Event"
|
||||||
@@ -337,7 +338,7 @@ class Library(models.Model):
|
|||||||
category = models.CharField(max_length=255)
|
category = models.CharField(max_length=255)
|
||||||
book_name = models.CharField(max_length=255)
|
book_name = models.CharField(max_length=255)
|
||||||
description = 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()
|
publication_year = models.PositiveIntegerField()
|
||||||
quantity = models.PositiveIntegerField()
|
quantity = models.PositiveIntegerField()
|
||||||
available = models.CharField(max_length=1, choices=[("Y", "Yes"), ("N", "NO")])
|
available = models.CharField(max_length=1, choices=[("Y", "Yes"), ("N", "NO")])
|
||||||
@@ -349,3 +350,208 @@ class Library(models.Model):
|
|||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = "Library"
|
verbose_name = "Library"
|
||||||
verbose_name_plural = "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 = [
|
urlpatterns = [
|
||||||
path("dashboard", views.dashboard, name="dashboard"),
|
path("dashboard", views.dashboard, name="dashboard"),
|
||||||
path("studentdashboard", views.studentdashboard, name="studentdashboard"),
|
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 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
|
from django.contrib.auth.decorators import login_required
|
||||||
|
|
||||||
|
|
||||||
# Dashboard for admin
|
@login_required
|
||||||
@login_required(login_url="login")
|
|
||||||
def dashboard(request):
|
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 = {
|
context = {
|
||||||
**site.each_context(request),
|
**site.each_context(request),
|
||||||
"title": "Dashboard",
|
"title": "Dashboard",
|
||||||
# "breadcrumbs": [{"name": "Dashboard", "url": "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)
|
return render(request, "dashboard.html", context)
|
||||||
|
|
||||||
|
|
||||||
# Student-specific dashboard
|
@login_required
|
||||||
def studentdashboard(request):
|
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 = {
|
context = {
|
||||||
**site.each_context(request),
|
**site.each_context(request),
|
||||||
"title": "Student Dashboard",
|
"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)
|
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 = {
|
JAZZMIN_SETTINGS = {
|
||||||
# title of the window (Will default to current_admin_site.site_title if absent or None)
|
# title of the window (Will default to current_admin_site.site_title if absent or None)
|
||||||
"site_title": "Student Management System Admin",
|
"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)
|
# Title on the login screen (19 chars max) (defaults to current_admin_site.site_header if absent or None)
|
||||||
"site_header": "Student Management System",
|
"site_header": "Student Management System",
|
||||||
|
|
||||||
# Title on the brand (19 chars max) (defaults to current_admin_site.site_header if absent or None)
|
# Title on the brand (19 chars max) (defaults to current_admin_site.site_header if absent or None)
|
||||||
"site_brand": "SMS",
|
"site_brand": "SMS",
|
||||||
|
|
||||||
# Logo to use for your site, must be present in static files, used for brand on top left
|
# Logo to use for your site, must be present in static files, used for brand on top left
|
||||||
"site_logo": "/src/img/logo2.png",
|
"site_logo": "/src/img/logo2.png",
|
||||||
|
|
||||||
# CSS classes that are applied to the logo above
|
# CSS classes that are applied to the logo above
|
||||||
"site_logo_classes": "img-circle",
|
"site_logo_classes": "img-circle",
|
||||||
|
|
||||||
# Relative path to a favicon for your site, will default to site_logo if absent (ideally 32x32 px)
|
# Relative path to a favicon for your site, will default to site_logo if absent (ideally 32x32 px)
|
||||||
"site_icon": None,
|
"site_icon": None,
|
||||||
|
|
||||||
# Welcome text on the login screen
|
# Welcome text on the login screen
|
||||||
"welcome_sign": "Welcome to the Student Management System",
|
"welcome_sign": "Welcome to the Student Management System",
|
||||||
|
|
||||||
# Copyright on the footer
|
# Copyright on the footer
|
||||||
"copyright": "ADDRSSS",
|
"copyright": "ADDRSSS",
|
||||||
|
|
||||||
# theme
|
# theme
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# The model admin to search from the search bar, search bar omitted if excluded
|
# The model admin to search from the search bar, search bar omitted if excluded
|
||||||
# "search_model": "auth.User",
|
# "search_model": "auth.User",
|
||||||
|
|
||||||
# Field name on user model that contains avatar ImageField/URLField/Charfield or a callable that receives the user
|
# Field name on user model that contains avatar ImageField/URLField/Charfield or a callable that receives the user
|
||||||
"user_avatar": None,
|
"user_avatar": None,
|
||||||
|
"version": False,
|
||||||
############
|
############
|
||||||
# Top Menu #
|
# Top Menu #
|
||||||
############
|
############
|
||||||
|
|
||||||
# Links to put along the top menu
|
# Links to put along the top menu
|
||||||
"topmenu_links": [
|
"topmenu_links": [
|
||||||
|
|
||||||
# Url that gets reversed (Permissions can be added)
|
# Url that gets reversed (Permissions can be added)
|
||||||
{"name": "Home", "url": "admin:index", "permissions": ["auth.view_user"]},
|
{"name": "Home", "url": "admin:index", "permissions": ["auth.view_user"]},
|
||||||
|
|
||||||
# external url that opens in a new window (Permissions can be added)
|
# 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},
|
# {"name": "Support", "url": "https://github.com/farridav/django-jazzmin/issues", "new_window": True},
|
||||||
|
|
||||||
# model admin to link to (Permissions checked against model)
|
# model admin to link to (Permissions checked against model)
|
||||||
# {"model": "auth.User"},
|
# {"model": "auth.User"},
|
||||||
|
|
||||||
# App with dropdown menu to all its models pages (Permissions checked against models)
|
# App with dropdown menu to all its models pages (Permissions checked against models)
|
||||||
# {"app": "books"},
|
# {"app": "books"},
|
||||||
],
|
],
|
||||||
|
|
||||||
#############
|
#############
|
||||||
# User Menu #
|
# User Menu #
|
||||||
#############
|
#############
|
||||||
|
|
||||||
# Additional links to include in the user menu on the top right ("app" url type is not allowed)
|
# Additional links to include in the user menu on the top right ("app" url type is not allowed)
|
||||||
# "usermenu_links": [
|
# "usermenu_links": [
|
||||||
# {"name": "Support", "url": "https://github.com/farridav/django-jazzmin/issues", "new_window": True},
|
# {"name": "Support", "url": "https://github.com/farridav/django-jazzmin/issues", "new_window": True},
|
||||||
@@ -67,30 +47,30 @@ JAZZMIN_SETTINGS = {
|
|||||||
#############
|
#############
|
||||||
# Side Menu #
|
# Side Menu #
|
||||||
#############
|
#############
|
||||||
|
|
||||||
# Whether to display the side menu
|
# Whether to display the side menu
|
||||||
"show_sidebar": True,
|
"show_sidebar": True,
|
||||||
|
|
||||||
# Whether to aut expand the menu
|
# Whether to aut expand the menu
|
||||||
"navigation_expanded": True,
|
"navigation_expanded": True,
|
||||||
|
|
||||||
# Hide these apps when generating side menu e.g (auth)
|
# Hide these apps when generating side menu e.g (auth)
|
||||||
"hide_apps": [],
|
"hide_apps": [],
|
||||||
|
|
||||||
# Hide these models when generating side menu (e.g auth.user)
|
# Hide these models when generating side menu (e.g auth.user)
|
||||||
"hide_models": [],
|
"hide_models": [],
|
||||||
|
|
||||||
# List of apps (and/or models) to base side menu ordering off of (does not need to contain all apps/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 #
|
# Related Modal #
|
||||||
#################
|
#################
|
||||||
# Use modals instead of popups
|
# Use modals instead of popups
|
||||||
"related_modal_active": False,
|
"related_modal_active": False,
|
||||||
|
|
||||||
#############
|
#############
|
||||||
# UI Tweaks #
|
# UI Tweaks #
|
||||||
#############
|
#############
|
||||||
@@ -99,7 +79,6 @@ JAZZMIN_SETTINGS = {
|
|||||||
"custom_js": None,
|
"custom_js": None,
|
||||||
# Whether to show the UI customizer on the sidebar
|
# Whether to show the UI customizer on the sidebar
|
||||||
"show_ui_builder": False,
|
"show_ui_builder": False,
|
||||||
|
|
||||||
###############
|
###############
|
||||||
# Change view #
|
# Change view #
|
||||||
###############
|
###############
|
||||||
@@ -111,10 +90,14 @@ JAZZMIN_SETTINGS = {
|
|||||||
# - carousel
|
# - carousel
|
||||||
"changeform_format": "horizontal_tabs",
|
"changeform_format": "horizontal_tabs",
|
||||||
# override change forms on a per modeladmin basis
|
# 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 = {
|
JAZZMIN_UI_TWEAKS = {
|
||||||
|
# "footer_fixed": True,
|
||||||
"theme": "lumen",
|
"theme": "lumen",
|
||||||
# "dark_mode_theme": "cyborg",
|
# "dark_mode_theme": "cyborg",
|
||||||
}
|
}
|
||||||
@@ -25,26 +25,8 @@ urlpatterns = (
|
|||||||
[
|
[
|
||||||
path("admin/", admin.site.urls),
|
path("admin/", admin.site.urls),
|
||||||
path("", RedirectView.as_view(url="/admin/", permanent=False)),
|
path("", RedirectView.as_view(url="/admin/", permanent=False)),
|
||||||
|
path("", include("app.urls")),
|
||||||
]
|
]
|
||||||
+ static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
|
+ static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
|
||||||
+ static(settings.MEDIA_URL, document_root=settings.MEDIA_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