From de4ef9d6f48ccd2417e05393081c8c04d89b7c22 Mon Sep 17 00:00:00 2001 From: Mo8it Date: Sun, 27 Feb 2022 17:43:31 +0100 Subject: [PATCH] Move weightings from Experiment to SemesterExperiment --- DB.drawio | 2 +- advlabdb/adminModelViews.py | 56 ++++++++++++++---- advlabdb/customClasses.py | 9 ++- advlabdb/models.py | 114 ++++++++++++++++++------------------ poetry.lock | 6 +- testDB.py | 6 -- 6 files changed, 114 insertions(+), 79 deletions(-) diff --git a/DB.drawio b/DB.drawio index c36e48e..5e91ecb 100644 --- a/DB.drawio +++ b/DB.drawio @@ -1 +1 @@ -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 \ No newline at end of file +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 \ No newline at end of file diff --git a/advlabdb/adminModelViews.py b/advlabdb/adminModelViews.py index 9c1c36c..0aadda9 100644 --- a/advlabdb/adminModelViews.py +++ b/advlabdb/adminModelViews.py @@ -12,8 +12,16 @@ from flask_wtf import FlaskForm from flask_wtf.file import FileAllowed, FileField, FileRequired from sqlalchemy import and_, func, or_ from werkzeug.utils import secure_filename -from wtforms import BooleanField, Form, RadioField, SelectField, StringField -from wtforms.fields import DateField, IntegerField +from wtforms import Form +from wtforms.fields import ( + BooleanField, + DateField, + DecimalField, + IntegerField, + RadioField, + SelectField, + StringField, +) from wtforms.validators import URL, DataRequired, Email, NumberRange, Optional from advlabdb import adminSpace, app, assistantSpace, db, user_datastore @@ -523,9 +531,6 @@ class ExperimentView(SecureAdminModelView): "room", "responsibility", "duration_in_days", - "oral_weighting", - "protocol_weighting", - "final_weighting", "semester_experiments", ] @@ -538,9 +543,6 @@ class ExperimentView(SecureAdminModelView): form_args = { "wiki_link": {"validators": [URL()]}, - "oral_weighting": { - "description": "Oral and protocol weighting have to add to 1! Both are rounded to 2 decimal digits." - }, } form_extra_fields = { "program": QuerySelectField( @@ -548,9 +550,6 @@ class ExperimentView(SecureAdminModelView): ) } - def on_model_change(self, form, model, is_created): - model.checkWeightings(roundWeightings=True) - def assistantQueryFactory(): return Assistant.query.filter(Assistant.user.has(User.active == True)) @@ -569,6 +568,28 @@ class SemesterExperimentView(SecureAdminModelView): blank_text="-", ) + oral_weighting = DecimalField( + "Oral weighting", + validators=[DataRequired(), NumberRange(min=0, max=1)], + default=0.5, + description="Between 0 and 1", + places=2, + ) + protocol_weighting = DecimalField( + "Protocol weighting", + validators=[DataRequired(), NumberRange(min=0, max=1)], + default=0.5, + description="Between 0 and 1. Oral and protocol weightings have to add to 1! Both are rounded to 2 decimal digits.", + places=2, + ) + final_weighting = DecimalField( + "Final weighting", + validators=[DataRequired(), NumberRange(min=0, max=1)], + default=1.0, + description="Between 0 and 1", + places=2, + ) + assistants = QuerySelectMultipleField("Assistants", query_factory=assistantQueryFactory) form = CreateForm @@ -581,6 +602,9 @@ class SemesterExperimentView(SecureAdminModelView): "semester", ] column_details_list = column_list + [ + "oral_weighting", + "protocol_weighting", + "final_weighting", "group_experiments", ] column_filters = [ @@ -592,9 +616,17 @@ class SemesterExperimentView(SecureAdminModelView): def customCreateModel(self, form): return SemesterExperiment( - semester=userActiveSemester(), experiment=form.experiment.data, assistants=form.assistants.data + semester=userActiveSemester(), + oral_weighting=form.oral_weighting.data, + protocol_weighting=form.protocol_weighting.data, + final_weighting=form.final_weighting.data, + experiment=form.experiment.data, + assistants=form.assistants.data, ) + def on_model_change(self, form, model, is_created): + model.checkAndRoundWeightings() + class AssistantView(SecureAdminModelView): def assistantUserQueryFactory(): diff --git a/advlabdb/customClasses.py b/advlabdb/customClasses.py index 8fa0f61..c7deba0 100644 --- a/advlabdb/customClasses.py +++ b/advlabdb/customClasses.py @@ -5,7 +5,14 @@ from flask_security import current_user from sqlalchemy import and_ from advlabdb.exceptions import DataBaseException, ModelViewException -from advlabdb.models import ExperimentMark, Part, PartStudent, GroupExperiment, SemesterExperiment, Assistant +from advlabdb.models import ( + Assistant, + ExperimentMark, + GroupExperiment, + Part, + PartStudent, + SemesterExperiment, +) from advlabdb.utils import reportBadAttempt, userActiveSemester diff --git a/advlabdb/models.py b/advlabdb/models.py index 0928497..46be52a 100644 --- a/advlabdb/models.py +++ b/advlabdb/models.py @@ -85,21 +85,19 @@ class PartStudent(db.Model): groupExperiments = [] for experimentMark in self.experiment_marks: - if not (experimentMark.oral_mark and experimentMark.protocol_mark): + if None in (experimentMark.oral_mark, experimentMark.protocol_mark): + # Not all marks are set! return groupExperiment = experimentMark.group_experiment groupExperiments.append(groupExperiment) - experiment = groupExperiment.semester_experiment.experiment + semesterExperiment = groupExperiment.semester_experiment - finalWeighting = experiment.final_weighting + finalWeighting = semesterExperiment.final_weighting finalWeightingSum += finalWeighting - finalMark += finalWeighting * ( - experiment.oral_weighting * experimentMark.oral_mark - + experiment.protocol_weighting * experimentMark.protocol_mark - ) + finalMark += finalWeighting * experimentMark.final_experiment_mark if set(groupExperiments) != set(self.group.group_experiments): flash(f"{self} does not have an experiment mark for every group experiment in his group!", "warning") @@ -114,7 +112,7 @@ class PartStudent(db.Model): except Exception as ex: flash(str(ex), "error") - self.session.rollback() + db.session.rollback() else: if current_user.has_role("admin"): if oldFinalPartMark != self.final_part_mark: @@ -205,11 +203,7 @@ class GroupExperiment(db.Model): student = partStudent.student for partStudent in student.part_students: for experimentMark in partStudent.experiment_marks: - if ( - (experimentMark.oral_mark or experimentMark.protocol_mark) - and experimentMark.group_experiment.semester_experiment.experiment - == semester_experiment.experiment - ): + if experimentMark.group_experiment.semester_experiment.experiment == semester_experiment.experiment: raise Exception( f"{student} has already done {semester_experiment.experiment} in {partStudent.part} and had {experimentMark}!" ) @@ -240,45 +234,12 @@ class Experiment(db.Model): duration_in_days = db.Column(db.Integer, db.CheckConstraint("duration_in_days > 0"), nullable=False) active = db.Column(db.Boolean, default=True, nullable=False) - oral_weighting = db.Column( - db.Float, - db.CheckConstraint("oral_weighting >= 0"), - db.CheckConstraint("oral_weighting <= 1"), - default=0.5, - nullable=False, - ) - protocol_weighting = db.Column( - db.Float, - db.CheckConstraint("protocol_weighting >= 0"), - db.CheckConstraint("protocol_weighting <= 1"), - default=0.5, - nullable=False, - ) - final_weighting = db.Column( - db.Float, db.CheckConstraint("final_weighting >= 0"), db.CheckConstraint("final_weighting <= 1"), nullable=False - ) - program_id = db.Column(db.Integer, db.ForeignKey("program.id"), nullable=False) semester_experiments = db.relationship("SemesterExperiment", backref="experiment", lazy=True) __table_args__ = (db.UniqueConstraint(number, program_id),) - def checkWeightings(self, roundWeightings=False): - roundedOralWeighting = round(self.oral_weighting, 2) - roundedProtocolWeighting = round(self.protocol_weighting, 2) - - weightingSum = round(roundedOralWeighting + roundedProtocolWeighting, 2) - - if weightingSum != 1: - raise DataBaseException( - f"Oral and protocol weighting (rounded to 2 decimal digits) sum to {weightingSum} and not 1.00!" - ) - - if roundWeightings: - self.oral_weighting = roundedOralWeighting - self.protocol_weighting = roundedProtocolWeighting - def repr(self): return f"{self.number} {self.program.repr()}" @@ -297,6 +258,27 @@ experiment_assistant = db.Table( class SemesterExperiment(db.Model): # An experiment in a specific semester id = db.Column(db.Integer, primary_key=True) + oral_weighting = db.Column( + db.Float, + db.CheckConstraint("oral_weighting >= 0"), + db.CheckConstraint("oral_weighting <= 1"), + default=0.5, + nullable=False, + ) + protocol_weighting = db.Column( + db.Float, + db.CheckConstraint("protocol_weighting >= 0"), + db.CheckConstraint("protocol_weighting <= 1"), + default=0.5, + nullable=False, + ) + final_weighting = db.Column( + db.Float, + db.CheckConstraint("final_weighting >= 0"), + db.CheckConstraint("final_weighting <= 1"), + default=1.0, + nullable=False, + ) experiment_id = db.Column(db.Integer, db.ForeignKey("experiment.id"), nullable=False) semester_id = db.Column(db.Integer, db.ForeignKey("semester.id"), nullable=False) @@ -308,6 +290,20 @@ class SemesterExperiment(db.Model): __table_args__ = (db.UniqueConstraint(experiment_id, semester_id),) + def checkAndRoundWeightings(self): + roundedOralWeighting = round(self.oral_weighting, 2) + roundedProtocolWeighting = round(self.protocol_weighting, 2) + + weightingSum = round(roundedOralWeighting + roundedProtocolWeighting, 2) + + if weightingSum != 1: + raise DataBaseException( + f"Oral and protocol weightings (rounded to 2 decimal digits) sum to {weightingSum} and not 1.00!" + ) + + self.oral_weighting = roundedOralWeighting + self.protocol_weighting = roundedProtocolWeighting + def repr(self): return f"{self.experiment.repr()} {self.semester.repr()}" @@ -456,17 +452,23 @@ class ExperimentMark(db.Model): experimentMark = ExperimentMark.query.get(params["experiment_mark_id"]) - experiment = experimentMark.group_experiment.semester_experiment.experiment + oral_mark = params.get("oral_mark") + if oral_mark is None: + oral_mark = experimentMark.oral_mark + if oral_mark is None: + return - oral_mark = params.get("oral_mark") or experimentMark.oral_mark - protocol_mark = params.get("protocol_mark") or experimentMark.protocol_mark + protocol_mark = params.get("protocol_mark") + if protocol_mark is None: + protocol_mark = experimentMark.protocol_mark + if protocol_mark is None: + return - if not (oral_mark and protocol_mark): - return - else: - return roundHalfUpToInt( - experiment.oral_weighting * oral_mark + experiment.protocol_weighting * protocol_mark - ) + semesterExperiment = experimentMark.group_experiment.semester_experiment + + return roundHalfUpToInt( + semesterExperiment.oral_weighting * oral_mark + semesterExperiment.protocol_weighting * protocol_mark + ) id = db.Column(db.Integer, primary_key=True) @@ -491,7 +493,7 @@ class ExperimentMark(db.Model): nullable=True, ) - edited_by_admin = db.Column(db.Boolean, default=False, nullable=False) + edited_by_admin = db.Column(db.Boolean, default=False, nullable=False) # TODO: Admin id part_student_id = db.Column(db.Integer, db.ForeignKey("part_student.id"), nullable=False) group_experiment_id = db.Column(db.Integer, db.ForeignKey("group_experiment.id"), nullable=False) diff --git a/poetry.lock b/poetry.lock index 0a1b238..81d6b22 100644 --- a/poetry.lock +++ b/poetry.lock @@ -327,7 +327,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] name = "rope" -version = "0.22.0" +version = "0.23.0" description = "a python refactoring library..." category = "dev" optional = false @@ -625,8 +625,8 @@ pyflakes = [ {file = "pyflakes-2.4.0.tar.gz", hash = "sha256:05a85c2872edf37a4ed30b0cce2f6093e1d0581f8c19d7393122da7e25b2b24c"}, ] rope = [ - {file = "rope-0.22.0-py3-none-any.whl", hash = "sha256:2847220bf72ead09b5abe72b1edc9cacff90ab93663ece06913fc97324167870"}, - {file = "rope-0.22.0.tar.gz", hash = "sha256:b00fbc064a26fc62d7220578a27fd639b2fad57213663cc396c137e92d73f10f"}, + {file = "rope-0.23.0-py3-none-any.whl", hash = "sha256:edf2ed3c9b35a8814752ffd3ea55b293c791e5087e252461de898e953cf9c146"}, + {file = "rope-0.23.0.tar.gz", hash = "sha256:f87662c565086d660fc855cc07f37820267876634c3e9e51bddb32ff51547268"}, ] sqlalchemy = [ {file = "SQLAlchemy-1.4.31-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:c3abc34fed19fdeaead0ced8cf56dd121f08198008c033596aa6aae7cc58f59f"}, diff --git a/testDB.py b/testDB.py index 49729b3..4d34563 100644 --- a/testDB.py +++ b/testDB.py @@ -68,9 +68,6 @@ with app.app_context(): building="phy", responsibility="none", duration_in_days=2, - oral_weighting=0.5, - protocol_weighting=0.5, - final_weighting=1, ) ex2 = Experiment( @@ -81,9 +78,6 @@ with app.app_context(): building="phy", responsibility="none", duration_in_days=2, - oral_weighting=0.5, - protocol_weighting=0.5, - final_weighting=1, ) db.session.add(ex1)