WIP: definition base en SQLAlchemy

This commit is contained in:
Emmanuel Viennet 2021-08-08 16:01:10 +02:00
parent 186440293d
commit 1375c195ca
11 changed files with 56 additions and 53 deletions

View File

@ -128,6 +128,3 @@ def create_app(config_class=Config):
app.logger.info("ScoDoc8 startup") app.logger.info("ScoDoc8 startup")
return app return app
# from app import models

View File

@ -17,17 +17,17 @@ class NotesFormation(db.Model):
formation_id = db.synonym("id") formation_id = db.synonym("id")
acronyme = db.Column(db.String(SHORT_STR_LEN), nullable=False) acronyme = db.Column(db.String(SHORT_STR_LEN), nullable=False)
titre = db.Column(db.Text(), nullable=False) titre = db.Column(db.Text(), nullable=False)
titre_officiel = db.Column(db.Text(), nullable=False)
version = db.Column(db.Integer, default=1) version = db.Column(db.Integer, default=1)
formation_code = db.Column(db.String(SHORT_STR_LEN), nullable=False) formation_code = db.Column(
db.String(SHORT_STR_LEN),
server_default=db.text("notes_newid_fcod()"),
nullable=False,
)
# nb: la fonction SQL notes_newid_fcod doit être créée à part
type_parcours = db.Column(db.Integer, default=0) type_parcours = db.Column(db.Integer, default=0)
code_specialite = db.Column(db.String(SHORT_STR_LEN)) code_specialite = db.Column(db.String(SHORT_STR_LEN))
def __init__(self, **kwargs):
super(NotesFormation, self).__init__(**kwargs)
if self.formation_code is None:
# génère formation_code à la création
self.formation_code = f"FCOD{self.id:03d}"
class NotesUE(db.Model): class NotesUE(db.Model):
"""Unité d'Enseignement""" """Unité d'Enseignement"""
@ -43,7 +43,13 @@ class NotesUE(db.Model):
# Type d'UE: 0 normal ("fondamentale"), 1 "sport", 2 "projet et stage (LP)", # Type d'UE: 0 normal ("fondamentale"), 1 "sport", 2 "projet et stage (LP)",
# 4 "élective" # 4 "élective"
type = db.Column(db.Integer, default=0) type = db.Column(db.Integer, default=0)
ue_code = db.Column(db.String(SHORT_STR_LEN), nullable=False) # Les UE sont "compatibles" (pour la capitalisation) ssi elles ont ^m code
# note: la fonction SQL notes_newid_ucod doit être créée à part
ue_code = db.Column(
db.String(SHORT_STR_LEN),
server_default=db.text("notes_newid_ucod()"),
nullable=False,
)
ects = db.Column(db.Float) # nombre de credits ECTS ects = db.Column(db.Float) # nombre de credits ECTS
is_external = db.Column(db.Boolean(), nullable=False, default=False) is_external = db.Column(db.Boolean(), nullable=False, default=False)
# id de l'element pedagogique Apogee correspondant: # id de l'element pedagogique Apogee correspondant:
@ -51,12 +57,6 @@ class NotesUE(db.Model):
# coef UE, utilise seulement si l'option use_ue_coefs est activée: # coef UE, utilise seulement si l'option use_ue_coefs est activée:
coefficient = db.Column(db.Float) coefficient = db.Column(db.Float)
def __init__(self, **kwargs):
super(NotesUE, self).__init__(**kwargs)
if self.ue_code is None:
# génère code à la création
self.ue_code = f"UCOD{self.ue_id:03d}"
class NotesMatiere(db.Model): class NotesMatiere(db.Model):
"""Matières: regroupe les modules d'une UE """Matières: regroupe les modules d'une UE

View File

