diff --git a/stude/accounts/migrations/0001_initial.py b/stude/accounts/migrations/0001_initial.py index fecce05..89231ab 100644 --- a/stude/accounts/migrations/0001_initial.py +++ b/stude/accounts/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 4.2.3 on 2023-08-06 05:55 +# Generated by Django 4.2.3 on 2023-09-03 09:32 import accounts.models import django.contrib.auth.models @@ -13,9 +13,9 @@ class Migration(migrations.Migration): initial = True dependencies = [ - ('auth', '0012_alter_user_first_name_max_length'), ('semesters', '0001_initial'), ('courses', '0001_initial'), + ('auth', '0012_alter_user_first_name_max_length'), ] operations = [ @@ -36,7 +36,7 @@ class Migration(migrations.Migration): ('is_student', models.BooleanField(default=True)), ('is_studying', models.BooleanField(default=False)), ('irregular', models.BooleanField(default=False)), - ('student_id_number', models.IntegerField()), + ('student_id_number', models.IntegerField(unique=True)), ('avatar', models.ImageField(null=True, upload_to=accounts.models.CustomUser._get_upload_to)), ('course', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='courses.course')), ('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.group', verbose_name='groups')), diff --git a/stude/accounts/migrations/0002_initial.py b/stude/accounts/migrations/0002_initial.py index a474d0a..536f0cf 100644 --- a/stude/accounts/migrations/0002_initial.py +++ b/stude/accounts/migrations/0002_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 4.2.3 on 2023-08-06 05:55 +# Generated by Django 4.2.3 on 2023-09-03 09:32 from django.db import migrations, models import django.db.models.deletion @@ -9,17 +9,17 @@ class Migration(migrations.Migration): initial = True dependencies = [ - ('auth', '0012_alter_user_first_name_max_length'), ('accounts', '0001_initial'), - ('subjects', '0001_initial'), ('year_levels', '0001_initial'), + ('subjects', '0001_initial'), + ('auth', '0012_alter_user_first_name_max_length'), ] operations = [ migrations.AddField( model_name='customuser', name='subjects', - field=models.ManyToManyField(to='subjects.subject'), + field=models.ManyToManyField(to='subjects.subjectinstance'), ), migrations.AddField( model_name='customuser', diff --git a/stude/accounts/migrations/0003_alter_customuser_student_id_number.py b/stude/accounts/migrations/0003_alter_customuser_student_id_number.py deleted file mode 100644 index fc7805a..0000000 --- a/stude/accounts/migrations/0003_alter_customuser_student_id_number.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 4.2.3 on 2023-09-02 05:03 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('accounts', '0002_initial'), - ] - - operations = [ - migrations.AlterField( - model_name='customuser', - name='student_id_number', - field=models.IntegerField(unique=True), - ), - ] diff --git a/stude/accounts/models.py b/stude/accounts/models.py index 97dcf8f..2273cbf 100644 --- a/stude/accounts/models.py +++ b/stude/accounts/models.py @@ -59,7 +59,7 @@ class CustomUser(AbstractUser): on_delete=models.SET_NULL, null=True ) - subjects = models.ManyToManyField('subjects.Subject') + subjects = models.ManyToManyField('subjects.SubjectInstance') @property def full_name(self): diff --git a/stude/accounts/serializers.py b/stude/accounts/serializers.py index d67d9d6..986d5df 100644 --- a/stude/accounts/serializers.py +++ b/stude/accounts/serializers.py @@ -11,7 +11,7 @@ from django.contrib.auth.password_validation import validate_password from courses.models import Course from year_levels.models import Year_Level from semesters.models import Semester -from subjects.models import Subject +from subjects.models import Subject, SubjectInstance from django.contrib.gis.geos import Point from django.utils.encoding import smart_str from drf_spectacular.utils import extend_schema_field @@ -25,9 +25,10 @@ class SubjectSlugRelatedField(serializers.SlugRelatedField): def to_internal_value(self, data): user_course = self.context['request'].user.course try: - subject = Subject.objects.get(name=data, course=user_course) + subject = SubjectInstance.objects.get( + name=data, course=user_course) return subject - except Subject.DoesNotExist: + except SubjectInstance.DoesNotExist: self.fail('does_not_exist', slug_name=self.slug_field, value=smart_str(data)) except (TypeError, ValueError): @@ -46,7 +47,7 @@ class CustomUserSerializer(BaseUserSerializer): many=False, slug_field='name', queryset=Semester.objects.all(), required=False, allow_null=True) # Use custom slug field for filtering subjects = SubjectSlugRelatedField( - many=True, slug_field='name', queryset=Subject.objects.all(), required=False) + many=True, slug_field='name', queryset=SubjectInstance.objects.all(), required=False) avatar = Base64ImageField() class Meta(BaseUserSerializer.Meta): @@ -112,7 +113,7 @@ class CustomUserSerializer(BaseUserSerializer): def add_subjects(self, instance): # Get the matching subjects based on the user's course, year level, and semester - matching_subjects = Subject.objects.filter( + matching_subjects = SubjectInstance.objects.filter( course=instance.course, year_level=instance.year_level, semester=instance.semester) # Add the matching subjects to the user's subjects list print(matching_subjects) diff --git a/stude/courses/migrations/0001_initial.py b/stude/courses/migrations/0001_initial.py index f445b71..ae82c42 100644 --- a/stude/courses/migrations/0001_initial.py +++ b/stude/courses/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 4.2.3 on 2023-08-06 05:55 +# Generated by Django 4.2.3 on 2023-09-03 09:32 from django.db import migrations, models diff --git a/stude/landmarks/migrations/0001_initial.py b/stude/landmarks/migrations/0001_initial.py index 5c1579e..a1f57ad 100644 --- a/stude/landmarks/migrations/0001_initial.py +++ b/stude/landmarks/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 4.2.3 on 2023-08-06 05:55 +# Generated by Django 4.2.3 on 2023-09-03 09:32 import django.contrib.gis.db.models.fields from django.db import migrations, models diff --git a/stude/semesters/migrations/0001_initial.py b/stude/semesters/migrations/0001_initial.py index 34af86b..d126d49 100644 --- a/stude/semesters/migrations/0001_initial.py +++ b/stude/semesters/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 4.2.3 on 2023-08-06 05:55 +# Generated by Django 4.2.3 on 2023-09-03 09:32 from django.db import migrations, models diff --git a/stude/student_status/migrations/0001_initial.py b/stude/student_status/migrations/0001_initial.py index f461925..8472f88 100644 --- a/stude/student_status/migrations/0001_initial.py +++ b/stude/student_status/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 4.2.3 on 2023-08-06 05:55 +# Generated by Django 4.2.3 on 2023-09-03 09:32 from django.conf import settings import django.contrib.gis.db.models.fields @@ -11,8 +11,8 @@ class Migration(migrations.Migration): initial = True dependencies = [ - ('accounts', '0002_initial'), ('landmarks', '0001_initial'), + ('accounts', '0002_initial'), ] operations = [ @@ -22,7 +22,7 @@ class Migration(migrations.Migration): ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, serialize=False, to=settings.AUTH_USER_MODEL)), ('location', django.contrib.gis.db.models.fields.PointField(blank=True, null=True, srid=4326)), ('active', models.BooleanField(default=False)), - ('timestamp', models.DateField(auto_now_add=True)), + ('timestamp', models.DateTimeField(auto_now_add=True)), ('landmark', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='landmarks.landmark')), ], ), diff --git a/stude/student_status/migrations/0002_initial.py b/stude/student_status/migrations/0002_initial.py index c66047f..975004e 100644 --- a/stude/student_status/migrations/0002_initial.py +++ b/stude/student_status/migrations/0002_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 4.2.3 on 2023-08-06 05:55 +# Generated by Django 4.2.3 on 2023-09-03 09:32 from django.db import migrations, models import django.db.models.deletion diff --git a/stude/student_status/migrations/0003_alter_studentstatus_timestamp.py b/stude/student_status/migrations/0003_alter_studentstatus_timestamp.py deleted file mode 100644 index 0a7fea7..0000000 --- a/stude/student_status/migrations/0003_alter_studentstatus_timestamp.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 4.2.3 on 2023-08-15 10:51 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('student_status', '0002_initial'), - ] - - operations = [ - migrations.AlterField( - model_name='studentstatus', - name='timestamp', - field=models.DateTimeField(auto_now_add=True), - ), - ] diff --git a/stude/student_status/serializers.py b/stude/student_status/serializers.py index 26c2a97..6c1346c 100644 --- a/stude/student_status/serializers.py +++ b/stude/student_status/serializers.py @@ -8,7 +8,7 @@ from landmarks.models import Landmark class StudentStatusSerializer(serializers.ModelSerializer): subject = serializers.SlugRelatedField( - queryset=Subject.objects.all(), slug_field='name', required=True) + queryset=Subject.objects.all(), slug_field='name', required=True, many=False) user = serializers.CharField(source='user.full_name', read_only=True) location = PointField(required=True) landmark = serializers.SlugRelatedField( @@ -32,8 +32,8 @@ class StudentStatusSerializer(serializers.ModelSerializer): def update(self, instance, validated_data): active = validated_data.get('active', None) - # subject = validated_data.get('subject', None) - + subject = validated_data.get('subject', None) + print('=====', subject, '======') # If status is set as false in the request, clear the student status if active is False: validated_data['location'] = Point(0, 0) diff --git a/stude/study_groups/migrations/0001_initial.py b/stude/study_groups/migrations/0001_initial.py index 9f77cd8..2227a51 100644 --- a/stude/study_groups/migrations/0001_initial.py +++ b/stude/study_groups/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 4.2.3 on 2023-08-06 05:55 +# Generated by Django 4.2.3 on 2023-09-03 09:32 import django.contrib.gis.db.models.fields from django.db import migrations, models diff --git a/stude/studygroup_messages/migrations/0001_initial.py b/stude/studygroup_messages/migrations/0001_initial.py index 94c52b8..3366c5c 100644 --- a/stude/studygroup_messages/migrations/0001_initial.py +++ b/stude/studygroup_messages/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 4.2.3 on 2023-08-06 05:55 +# Generated by Django 4.2.3 on 2023-09-03 09:32 from django.conf import settings from django.db import migrations, models diff --git a/stude/subjects/admin.py b/stude/subjects/admin.py index 6a58e86..f288660 100644 --- a/stude/subjects/admin.py +++ b/stude/subjects/admin.py @@ -1,4 +1,5 @@ from django.contrib import admin -from .models import Subject +from .models import Subject, SubjectInstance admin.site.register(Subject) +admin.site.register(SubjectInstance) diff --git a/stude/subjects/migrations/0001_initial.py b/stude/subjects/migrations/0001_initial.py index d500266..2f591ac 100644 --- a/stude/subjects/migrations/0001_initial.py +++ b/stude/subjects/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 4.2.3 on 2023-08-06 05:55 +# Generated by Django 4.2.3 on 2023-09-03 09:32 from django.conf import settings from django.db import migrations, models @@ -10,10 +10,10 @@ class Migration(migrations.Migration): initial = True dependencies = [ - ('semesters', '0001_initial'), - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ('courses', '0001_initial'), ('year_levels', '0001_initial'), + ('semesters', '0001_initial'), + ('courses', '0001_initial'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), ] operations = [ @@ -22,14 +22,18 @@ class Migration(migrations.Migration): fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('name', models.CharField(max_length=64)), + ('students', models.ManyToManyField(blank=True, to=settings.AUTH_USER_MODEL)), + ], + ), + migrations.CreateModel( + name='SubjectInstance', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('code', models.CharField(max_length=16)), ('course', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='courses.course')), ('semester', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='semesters.semester')), - ('students', models.ManyToManyField(blank=True, to=settings.AUTH_USER_MODEL)), + ('subject', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='subjects.subject')), ('year_level', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='year_levels.year_level')), ], - options={ - 'unique_together': {('name', 'course', 'year_level', 'semester')}, - }, ), ] diff --git a/stude/subjects/models.py b/stude/subjects/models.py index f6f86ac..d10f6dc 100644 --- a/stude/subjects/models.py +++ b/stude/subjects/models.py @@ -15,6 +15,14 @@ class Subject(models.Model): name = models.CharField(max_length=64) students = models.ManyToManyField( CustomUser, blank=True) + + def __str__(self): + return self.name + + +class SubjectInstance(models.Model): + subject = models.ForeignKey( + Subject, on_delete=models.CASCADE) code = models.CharField(max_length=16) course = models.ForeignKey( Course, on_delete=models.CASCADE) @@ -23,11 +31,8 @@ class Subject(models.Model): semester = models.ForeignKey( Semester, on_delete=models.CASCADE) - class Meta: - unique_together = ['name', 'course', 'year_level', 'semester'] - def __str__(self): - return f'Subject: {self.name}({self.code}) - {self.course.shortname} - {self.year_level} - {self.semester}' + return f'Subject: {self.subject.name}({self.code}) - {self.course.shortname} - {self.year_level} - {self.semester}' # Create subjects on initial migrate @@ -82,17 +87,32 @@ def populate_subjects(sender, **kwargs): semester = Semester.objects.filter( name=subject_semester).first() - # If subject exists, skip over - if (Subject.objects.filter(name=subject_name, course=course, year_level=year_level, semester=semester, code=subject_code).exists()): - # print('Duplicate subject') - existing_subjects += 1 - continue - - # If subject does not exist at all, then create new subject - else: - + # Check if subject exists + if (Subject.objects.filter(name=subject_name).exists()): + # If so, get the subject SUBJECT, created = Subject.objects.get_or_create( - name=subject_name, course=course, year_level=year_level, semester=semester, code=subject_code) + name=subject_name) + # Then check if subject instance exists + if (SubjectInstance.objects.filter(subject=SUBJECT, course=course, year_level=year_level, semester=semester, code=subject_code).exists()): + # If subject instance already exists, skip + existing_subjects += 1 + continue + + # If subject instance does not exist, create it + else: + SUBJECT, created = Subject.objects.get_or_create( + name=subject_name) + SUBJECT_INSTANCE, created = SubjectInstance.objects.get_or_create( + subject=SUBJECT, course=course, year_level=year_level, semester=semester, code=subject_code) + subject_count += 1 + # If subject does not exist + else: + # Create subject first + SUBJECT, created = Subject.objects.get_or_create( + name=subject_name) + # Then create instance + SUBJECT_INSTANCE, created = SubjectInstance.objects.get_or_create( + subject=SUBJECT, course=course, year_level=year_level, semester=semester, code=subject_code) subject_count += 1 # Set the course, year level, and semester of the subject diff --git a/stude/subjects/serializers.py b/stude/subjects/serializers.py index 6f9c30c..e1c7aae 100644 --- a/stude/subjects/serializers.py +++ b/stude/subjects/serializers.py @@ -1,11 +1,13 @@ from rest_framework import serializers -from .models import Subject +from .models import Subject, SubjectInstance from courses.models import Course from year_levels.models import Year_Level from semesters.models import Semester class SubjectSerializer(serializers.ModelSerializer): + year_level = serializers.SlugRelatedField( + queryset=Subject.objects.all(), slug_field='name', allow_null=False) year_level = serializers.SlugRelatedField( queryset=Year_Level.objects.all(), slug_field='name', allow_null=True) semester = serializers.SlugRelatedField( @@ -14,5 +16,5 @@ class SubjectSerializer(serializers.ModelSerializer): queryset=Course.objects.all(), slug_field='name', allow_null=True) class Meta: - model = Subject - fields = ('id', 'name', 'code', 'course', 'year_level', 'semester') + model = SubjectInstance + fields = ('id', 'subject', 'code', 'course', 'year_level', 'semester') diff --git a/stude/subjects/views.py b/stude/subjects/views.py index 865a785..f08d7a3 100644 --- a/stude/subjects/views.py +++ b/stude/subjects/views.py @@ -1,5 +1,5 @@ from rest_framework import generics, viewsets -from .models import Subject +from .models import Subject, SubjectInstance from .serializers import SubjectSerializer from rest_framework.views import APIView from rest_framework.response import Response @@ -8,12 +8,12 @@ from rest_framework.permissions import IsAuthenticated class SubjectListAllView(generics.ListAPIView): serializer_class = SubjectSerializer - queryset = Subject.objects.all() + queryset = SubjectInstance.objects.all() class SubjectListView(generics.ListAPIView): permission_classes = [IsAuthenticated] - queryset = Subject.objects.all() + queryset = SubjectInstance.objects.all() serializer_class = SubjectSerializer def get(self, request): @@ -21,14 +21,14 @@ class SubjectListView(generics.ListAPIView): user_course = user.course # If user is irregular, show all subjects in his/her course to choose from if (user.irregular): - subjects = Subject.objects.filter( + subjects = SubjectInstance.objects.filter( course__name=user_course) # Else, return subjects that match the user's student info (Year Level, Semster, Course) else: user_yearlevel = user.year_level user_semester = user.semester - subjects = Subject.objects.filter( + subjects = SubjectInstance.objects.filter( course__name=user.course, year_level__name=user_yearlevel, semester__name=user_semester) # Serialize the subjects @@ -37,12 +37,12 @@ class SubjectListView(generics.ListAPIView): class SubjectByCourseView(generics.ListAPIView): - queryset = Subject.objects.all() + queryset = SubjectInstance.objects.all() serializer_class = SubjectSerializer def get(self, request, course_slug): # Retrieve the subjects based on course slug - subjects = Subject.objects.filter( + subjects = SubjectInstance.objects.filter( course__shortname=course_slug) # Serialize the subjects diff --git a/stude/year_levels/migrations/0001_initial.py b/stude/year_levels/migrations/0001_initial.py index 0765c4b..795e5f0 100644 --- a/stude/year_levels/migrations/0001_initial.py +++ b/stude/year_levels/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 4.2.3 on 2023-08-06 05:55 +# Generated by Django 4.2.3 on 2023-09-03 09:32 from django.db import migrations, models