From 7aa78c28078a0a33abac60d40cdb110b41fed90c Mon Sep 17 00:00:00 2001 From: Ross Date: Mon, 15 May 2023 11:12:52 +0100 Subject: [PATCH] create base useranswer class --- anatomy/filters.py | 6 ++-- .../0068_alter_ciduseranswer_options.py | 17 +++++++++++ anatomy/models.py | 13 ++------- anatomy/tables.py | 4 +-- anatomy/urls.py | 6 ++-- anatomy/views.py | 24 ++++++++-------- generic/models.py | 28 +++++++++++++++++++ generic/views.py | 2 +- longs/filters.py | 4 +-- longs/models.py | 18 ++---------- longs/tables.py | 2 +- longs/urls.py | 6 ++-- longs/views.py | 14 +++++----- physics/filters.py | 6 ++-- ...ranswer_options_alter_ciduseranswer_cid.py | 22 +++++++++++++++ physics/models.py | 8 ++---- physics/tables.py | 4 +-- physics/urls.py | 6 ++-- physics/views.py | 14 +++++----- rad/urls.py | 2 +- rapids/filters.py | 4 +-- .../0062_alter_ciduseranswer_options.py | 17 +++++++++++ rapids/models.py | 11 ++------ rapids/serializers.py | 2 +- rapids/tables.py | 2 +- rapids/urls.py | 6 ++-- rapids/views.py | 20 ++++++------- sbas/filters.py | 6 ++-- ...ranswer_options_alter_ciduseranswer_cid.py | 22 +++++++++++++++ sbas/models.py | 9 ++---- sbas/tables.py | 4 +-- sbas/urls.py | 6 ++-- sbas/views.py | 14 +++++----- 33 files changed, 198 insertions(+), 131 deletions(-) create mode 100644 anatomy/migrations/0068_alter_ciduseranswer_options.py create mode 100644 physics/migrations/0027_alter_ciduseranswer_options_alter_ciduseranswer_cid.py create mode 100644 rapids/migrations/0062_alter_ciduseranswer_options.py create mode 100644 sbas/migrations/0017_alter_ciduseranswer_options_alter_ciduseranswer_cid.py diff --git a/anatomy/filters.py b/anatomy/filters.py index 0db1e28a..18a7f8bb 100644 --- a/anatomy/filters.py +++ b/anatomy/filters.py @@ -2,7 +2,7 @@ import django_filters from .models import AnatomyQuestion, CidUserAnswer, Exam -#from generic.filters import UserAnswerFilter +#from generic.filters import CidUserAnswerFilter from django.contrib.auth.models import User @@ -46,7 +46,7 @@ class AnatomyQuestionFilter(django_filters.FilterSet): super(AnatomyQuestionFilter, self).__init__(data=data, queryset=queryset, prefix=prefix, request=request) pass -class AnatomyUserAnswerFilter(django_filters.FilterSet): +class AnatomyCidUserAnswerFilter(django_filters.FilterSet): class Meta: model= CidUserAnswer fields = ( @@ -63,5 +63,5 @@ class AnatomyUserAnswerFilter(django_filters.FilterSet): def __init__(self, data=None, queryset=None, prefix=None, strict=None, user=None, request=None): if not request.user.groups.filter(name="anatomy_checker").exists(): queryset = queryset.filter(open_access=True) | queryset.filter(author__id=request.user.id) - super(AnatomyUserAnswerFilter, self).__init__(data=data, queryset=queryset, prefix=prefix, request=request) + super(AnatomyCidUserAnswerFilter, self).__init__(data=data, queryset=queryset, prefix=prefix, request=request) pass \ No newline at end of file diff --git a/anatomy/migrations/0068_alter_ciduseranswer_options.py b/anatomy/migrations/0068_alter_ciduseranswer_options.py new file mode 100644 index 00000000..5de7f8c1 --- /dev/null +++ b/anatomy/migrations/0068_alter_ciduseranswer_options.py @@ -0,0 +1,17 @@ +# Generated by Django 4.1.4 on 2023-05-15 10:11 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('anatomy', '0067_alter_anatomyquestion_image'), + ] + + operations = [ + migrations.AlterModelOptions( + name='ciduseranswer', + options={'ordering': ['cid']}, + ), + ] diff --git a/anatomy/models.py b/anatomy/models.py index 5d192ab7..08554c1f 100644 --- a/anatomy/models.py +++ b/anatomy/models.py @@ -16,7 +16,7 @@ from sortedm2m.fields import SortedManyToManyField import string -from generic.models import CidUser, CidUserGroup, ExamUserStatus, Examination, ExamBase, QuestionNote, UserUserGroup +from generic.models import CidUser, CidUserGroup, ExamUserStatus, Examination, ExamBase, QuestionNote, CidUserAnswerBase, UserUserGroup from collections import defaultdict from helpers.images import image_as_base64 @@ -467,7 +467,7 @@ class Exam(ExamBase): @reversion.register -class CidUserAnswer(models.Model): +class CidUserAnswer(CidUserAnswerBase): """User answers by candidate""" question = models.ForeignKey( @@ -477,12 +477,6 @@ class CidUserAnswer(models.Model): answer_compare = models.TextField(max_length=500, blank=True) - cid = models.BigIntegerField( - blank=True, - null=True, - help_text="Candidate ID (limitied by BigIntegerField size)", - ) - user = models.ForeignKey( settings.AUTH_USER_MODEL, on_delete=models.CASCADE, blank=True, null=True, related_name="user_anatomy_user_answers" ) @@ -492,9 +486,6 @@ class CidUserAnswer(models.Model): Exam, related_name="cid_user_answers", on_delete=models.CASCADE, null=True ) - created = models.DateTimeField(auto_now_add=True) - updated = models.DateTimeField(auto_now=True) - score = models.CharField( max_length=1, choices=Answer.MarkOptions.choices, diff --git a/anatomy/tables.py b/anatomy/tables.py index f32a5839..7f0486d5 100644 --- a/anatomy/tables.py +++ b/anatomy/tables.py @@ -9,7 +9,7 @@ from easy_thumbnails.files import get_thumbnailer from easy_thumbnails.exceptions import InvalidImageFormatError -#from generic.tables import UserAnswerTable +#from generic.tables import CidUserAnswerTable class ImageColumn(tables.Column): @@ -64,7 +64,7 @@ class AnatomyQuestionTable(tables.Table): *args, **kwargs, ) -class AnatomyUserAnswerTable(tables.Table): +class AnatomyCidUserAnswerTable(tables.Table): select = tables.CheckBoxColumn(accessor=("pk")) delete = tables.LinkColumn( "anatomy:user_answer_delete", text="Delete", args=[A("pk")], orderable=False diff --git a/anatomy/urls.py b/anatomy/urls.py index 77d2ffe6..5ad76726 100644 --- a/anatomy/urls.py +++ b/anatomy/urls.py @@ -73,15 +73,15 @@ urlpatterns = [ ), path( "user_answers/", - views.UserAnswerTableView.as_view(), + views.CidUserAnswerTableView.as_view(), name="user_answer_table_view", ), path( - "user_answers/", views.UserAnswerView.as_view(), name="user_answer_view" + "user_answers/", views.CidUserAnswerView.as_view(), name="user_answer_view" ), path( "user_answers//delete", - views.UserAnswerDelete.as_view(), + views.CidUserAnswerDelete.as_view(), name="user_answer_delete", ), path( diff --git a/anatomy/views.py b/anatomy/views.py index 1f448b4e..31149b32 100644 --- a/anatomy/views.py +++ b/anatomy/views.py @@ -55,8 +55,8 @@ from reversion.views import RevisionMixin from .decorators import user_is_author_or_anatomy_checker -from .tables import AnatomyQuestionTable, AnatomyUserAnswerTable -from .filters import AnatomyQuestionFilter, AnatomyUserAnswerFilter +from .tables import AnatomyQuestionTable, AnatomyCidUserAnswerTable +from .filters import AnatomyQuestionFilter, AnatomyCidUserAnswerFilter from django_tables2 import SingleTableView, SingleTableMixin from django_filters.views import FilterView @@ -161,12 +161,12 @@ def answer_question(request, pk): # } # # # Get data for flagged -# # answered_questions = UserAnswer.objects.filter(user=request.user).values_list("question__pk", flat=True) -# user_answer_data = UserAnswer.objects.filter(user=request.user).values_list( +# # answered_questions = CidUserAnswer.objects.filter(user=request.user).values_list("question__pk", flat=True) +# user_answer_data = CidUserAnswer.objects.filter(user=request.user).values_list( # "question__pk", "answer", "flagged" # ) -# # flagged_questions = UserAnswer.objects.filter(user=request.user, flagged=True).values_list("question__pk", flat=True) -# # flagged_questions I= UserAnswer.filter(user=request.user, ).values_list("question__pk", flat=True) +# # flagged_questions = CidUserAnswer.objects.filter(user=request.user, flagged=True).values_list("question__pk", flat=True) +# # flagged_questions I= CidUserAnswer.filter(user=request.user, ).values_list("question__pk", flat=True) # # answered_questions = set() # flagged_questions = set() @@ -215,7 +215,7 @@ def answer_question(request, pk): # def flag_question(request): # pk = request.GET.get("pk", None) -# ans = UserAnswer.objects.filter(user=request.user, question__pk=pk).first() +# ans = CidUserAnswer.objects.filter(user=request.user, question__pk=pk).first() # ans.flagged = not ans.flagged # ans.save() # data = {"flagged": ans.flagged} @@ -737,19 +737,19 @@ GenericExamViews = ExamViews( ) -class UserAnswerView(SuperuserRequiredMixin, DetailView): +class CidUserAnswerView(SuperuserRequiredMixin, DetailView): model = CidUserAnswer -class UserAnswerTableView(SuperuserRequiredMixin, SingleTableMixin, FilterView): +class CidUserAnswerTableView(SuperuserRequiredMixin, SingleTableMixin, FilterView): model = CidUserAnswer - table_class = AnatomyUserAnswerTable + table_class = AnatomyCidUserAnswerTable template_name = "anatomy/user_answer_question_view.html" - filterset_class = AnatomyUserAnswerFilter + filterset_class = AnatomyCidUserAnswerFilter -class UserAnswerDelete(SuperuserRequiredMixin, DeleteView): +class CidUserAnswerDelete(SuperuserRequiredMixin, DeleteView): model = CidUserAnswer template_name = "user_answer_delete.html" success_url = reverse_lazy("anatomy:user_answer_table_view") diff --git a/generic/models.py b/generic/models.py index 137e5732..d0e2ffa4 100644 --- a/generic/models.py +++ b/generic/models.py @@ -394,6 +394,34 @@ class ExamUserStatus(models.Model): return f"{self.datetime}: {user} - {self.status} ({self.extra})" +class CidUserAnswerBase(models.Model): + + cid = models.BigIntegerField( + blank=True, + null=True, + help_text="Candidate ID (limitied by BigIntegerField size)", + ) + + created = models.DateTimeField(auto_now_add=True) + updated = models.DateTimeField(auto_now=True) + + + class Meta: + abstract = True + ordering = ["cid"] + + def get_candidate_name(self) -> str: + if self.cid is not None: + return str(self.cid) + else: + return self.user.username + + def get_candidate_masked(self) -> str: + if self.cid is not None: + return str(self.cid) + else: + return str(self.user.id) + class NoteType(models.Model): note_type = models.CharField(max_length=200) diff --git a/generic/views.py b/generic/views.py index 1917d1a0..20e2dced 100644 --- a/generic/views.py +++ b/generic/views.py @@ -1527,7 +1527,7 @@ class ExamViews(View, LoginRequiredMixin): n = n + 1 - # print(UserAnswer.objects.filter(exam__id=q["eid"])) + # print(CidUserAnswer.objects.filter(exam__id=q["eid"])) # print(request.urlencode()) exam_type, exam_id = request.POST.get("eid").split("/") diff --git a/longs/filters.py b/longs/filters.py index a3d8c5bc..4d7004c5 100755 --- a/longs/filters.py +++ b/longs/filters.py @@ -53,7 +53,7 @@ class LongSeriesFilter(django_filters.FilterSet): super(LongSeriesFilter, self).__init__(data=data, queryset=queryset, prefix=prefix, request=request) pass -class UserAnswerFilter(django_filters.FilterSet): +class CidUserAnswerFilter(django_filters.FilterSet): class Meta: model = CidUserAnswer fields = ( @@ -69,5 +69,5 @@ class UserAnswerFilter(django_filters.FilterSet): def __init__(self, data=None, queryset=None, prefix=None, strict=None, user=None, request=None): if not request.user.groups.filter(name="long_checker").exists(): queryset = queryset.filter(open_access=True) | queryset.filter(author__id=request.user.id) - super(UserAnswerFilter, self).__init__(data=data, queryset=queryset, prefix=prefix, request=request) + super(CidUserAnswerFilter, self).__init__(data=data, queryset=queryset, prefix=prefix, request=request) pass \ No newline at end of file diff --git a/longs/models.py b/longs/models.py index 1b50142f..27cc4ed6 100644 --- a/longs/models.py +++ b/longs/models.py @@ -38,6 +38,7 @@ from generic.models import ( Plane, Contrast, QuestionNote, + CidUserAnswerBase, UserUserGroup, ) @@ -752,7 +753,7 @@ class Exam(ExamBase): @reversion.register -class CidUserAnswer(models.Model): +class CidUserAnswer(CidUserAnswerBase): """User answers by candidate""" question = models.ForeignKey( @@ -812,11 +813,7 @@ class CidUserAnswer(models.Model): # "AnswerMarks", related_name="user_answer", on_delete=models.SET_NULL, null=True, blank=True # ) - created = models.DateTimeField(auto_now_add=True) - updated = models.DateTimeField(auto_now=True) - class Meta: - ordering = ["cid"] def __str__(self): try: @@ -885,17 +882,6 @@ class CidUserAnswer(models.Model): def get_absolute_url(self): return reverse("longs:user_answer_view", kwargs={"pk": self.pk}) - def get_candidate_name(self) -> str: - if self.cid is not None: - return str(self.cid) - else: - return self.user.username - - def get_candidate_masked(self) -> str: - if self.cid is not None: - return str(self.cid) - else: - return str(self.user.id) @reversion.register diff --git a/longs/tables.py b/longs/tables.py index 4d8f6d37..72e98702 100755 --- a/longs/tables.py +++ b/longs/tables.py @@ -130,7 +130,7 @@ class LongSeriesTable(tables.Table): print(self) return format_html("""Popup""", record.pk) -class UserAnswerTable(tables.Table): +class CidUserAnswerTable(tables.Table): select = tables.CheckBoxColumn(accessor=("pk")) delete = tables.LinkColumn( "longs:user_answer_delete", text="Delete", args=[A("pk")], orderable=False diff --git a/longs/urls.py b/longs/urls.py index 895aaef8..e30f4b70 100755 --- a/longs/urls.py +++ b/longs/urls.py @@ -136,15 +136,15 @@ urlpatterns = [ ), path( "user_answers/", - views.UserAnswerTableView.as_view(), + views.CidUserAnswerTableView.as_view(), name="user_answer_table_view", ), path( - "user_answers/", views.UserAnswerView.as_view(), name="user_answer_view" + "user_answers/", views.CidUserAnswerView.as_view(), name="user_answer_view" ), path( "user_answers//delete", - views.UserAnswerDelete.as_view(), + views.CidUserAnswerDelete.as_view(), name="user_answer_delete", ), path( diff --git a/longs/views.py b/longs/views.py index 1e8a14a4..4b8286ee 100755 --- a/longs/views.py +++ b/longs/views.py @@ -43,8 +43,8 @@ from .models import ( Exam, CidUserAnswer, ) -from .tables import LongTable, LongSeriesTable, UserAnswerTable -from .filters import LongFilter, LongSeriesFilter, UserAnswerFilter +from .tables import LongTable, LongSeriesTable, CidUserAnswerTable +from .filters import LongFilter, LongSeriesFilter, CidUserAnswerFilter from django_tables2 import SingleTableView, SingleTableMixin from django_filters.views import FilterView @@ -1194,19 +1194,19 @@ def question_json_recreate(request, pk): return redirect("longs:question_detail", pk=pk) -class UserAnswerView(LoginRequiredMixin, DetailView): +class CidUserAnswerView(LoginRequiredMixin, DetailView): model = CidUserAnswer -class UserAnswerTableView(LoginRequiredMixin, SingleTableMixin, FilterView): +class CidUserAnswerTableView(LoginRequiredMixin, SingleTableMixin, FilterView): model = CidUserAnswer - table_class = UserAnswerTable + table_class = CidUserAnswerTable template_name = "longs/user_answer_question_view.html" - filterset_class = UserAnswerFilter + filterset_class = CidUserAnswerFilter -class UserAnswerDelete(SuperuserRequiredMixin, DeleteView): +class CidUserAnswerDelete(SuperuserRequiredMixin, DeleteView): model = CidUserAnswer template_name = "user_answer_delete.html" success_url = reverse_lazy("longs:user_answer_table_view") diff --git a/physics/filters.py b/physics/filters.py index 67c65404..be6b1811 100644 --- a/physics/filters.py +++ b/physics/filters.py @@ -2,7 +2,7 @@ import django_filters from .models import Category, Question, CidUserAnswer, Exam -#from generic.filters import UserAnswerFilter +#from generic.filters import CidUserAnswerFilter from django.contrib.auth.models import User @@ -43,7 +43,7 @@ class QuestionFilter(django_filters.FilterSet): super(QuestionFilter, self).__init__(data=data, queryset=queryset, prefix=prefix, request=request) pass -class UserAnswerFilter(django_filters.FilterSet): +class CidUserAnswerFilter(django_filters.FilterSet): class Meta: model= CidUserAnswer fields = ( @@ -59,5 +59,5 @@ class UserAnswerFilter(django_filters.FilterSet): def __init__(self, data=None, queryset=None, prefix=None, strict=None, user=None, request=None): if not request.user.groups.filter(name="physics_checker").exists(): queryset = queryset.filter(author__id=request.user.id) - super(UserAnswerFilter, self).__init__(data=data, queryset=queryset, prefix=prefix, request=request) + super(CidUserAnswerFilter, self).__init__(data=data, queryset=queryset, prefix=prefix, request=request) pass \ No newline at end of file diff --git a/physics/migrations/0027_alter_ciduseranswer_options_alter_ciduseranswer_cid.py b/physics/migrations/0027_alter_ciduseranswer_options_alter_ciduseranswer_cid.py new file mode 100644 index 00000000..30956076 --- /dev/null +++ b/physics/migrations/0027_alter_ciduseranswer_options_alter_ciduseranswer_cid.py @@ -0,0 +1,22 @@ +# Generated by Django 4.1.4 on 2023-05-15 10:11 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('physics', '0026_remove_exam_stats_graph'), + ] + + operations = [ + migrations.AlterModelOptions( + name='ciduseranswer', + options={'ordering': ['cid']}, + ), + migrations.AlterField( + model_name='ciduseranswer', + name='cid', + field=models.BigIntegerField(blank=True, help_text='Candidate ID (limitied by BigIntegerField size)', null=True), + ), + ] diff --git a/physics/models.py b/physics/models.py index 187aab17..88bc78e4 100644 --- a/physics/models.py +++ b/physics/models.py @@ -12,7 +12,7 @@ from django.utils.translation import gettext_lazy as _ from sortedm2m.fields import SortedManyToManyField -from generic.models import CidUser, CidUserGroup, ExamBase, ExamUserStatus, QuestionNote, UserUserGroup +from generic.models import CidUser, CidUserGroup, ExamBase, ExamUserStatus, QuestionNote, CidUserAnswerBase, UserUserGroup import reversion @@ -182,7 +182,7 @@ class Exam(ExamBase): @reversion.register -class CidUserAnswer(models.Model): +class CidUserAnswer(CidUserAnswerBase): """User answers by candidate""" question = models.ForeignKey( @@ -194,8 +194,6 @@ class CidUserAnswer(models.Model): d = models.BooleanField(blank=False) e = models.BooleanField(blank=False) - cid = models.IntegerField(blank=True, null=True) - user = models.ForeignKey( settings.AUTH_USER_MODEL, on_delete=models.CASCADE, @@ -209,8 +207,6 @@ class CidUserAnswer(models.Model): Exam, related_name="cid_user_answers", on_delete=models.CASCADE, null=True ) - created = models.DateTimeField(auto_now_add=True) - updated = models.DateTimeField(auto_now=True) def __str__(self): return "{}/{}/{}".format(self.cid, self.exam, self.question.pk) diff --git a/physics/tables.py b/physics/tables.py index 7bd70145..bcbd9c69 100644 --- a/physics/tables.py +++ b/physics/tables.py @@ -10,7 +10,7 @@ from django.utils.html import format_html # from easy_thumbnails.exceptions import InvalidImageFormatError -# from generic.tables import UserAnswerTable +# from generic.tables import CidUserAnswerTable # class ImageColumn(tables.Column): @@ -75,7 +75,7 @@ class QuestionTable(tables.Table): return mark_safe(value) -class UserAnswerTable(tables.Table): +class CidUserAnswerTable(tables.Table): select = tables.CheckBoxColumn(accessor=("pk")) # delete = tables.LinkColumn( # "physics:user_answer_delete", text="Delete", args=[A("pk")], orderable=False diff --git a/physics/urls.py b/physics/urls.py index 37129187..7980baa8 100644 --- a/physics/urls.py +++ b/physics/urls.py @@ -51,17 +51,17 @@ urlpatterns.extend( # path("exam/json//recreate", views.exam_json_recreate, name="exam_json_recreate"), path( "user_answers/", - views.UserAnswerTableView.as_view(), + views.CidUserAnswerTableView.as_view(), name="user_answer_table_view", ), path( "user_answers/", - views.UserAnswerView.as_view(), + views.CidUserAnswerView.as_view(), name="user_answer_view", ), path( "user_answers//delete", - views.UserAnswerDelete.as_view(), + views.CidUserAnswerDelete.as_view(), name="user_answer_delete", ), path( diff --git a/physics/views.py b/physics/views.py index b3942068..4369e2bc 100644 --- a/physics/views.py +++ b/physics/views.py @@ -2,9 +2,9 @@ from django.contrib.contenttypes.models import ContentType from django.utils import timezone from generic.models import CidUser from physics.decorators import user_is_author_or_physics_checker -from physics.filters import QuestionFilter, UserAnswerFilter +from physics.filters import QuestionFilter, CidUserAnswerFilter from generic.mixins import SuperuserRequiredMixin -from physics.tables import QuestionTable, UserAnswerTable +from physics.tables import QuestionTable, CidUserAnswerTable from django.shortcuts import render, get_object_or_404, redirect from django.views.decorators.csrf import csrf_exempt from django import forms @@ -457,21 +457,21 @@ class QuestionView( -class UserAnswerView(AuthorOrCheckerRequiredMixin, LoginRequiredMixin, DetailView): +class CidUserAnswerView(AuthorOrCheckerRequiredMixin, LoginRequiredMixin, DetailView): model = CidUserAnswer -class UserAnswerTableView( +class CidUserAnswerTableView( AuthorOrCheckerRequiredMixin, LoginRequiredMixin, SingleTableMixin, FilterView ): model = CidUserAnswer - table_class = UserAnswerTable + table_class = CidUserAnswerTable template_name = "physics/user_answer_question_view.html" - filterset_class = UserAnswerFilter + filterset_class = CidUserAnswerFilter -class UserAnswerDelete(SuperuserRequiredMixin, DeleteView): +class CidUserAnswerDelete(SuperuserRequiredMixin, DeleteView): model = CidUserAnswer template_name = "user_answer_delete.html" success_url = reverse_lazy("physics:user_answer_table_view") diff --git a/rad/urls.py b/rad/urls.py index a1e93057..a53bb66d 100644 --- a/rad/urls.py +++ b/rad/urls.py @@ -47,7 +47,7 @@ router_drf = routers.DefaultRouter() #) #router_drf.register( # r"rapids/user_answer", -# rapid_views.UserAnswerViewSet, +# rapid_views.CidUserAnswerViewSet, # basename="rapid-question-answers", #) #router_drf.register(r"rapids", rapid_views.RapidViewSet, basename="rapid") diff --git a/rapids/filters.py b/rapids/filters.py index 5c517cd4..d73828fa 100755 --- a/rapids/filters.py +++ b/rapids/filters.py @@ -68,7 +68,7 @@ class RapidFilter(django_filters.FilterSet): pass -class RapidUserAnswerFilter(django_filters.FilterSet): +class RapidCidUserAnswerFilter(django_filters.FilterSet): class Meta: model = CidUserAnswer fields = ( @@ -95,7 +95,7 @@ class RapidUserAnswerFilter(django_filters.FilterSet): queryset = queryset.filter(open_access=True) | queryset.filter( author__id=request.user.id ) - super(RapidUserAnswerFilter, self).__init__( + super(RapidCidUserAnswerFilter, self).__init__( data=data, queryset=queryset, prefix=prefix, request=request ) pass diff --git a/rapids/migrations/0062_alter_ciduseranswer_options.py b/rapids/migrations/0062_alter_ciduseranswer_options.py new file mode 100644 index 00000000..885fc003 --- /dev/null +++ b/rapids/migrations/0062_alter_ciduseranswer_options.py @@ -0,0 +1,17 @@ +# Generated by Django 4.1.4 on 2023-05-15 10:11 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('rapids', '0061_remove_exam_stats_graph'), + ] + + operations = [ + migrations.AlterModelOptions( + name='ciduseranswer', + options={'ordering': ['cid']}, + ), + ] diff --git a/rapids/models.py b/rapids/models.py index 82dbf7aa..adaa81b3 100644 --- a/rapids/models.py +++ b/rapids/models.py @@ -34,6 +34,7 @@ from generic.models import ( #Sign, ExamBase, QuestionNote, + CidUserAnswerBase, UserUserGroup, ) @@ -768,7 +769,7 @@ class Exam(ExamBase): @reversion.register -class CidUserAnswer(models.Model): +class CidUserAnswer(CidUserAnswerBase): """User answers by candidate""" question = models.ForeignKey( @@ -781,11 +782,6 @@ class CidUserAnswer(models.Model): answer_compare = models.TextField(max_length=500, blank=True) - cid = models.BigIntegerField( - blank=True, - null=True, - help_text="Candidate ID (limitied by BigIntegerField size)", - ) user = models.ForeignKey( settings.AUTH_USER_MODEL, @@ -800,9 +796,6 @@ class CidUserAnswer(models.Model): Exam, related_name="cid_user_answers", on_delete=models.CASCADE, null=True ) - created = models.DateTimeField(auto_now_add=True) - updated = models.DateTimeField(auto_now=True) - score = models.CharField( max_length=1, choices=Answer.MarkOptions.choices, diff --git a/rapids/serializers.py b/rapids/serializers.py index 06114db7..7a957888 100644 --- a/rapids/serializers.py +++ b/rapids/serializers.py @@ -18,7 +18,7 @@ class QuestionAnswerSerializer(serializers.HyperlinkedModelSerializer): fields = ('id', 'question', 'answer', "answer_compare", "status") view_name = "rapid-exam" -class UserAnswerSerializer(serializers.HyperlinkedModelSerializer): +class CidUserAnswerSerializer(serializers.HyperlinkedModelSerializer): exam = serializers.HyperlinkedRelatedField(view_name='rapid-exam-detail', read_only=True ) diff --git a/rapids/tables.py b/rapids/tables.py index d7dd9bb8..a2b3d45e 100755 --- a/rapids/tables.py +++ b/rapids/tables.py @@ -66,7 +66,7 @@ class RapidTable(tables.Table): **kwargs, ) -class RapidUserAnswerTable(tables.Table): +class RapidCidUserAnswerTable(tables.Table): select = tables.CheckBoxColumn(accessor=("pk")) delete = tables.LinkColumn( "rapids:user_answer_delete", text="Delete", args=[A("pk")], orderable=False diff --git a/rapids/urls.py b/rapids/urls.py index a8aa8a8a..5dc08a11 100755 --- a/rapids/urls.py +++ b/rapids/urls.py @@ -83,15 +83,15 @@ urlpatterns = [ ), path( "user_answers/", - views.UserAnswerTableView.as_view(), + views.CidUserAnswerTableView.as_view(), name="user_answer_table_view", ), path( - "user_answers/", views.UserAnswerView.as_view(), name="user_answer_view" + "user_answers/", views.CidUserAnswerView.as_view(), name="user_answer_view" ), path( "user_answers//delete", - views.UserAnswerDelete.as_view(), + views.CidUserAnswerDelete.as_view(), name="user_answer_delete", ), path( diff --git a/rapids/views.py b/rapids/views.py index 5b4e8cac..cc64af47 100755 --- a/rapids/views.py +++ b/rapids/views.py @@ -54,8 +54,8 @@ from generic.views import ( from reversion.views import RevisionMixin -from .tables import RapidTable, RapidUserAnswerTable -from .filters import RapidFilter, RapidUserAnswerFilter +from .tables import RapidTable, RapidCidUserAnswerTable +from .filters import RapidFilter, RapidCidUserAnswerFilter from django_tables2 import SingleTableView, SingleTableMixin from django_filters.views import FilterView @@ -86,7 +86,7 @@ from .serializers import ( QuestionAnswerSerializer, RapidLateralitySerializer, RapidSerializer, - UserAnswerSerializer, + CidUserAnswerSerializer, ) from generic.mixins import SuperuserRequiredMixin @@ -717,19 +717,19 @@ class ExamAuthorUpdate( -class UserAnswerView(LoginRequiredMixin, DetailView): +class CidUserAnswerView(LoginRequiredMixin, DetailView): model = CidUserAnswer -class UserAnswerTableView(LoginRequiredMixin, SingleTableMixin, FilterView): +class CidUserAnswerTableView(LoginRequiredMixin, SingleTableMixin, FilterView): model = CidUserAnswer - table_class = RapidUserAnswerTable + table_class = RapidCidUserAnswerTable template_name = "rapids/user_answer_question_view.html" - filterset_class = RapidUserAnswerFilter + filterset_class = RapidCidUserAnswerFilter -class UserAnswerDelete(SuperuserRequiredMixin, DeleteView): +class CidUserAnswerDelete(SuperuserRequiredMixin, DeleteView): model = CidUserAnswer template_name = "user_answer_delete.html" success_url = reverse_lazy("rapids:user_answer_table_view") @@ -768,9 +768,9 @@ class ExamViewSet(RevisionMixin, viewsets.ModelViewSet): # permission_classes = [permissions.IsAuthenticated] # # -#class UserAnswerViewSet(viewsets.ModelViewSet): +#class CidUserAnswerViewSet(viewsets.ModelViewSet): # queryset = CidUserAnswer.objects.all() # .order_by('name') -# serializer_class = UserAnswerSerializer +# serializer_class = CidUserAnswerSerializer # permission_classes = [permissions.IsAuthenticated] diff --git a/sbas/filters.py b/sbas/filters.py index bdd8be19..e89cb860 100644 --- a/sbas/filters.py +++ b/sbas/filters.py @@ -2,7 +2,7 @@ import django_filters from .models import Category, Question, CidUserAnswer, Exam -#from generic.filters import UserAnswerFilter +#from generic.filters import CidUserAnswerFilter from django.contrib.auth.models import User @@ -43,7 +43,7 @@ class QuestionFilter(django_filters.FilterSet): super(QuestionFilter, self).__init__(data=data, queryset=queryset, prefix=prefix, request=request) pass -class UserAnswerFilter(django_filters.FilterSet): +class CidUserAnswerFilter(django_filters.FilterSet): class Meta: model= CidUserAnswer fields = ( @@ -59,5 +59,5 @@ class UserAnswerFilter(django_filters.FilterSet): def __init__(self, data=None, queryset=None, prefix=None, strict=None, user=None, request=None): if not request.user.groups.filter(name="sba_checker").exists(): queryset = queryset.filter(open_access=True) | queryset.filter(author__id=request.user.id) - super(UserAnswerFilter, self).__init__(data=data, queryset=queryset, prefix=prefix, request=request) + super(CidUserAnswerFilter, self).__init__(data=data, queryset=queryset, prefix=prefix, request=request) pass \ No newline at end of file diff --git a/sbas/migrations/0017_alter_ciduseranswer_options_alter_ciduseranswer_cid.py b/sbas/migrations/0017_alter_ciduseranswer_options_alter_ciduseranswer_cid.py new file mode 100644 index 00000000..4b5c94b4 --- /dev/null +++ b/sbas/migrations/0017_alter_ciduseranswer_options_alter_ciduseranswer_cid.py @@ -0,0 +1,22 @@ +# Generated by Django 4.1.4 on 2023-05-15 10:11 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('sbas', '0016_remove_exam_stats_graph'), + ] + + operations = [ + migrations.AlterModelOptions( + name='ciduseranswer', + options={'ordering': ['cid']}, + ), + migrations.AlterField( + model_name='ciduseranswer', + name='cid', + field=models.BigIntegerField(blank=True, help_text='Candidate ID (limitied by BigIntegerField size)', null=True), + ), + ] diff --git a/sbas/models.py b/sbas/models.py index 6514694c..e339d1d8 100644 --- a/sbas/models.py +++ b/sbas/models.py @@ -11,7 +11,7 @@ from django.utils.translation import gettext_lazy as _ from sortedm2m.fields import SortedManyToManyField -from generic.models import CidUser, CidUserGroup, ExamBase, ExamUserStatus, QuestionNote, UserUserGroup +from generic.models import CidUser, CidUserGroup, ExamBase, ExamUserStatus, QuestionNote, CidUserAnswerBase, UserUserGroup import reversion @@ -205,7 +205,7 @@ class Exam(ExamBase): @reversion.register -class CidUserAnswer(models.Model): +class CidUserAnswer(CidUserAnswerBase): """User answers by candidate""" question = models.ForeignKey( @@ -217,8 +217,6 @@ class CidUserAnswer(models.Model): help_text="The correct answer", ) - cid = models.IntegerField(blank=True, null=True) - user = models.ForeignKey( settings.AUTH_USER_MODEL, on_delete=models.CASCADE, @@ -232,9 +230,6 @@ class CidUserAnswer(models.Model): Exam, related_name="cid_user_answers", on_delete=models.CASCADE, null=True ) - created = models.DateTimeField(auto_now_add=True) - updated = models.DateTimeField(auto_now=True) - def __str__(self): return "{}/{}/{}".format(self.cid, self.exam, self.question.pk) diff --git a/sbas/tables.py b/sbas/tables.py index 6134af7d..04311619 100644 --- a/sbas/tables.py +++ b/sbas/tables.py @@ -10,7 +10,7 @@ from django.utils.html import format_html #from easy_thumbnails.exceptions import InvalidImageFormatError -#from generic.tables import UserAnswerTable +#from generic.tables import CidUserAnswerTable #class ImageColumn(tables.Column): @@ -69,7 +69,7 @@ class QuestionTable(tables.Table): return mark_safe(value) -class UserAnswerTable(tables.Table): +class CidUserAnswerTable(tables.Table): select = tables.CheckBoxColumn(accessor=("pk")) #delete = tables.LinkColumn( # "sbas:user_answer_delete", text="Delete", args=[A("pk")], orderable=False diff --git a/sbas/urls.py b/sbas/urls.py index 2fb30b1b..3d726d62 100644 --- a/sbas/urls.py +++ b/sbas/urls.py @@ -50,15 +50,15 @@ urlpatterns = [ # path("exam/json//recreate", views.exam_json_recreate, name="exam_json_recreate"), path( "user_answers/", - views.UserAnswerTableView.as_view(), + views.CidUserAnswerTableView.as_view(), name="user_answer_table_view", ), path( - "user_answers/", views.UserAnswerView.as_view(), name="user_answer_view" + "user_answers/", views.CidUserAnswerView.as_view(), name="user_answer_view" ), path( "user_answers//delete", - views.UserAnswerDelete.as_view(), + views.CidUserAnswerDelete.as_view(), name="user_answer_delete", ), path( diff --git a/sbas/views.py b/sbas/views.py index cb63bf1f..7d6b4033 100644 --- a/sbas/views.py +++ b/sbas/views.py @@ -48,8 +48,8 @@ from rest_framework.pagination import PageNumberPagination from django.core.exceptions import PermissionDenied -from .tables import QuestionTable, UserAnswerTable -from .filters import QuestionFilter, UserAnswerFilter +from .tables import QuestionTable, CidUserAnswerTable +from .filters import QuestionFilter, CidUserAnswerFilter from .forms import ( QuestionForm, @@ -404,19 +404,19 @@ class QuestionClone(QuestionCreateBase): return initial_data -class UserAnswerView(LoginRequiredMixin, DetailView): +class CidUserAnswerView(LoginRequiredMixin, DetailView): model = CidUserAnswer -class UserAnswerTableView(LoginRequiredMixin, SingleTableMixin, FilterView): +class CidUserAnswerTableView(LoginRequiredMixin, SingleTableMixin, FilterView): model = CidUserAnswer - table_class = UserAnswerTable + table_class = CidUserAnswerTable template_name = "sbas/user_answer_question_view.html" - filterset_class = UserAnswerFilter + filterset_class = CidUserAnswerFilter -class UserAnswerDelete(SuperuserRequiredMixin, DeleteView): +class CidUserAnswerDelete(SuperuserRequiredMixin, DeleteView): model = CidUserAnswer template_name = "user_answer_delete.html" success_url = reverse_lazy("sbas:user_answer_table_view")