@ -54,6 +54,7 @@ class GroupDescr(db.Model):
group_membership = db.Table( group_membership = db.Table(
"group_membership", "group_membership",
db.Column("id", db.Integer, primary_key=True), # was group_membership_id
db.Column("etudid", db.Integer, db.ForeignKey("identite.id")), db.Column("etudid", db.Integer, db.ForeignKey("identite.id")),
db.Column("group_id", db.Integer, db.ForeignKey("group_descr.id")), db.Column("group_id", db.Integer, db.ForeignKey("group_descr.id")),
db.UniqueConstraint("etudid", "group_id"), db.UniqueConstraint("etudid", "group_id"),

View File

@ -93,7 +93,9 @@ def SimpleDictFetch(query, args, cursor=None):
def DBInsertDict(cnx, table, vals, commit=0, convert_empty_to_nulls=1): def DBInsertDict(cnx, table, vals, commit=0, convert_empty_to_nulls=1):
"insert into table values in dict 'vals'" """insert into table values in dict 'vals'
Return: id de l'object créé
"""
cursor = cnx.cursor(cursor_factory=ScoDocCursor) cursor = cnx.cursor(cursor_factory=ScoDocCursor)
if convert_empty_to_nulls: if convert_empty_to_nulls:
for col in vals.keys(): for col in vals.keys():
@ -112,7 +114,8 @@ def DBInsertDict(cnx, table, vals, commit=0, convert_empty_to_nulls=1):
) )
else: else:
cursor.execute("insert into %s default values" % table) cursor.execute("insert into %s default values" % table)
oid = cursor.lastrowid cursor.execute(f"SELECT CURRVAL('{table}_id_seq')") # id créé
oid = cursor.fetchone()[0]
except: except:
log("DBInsertDict: EXCEPTION !") log("DBInsertDict: EXCEPTION !")
log("DBInsertDict: table=%s, vals=%s" % (str(table), str(vals))) log("DBInsertDict: table=%s, vals=%s" % (str(table), str(vals)))
@ -272,7 +275,6 @@ class EditableTable(object):
input_formators={}, input_formators={},
aux_tables=[], aux_tables=[],
convert_null_outputs_to_empty=True, convert_null_outputs_to_empty=True,
allow_set_id=False,
html_quote=True, html_quote=True,
fields_creators={}, # { field : [ sql_command_to_create_it ] } fields_creators={}, # { field : [ sql_command_to_create_it ] }
filter_nulls=True, # dont allow to set fields to null filter_nulls=True, # dont allow to set fields to null
@ -281,11 +283,16 @@ class EditableTable(object):
self.id_name = id_name self.id_name = id_name
self.aux_tables = aux_tables self.aux_tables = aux_tables
self.dbfields = dbfields self.dbfields = dbfields
# DB remove object_id ("id" in db)
try:
i = self.dbfields.index(id_name)
self.dbfields = self.dbfields[:i] + self.dbfields[i + 1 :]
except ValueError:
pass
self.sortkey = sortkey self.sortkey = sortkey
self.output_formators = output_formators self.output_formators = output_formators
self.input_formators = input_formators self.input_formators = input_formators
self.convert_null_outputs_to_empty = convert_null_outputs_to_empty self.convert_null_outputs_to_empty = convert_null_outputs_to_empty
self.allow_set_id = allow_set_id
self.html_quote = html_quote self.html_quote = html_quote
self.fields_creators = fields_creators self.fields_creators = fields_creators
self.filter_nulls = filter_nulls self.filter_nulls = filter_nulls
@ -294,7 +301,7 @@ class EditableTable(object):
def create(self, cnx, args): def create(self, cnx, args):
"create object in table" "create object in table"
vals = dictfilter(args, self.dbfields, self.filter_nulls) vals = dictfilter(args, self.dbfields, self.filter_nulls)
if self.id_name in vals and not self.allow_set_id: if self.id_name in vals:
del vals[self.id_name] del vals[self.id_name]
if self.html_quote: if self.html_quote:
quote_dict(vals) # quote all HTML markup quote_dict(vals) # quote all HTML markup
@ -303,14 +310,7 @@ class EditableTable(object):
if title in self.input_formators: if title in self.input_formators:
vals[title] = self.input_formators[title](vals[title]) vals[title] = self.input_formators[title](vals[title])
# insert # insert
oid = DBInsertDict(cnx, self.table_name, vals, commit=True) new_id = DBInsertDict(cnx, self.table_name, vals, commit=True)
# get back new object id
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
cursor.execute(
"select %(id_name)s from %(table_name)s where oid=%(oid)s"
% {"id_name": self.id_name, "table_name": self.table_name, "oid": oid}
)
new_id = cursor.fetchone()[0]
return new_id return new_id
def delete(self, cnx, oid, commit=True): def delete(self, cnx, oid, commit=True):
@ -346,6 +346,8 @@ class EditableTable(object):
) )
for r in res: for r in res:
self.format_output(r, disable_formatting=disable_formatting) self.format_output(r, disable_formatting=disable_formatting)
# Add ScoDoc7 id:
r[self.id_name] = r["id"]
return res return res
def format_output(self, r, disable_formatting=False): def format_output(self, r, disable_formatting=False):
@ -365,7 +367,10 @@ class EditableTable(object):
def edit(self, cnx, args, html_quote=None): def edit(self, cnx, args, html_quote=None):
"""Change fields""" """Change fields"""
# assert self.id_name in args
oid = args[self.id_name]
vals = dictfilter(args, self.dbfields, self.filter_nulls) vals = dictfilter(args, self.dbfields, self.filter_nulls)
vals["id"] = oid
html_quote = html_quote or self.html_quote html_quote = html_quote or self.html_quote
if html_quote: if html_quote:
quote_dict(vals) # quote HTML quote_dict(vals) # quote HTML
@ -381,7 +386,7 @@ class EditableTable(object):
cnx, cnx,
self.table_name, self.table_name,
vals, vals,
where="%s=%%(%s)s" % (self.id_name, self.id_name), where="id=%(id)s",
commit=True, commit=True,
) )
@ -575,4 +580,4 @@ def copy_tuples_changing_attribute(
t[column] = new_value t[column] = new_value
for c in to_exclude: for c in to_exclude:
del t[c] del t[c]
DBInsertDict(cnx, table, t, convert_empty_to_nulls=False) _ = DBInsertDict(cnx, table, t, convert_empty_to_nulls=False)

View File

@ -127,9 +127,9 @@ class EvaluationCache(ScoDocCache):
@classmethod @classmethod
def invalidate_sem(cls, formsemestre_id): def invalidate_sem(cls, formsemestre_id):
"delete evaluations in this formsemestre from cache" "delete evaluations in this formsemestre from cache"
req = """SELECT e.evaluation_id req = """SELECT e.id
FROM notes_formsemestre s, notes_evaluation e, notes_moduleimpl m FROM notes_formsemestre s, notes_evaluation e, notes_moduleimpl m
WHERE s.formsemestre_id = %(formsemestre_id)s and s.formsemestre_id=m.formsemestre_id and e.moduleimpl_id=m.moduleimpl_id; WHERE s.id = %(formsemestre_id)s and s.id=m.id and e.moduleimpl_id=m.id;
""" """
evaluation_ids = [ evaluation_ids = [
x[0] for x in ndb.SimpleQuery(req, {"formsemestre_id": formsemestre_id}) x[0] for x in ndb.SimpleQuery(req, {"formsemestre_id": formsemestre_id})
@ -140,8 +140,7 @@ class EvaluationCache(ScoDocCache):
def invalidate_all_sems(cls): def invalidate_all_sems(cls):
"delete all evaluations from cache" "delete all evaluations from cache"
evaluation_ids = [ evaluation_ids = [
x[0] x[0] for x in ndb.SimpleQuery("SELECT id FROM notes_evaluation", "")
for x in ndb.SimpleQuery("SELECT evaluation_id FROM notes_evaluation", "")
] ]
cls.delete_many(evaluation_ids) cls.delete_many(evaluation_ids)
@ -243,10 +242,7 @@ def invalidate_formsemestre( # was inval_cache( context, formsemestre_id=None,
# clear all caches # clear all caches
log("----- invalidate_formsemestre: clearing all caches -----") log("----- invalidate_formsemestre: clearing all caches -----")
formsemestre_ids = [ formsemestre_ids = [
x[0] x[0] for x in ndb.SimpleQuery("SELECT id FROM notes_formsemestre", "")
for x in ndb.SimpleQuery(
"SELECT formsemestre_id FROM notes_formsemestre", ""
)
] ]
else: else:
formsemestre_ids = [ formsemestre_ids = [

View File

@ -824,9 +824,10 @@ Si vous souhaitez modifier cette formation (par exemple pour y ajouter un module
return "".join(H) return "".join(H)
def ue_sharing_code(context, ue_code=None, ue_id=None, hide_ue_id=None): def ue_sharing_code(context, ue_code=None, ue_id=None, hide_ue_id=False):
"""HTML list of UE sharing this code """HTML list of UE sharing this code
Either ue_code or ue_id may be specified. Either ue_code or ue_id may be specified.
Si hide_ue_id, ne montre pas l'UE d'origine dans la liste
""" """
from app.scodoc import sco_formations from app.scodoc import sco_formations

View File

@ -267,7 +267,7 @@ _identiteEditor = ndb.EditableTable(
}, },
output_formators={"date_naissance": ndb.DateISOtoDMY}, output_formators={"date_naissance": ndb.DateISOtoDMY},
convert_null_outputs_to_empty=True, convert_null_outputs_to_empty=True,
allow_set_id=True, # car on specifie le code Apogee a la creation # allow_set_id=True, # car on specifie le code Apogee a la creation #sco8
) )
identite_delete = _identiteEditor.delete identite_delete = _identiteEditor.delete

View File

@ -1375,7 +1375,7 @@ def do_formsemestre_delete(context, formsemestre_id):
e, e,
) )
ndb.SimpleQuery( ndb.SimpleQuery(
"DELETE FROM notes_evaluation WHERE evaluation_id=%(evaluation_id)s", "DELETE FROM notes_evaluation WHERE id=%(evaluation_id)s",
e, e,
) )

View File

@ -113,7 +113,7 @@ def group_delete(context, group, force=False):
# remove memberships: # remove memberships:
ndb.SimpleQuery("DELETE FROM group_membership WHERE group_id=%(group_id)s", group) ndb.SimpleQuery("DELETE FROM group_membership WHERE group_id=%(group_id)s", group)
# delete group: # delete group:
ndb.SimpleQuery("DELETE FROM group_descr WHERE group_id=%(group_id)s", group) ndb.SimpleQuery("DELETE FROM group_descr WHERE id=%(group_id)s", group)
def get_partition(context, partition_id): def get_partition(context, partition_id):
@ -556,8 +556,8 @@ def change_etud_group_in_partition(
partition = get_partition(context, group["partition_id"]) partition = get_partition(context, group["partition_id"])
# 1- Supprime membership dans cette partition # 1- Supprime membership dans cette partition
ndb.SimpleQuery( ndb.SimpleQuery(
"""DELETE FROM group_membership WHERE group_membership_id IN """DELETE FROM group_membership WHERE id IN
(SELECT gm.group_membership_id (SELECT gm.id
FROM group_membership gm, group_descr gd FROM group_membership gm, group_descr gd
WHERE gm.etudid=%(etudid)s AND gm.group_id=gd.group_id AND gd.partition_id=%(partition_id)s)""", WHERE gm.etudid=%(etudid)s AND gm.group_id=gd.group_id AND gd.partition_id=%(partition_id)s)""",
{"etudid": etudid, "partition_id": partition["partition_id"]}, {"etudid": etudid, "partition_id": partition["partition_id"]},

View File

@ -201,7 +201,7 @@ class BasePreferences(object):
("pref_id", "name", "value", "formsemestre_id"), ("pref_id", "name", "value", "formsemestre_id"),
sortkey="name", sortkey="name",
convert_null_outputs_to_empty=False, convert_null_outputs_to_empty=False,
allow_set_id=True, # allow_set_id=True, #sco8
html_quote=False, # car markup pdf reportlab (<b> etc) html_quote=False, # car markup pdf reportlab (<b> etc)
filter_nulls=False, filter_nulls=False,
) )

View File

@ -82,13 +82,9 @@ class ScoTag(object):
# Create new tag: # Create new tag:
# log("creating new tag: %s" % self.title) # log("creating new tag: %s" % self.title)
cnx = ndb.GetDBConnexion() cnx = ndb.GetDBConnexion()
oid = ndb.DBInsertDict( self.tag_id = ndb.DBInsertDict(
cnx, self.tag_table, {"title": self.title}, commit=True cnx, self.tag_table, {"title": self.title}, commit=True
) )
self.tag_id = ndb.SimpleDictFetch(
"SELECT tag_id FROM " + self.tag_table + " WHERE oid=%(oid)s",
{"oid": oid},
)[0]["tag_id"]
if object_id: if object_id:
self.tag_object(object_id) self.tag_object(object_id)
@ -123,7 +119,14 @@ class ScoTag(object):
if not r: if not r:
# log("tag %s with %s" % (object_id, self.title)) # log("tag %s with %s" % (object_id, self.title))
cnx = ndb.GetDBConnexion() cnx = ndb.GetDBConnexion()
ndb.DBInsertDict(cnx, self.assoc_table, args, commit=True) query = f"""INSERT INTO {self.assoc_table}
(tag_id, f{self.obj_colname})
VALUES"""
ndb.SimpleQuery(
query + " (%(tag_id)s, %(object_id)s)",
{"tag_id": self.tag_id, "object_id": object_id},
)
cnx.commit()
def remove_tag_from_object(self, object_id): def remove_tag_from_object(self, object_id):
"""Remove tag from module. """Remove tag from module.