add examination schedule module and endpoint to set date of enrollment for students
This commit is contained in:
parent
adfb941fbe
commit
55a08d3406
@ -3,9 +3,11 @@ from flask import Blueprint
|
|||||||
from .students import bp as students_bp
|
from .students import bp as students_bp
|
||||||
from .project_supervisor import bp as project_supervisor_bp
|
from .project_supervisor import bp as project_supervisor_bp
|
||||||
from .groups import bp as groups_bp
|
from .groups import bp as groups_bp
|
||||||
|
from .examination_schedule import bp as examination_schedule_bp
|
||||||
|
|
||||||
bp = Blueprint("coordinator", __name__, url_prefix="/coordinator")
|
bp = Blueprint("coordinator", __name__, url_prefix="/coordinator")
|
||||||
|
|
||||||
bp.register_blueprint(students_bp)
|
bp.register_blueprint(students_bp)
|
||||||
bp.register_blueprint(project_supervisor_bp)
|
bp.register_blueprint(project_supervisor_bp)
|
||||||
bp.register_blueprint(groups_bp)
|
bp.register_blueprint(groups_bp)
|
||||||
|
bp.register_blueprint(examination_schedule_bp)
|
||||||
|
63
backend/app/coordinator/routes/examination_schedule.py
Normal file
63
backend/app/coordinator/routes/examination_schedule.py
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
from apiflask import APIBlueprint
|
||||||
|
from flask import abort
|
||||||
|
|
||||||
|
from ..schemas import ExaminationScheduleSchema, ExaminationScheduleUpdateSchema, MessageSchema, \
|
||||||
|
ExaminationSchedulesQuerySchema, ExaminationSchedulesPaginationSchema
|
||||||
|
from ...examination_schedule.models import ExaminationSchedule
|
||||||
|
from ...dependencies import db
|
||||||
|
from ...base.utils import paginate_models
|
||||||
|
|
||||||
|
bp = APIBlueprint("examination_schedule", __name__, url_prefix="/examination_schedule")
|
||||||
|
|
||||||
|
|
||||||
|
@bp.get('/')
|
||||||
|
@bp.input(ExaminationSchedulesQuerySchema, location='query')
|
||||||
|
@bp.output(ExaminationSchedulesPaginationSchema)
|
||||||
|
def list_examination_schedule(query: dict) -> dict:
|
||||||
|
page = query.get('page')
|
||||||
|
per_page = query.get('per_page')
|
||||||
|
data = paginate_models(page, ExaminationSchedule.query, per_page)
|
||||||
|
return {'examination_schedules': data['items'], 'max_pages': data['max_pages']}
|
||||||
|
|
||||||
|
|
||||||
|
@bp.post('/')
|
||||||
|
@bp.input(ExaminationScheduleSchema)
|
||||||
|
@bp.output(MessageSchema)
|
||||||
|
def create_examination_schedule(data: dict) -> dict:
|
||||||
|
examination_schedule = ExaminationSchedule(**data)
|
||||||
|
db.session.add(examination_schedule)
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
|
return {"message": "Examination schedule was created!"}
|
||||||
|
|
||||||
|
|
||||||
|
@bp.put('/<int:id>/')
|
||||||
|
@bp.input(ExaminationScheduleSchema)
|
||||||
|
@bp.output(MessageSchema)
|
||||||
|
def update_title_examination_schedule(id: int, data: dict) -> dict:
|
||||||
|
examination_schedule_query = db.session.query(ExaminationSchedule).filter(ExaminationSchedule.id == id)
|
||||||
|
examination_schedule = examination_schedule_query.first()
|
||||||
|
|
||||||
|
if examination_schedule is None:
|
||||||
|
abort(404, "Examination schedule doesn't exist!")
|
||||||
|
examination_schedule_query.update(data)
|
||||||
|
db.session.commit()
|
||||||
|
return {"message": "Examination schedule was updated!"}
|
||||||
|
|
||||||
|
|
||||||
|
@bp.put('/<int:id>/date')
|
||||||
|
@bp.input(ExaminationScheduleUpdateSchema)
|
||||||
|
@bp.output(MessageSchema)
|
||||||
|
def set_date_of_examination_schedule(id: int, data: dict) -> dict:
|
||||||
|
examination_schedule_query = db.session.query(ExaminationSchedule).filter(ExaminationSchedule.id == id)
|
||||||
|
examination_schedule = examination_schedule_query.first()
|
||||||
|
|
||||||
|
if examination_schedule is None:
|
||||||
|
abort(404, "Examination schedule doesn't exist!")
|
||||||
|
|
||||||
|
if data['start_date'] > data['end_date']:
|
||||||
|
abort(400, "Invalid data! End date must be greater than start date!")
|
||||||
|
|
||||||
|
examination_schedule_query.update(data)
|
||||||
|
db.session.commit()
|
||||||
|
return {"message": "You set date of examination schedule!"}
|
@ -1,127 +0,0 @@
|
|||||||
from ..dependencies import ma
|
|
||||||
from ..students.models import Student, Group
|
|
||||||
from ..project_supervisor.models import ProjectSupervisor
|
|
||||||
from marshmallow import fields, validate, ValidationError
|
|
||||||
|
|
||||||
|
|
||||||
def validate_index(index):
|
|
||||||
if len(str(index)) > 6:
|
|
||||||
raise ValidationError("Length of index is too long!")
|
|
||||||
elif len(str(index)) < 6:
|
|
||||||
raise ValidationError("Length of index is too short!")
|
|
||||||
|
|
||||||
|
|
||||||
class ProjectSupervisorSchema(ma.SQLAlchemyAutoSchema):
|
|
||||||
class Meta:
|
|
||||||
model = ProjectSupervisor
|
|
||||||
include_relationships = False
|
|
||||||
|
|
||||||
|
|
||||||
class GroupSchema(ma.SQLAlchemyAutoSchema):
|
|
||||||
project_supervisor = fields.Nested(ProjectSupervisorSchema)
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
model = Group
|
|
||||||
|
|
||||||
|
|
||||||
class StudentSchema(ma.SQLAlchemyAutoSchema):
|
|
||||||
group = fields.Nested(GroupSchema)
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
model = Student
|
|
||||||
|
|
||||||
|
|
||||||
class StudentsPaginationSchema(ma.Schema):
|
|
||||||
students = fields.List(fields.Nested(StudentSchema))
|
|
||||||
max_pages = fields.Integer()
|
|
||||||
|
|
||||||
|
|
||||||
class StudentListFileDownloaderSchema(ma.Schema):
|
|
||||||
mode = fields.Integer()
|
|
||||||
|
|
||||||
|
|
||||||
class StudentCreateSchema(ma.Schema):
|
|
||||||
first_name = fields.Str(validate=validate.Length(min=1, max=255), required=True)
|
|
||||||
last_name = fields.Str(validate=validate.Length(min=1, max=255), required=True)
|
|
||||||
pesel = fields.Str(validate=validate.Length(min=0, max=11), required=True)
|
|
||||||
index = fields.Integer(validate=validate_index, required=True)
|
|
||||||
mode = fields.Boolean(required=True)
|
|
||||||
|
|
||||||
|
|
||||||
class StudentEditSchema(ma.Schema):
|
|
||||||
first_name = fields.Str(validate=validate.Length(min=1, max=255))
|
|
||||||
last_name = fields.Str(validate=validate.Length(min=1, max=255))
|
|
||||||
pesel = fields.Str(validate=validate.Length(min=0, max=11))
|
|
||||||
index = fields.Integer(validate=validate_index)
|
|
||||||
mode = fields.Boolean()
|
|
||||||
|
|
||||||
|
|
||||||
class MessageSchema(ma.Schema):
|
|
||||||
message = fields.Str(required=True)
|
|
||||||
|
|
||||||
|
|
||||||
class FileSchema(ma.Schema):
|
|
||||||
file = fields.Raw(type='file', required=True)
|
|
||||||
|
|
||||||
|
|
||||||
class StudentQuerySchema(ma.Schema):
|
|
||||||
fullname = fields.Str()
|
|
||||||
order_by_first_name = fields.Str()
|
|
||||||
order_by_last_name = fields.Str()
|
|
||||||
page = fields.Integer()
|
|
||||||
per_page = fields.Integer()
|
|
||||||
mode = fields.Boolean()
|
|
||||||
|
|
||||||
|
|
||||||
class GroupQuerySchema(ma.Schema):
|
|
||||||
name = fields.Str()
|
|
||||||
page = fields.Integer()
|
|
||||||
per_page = fields.Integer()
|
|
||||||
|
|
||||||
|
|
||||||
class GroupsPaginationSchema(ma.Schema):
|
|
||||||
groups = fields.List(fields.Nested(GroupSchema))
|
|
||||||
max_pages = fields.Integer()
|
|
||||||
|
|
||||||
|
|
||||||
class GroupCreateSchema(ma.Schema):
|
|
||||||
name = fields.Str(validate=validate.Length(min=1, max=255), required=True)
|
|
||||||
project_supervisor_id = fields.Integer(required=True)
|
|
||||||
students = fields.List(fields.Integer(validate=validate_index, required=True))
|
|
||||||
|
|
||||||
|
|
||||||
class GroupEditSchema(ma.Schema):
|
|
||||||
name = fields.Str(validate=validate.Length(min=1, max=255))
|
|
||||||
project_supervisor_id = fields.Integer(validate=validate_index)
|
|
||||||
students = fields.List(fields.Nested(StudentSchema), validate=validate.Length(min=1, max=255))
|
|
||||||
|
|
||||||
|
|
||||||
class ProjectSupervisorQuerySchema(ma.Schema):
|
|
||||||
fullname = fields.Str()
|
|
||||||
order_by_first_name = fields.Str()
|
|
||||||
order_by_last_name = fields.Str()
|
|
||||||
page = fields.Integer()
|
|
||||||
per_page = fields.Integer()
|
|
||||||
mode = fields.Integer()
|
|
||||||
|
|
||||||
|
|
||||||
class ProjectSupervisorsPaginationSchema(ma.Schema):
|
|
||||||
project_supervisors = fields.List(fields.Nested(ProjectSupervisorSchema))
|
|
||||||
max_pages = fields.Integer()
|
|
||||||
|
|
||||||
|
|
||||||
class ProjectSupervisorCreateSchema(ma.Schema):
|
|
||||||
first_name = fields.Str(validate=validate.Length(min=1, max=255), required=True)
|
|
||||||
last_name = fields.Str(validate=validate.Length(min=1, max=255), required=True)
|
|
||||||
email = fields.Str(validate=validate.Length(min=1, max=255), required=True)
|
|
||||||
limit_group = fields.Integer()
|
|
||||||
mode = fields.Integer(required=True)
|
|
||||||
|
|
||||||
|
|
||||||
class ProjectSupervisorEditSchema(ma.Schema):
|
|
||||||
first_name = fields.Str(validate=validate.Length(min=1, max=255), required=True)
|
|
||||||
last_name = fields.Str(validate=validate.Length(min=1, max=255), required=True)
|
|
||||||
email = fields.Str(validate=validate.Length(min=0, max=11), required=True)
|
|
||||||
limit_group = fields.Integer(validate=validate_index)
|
|
||||||
count_groups = fields.Integer(validate=validate_index)
|
|
||||||
mode = fields.Integer(required=True)
|
|
8
backend/app/coordinator/schemas/__init__.py
Normal file
8
backend/app/coordinator/schemas/__init__.py
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
from .groups import GroupQuerySchema, GroupsPaginationSchema, GroupCreateSchema, GroupEditSchema
|
||||||
|
from .project_supervisor import ProjectSupervisorQuerySchema, ProjectSupervisorsPaginationSchema, \
|
||||||
|
ProjectSupervisorCreateSchema, ProjectSupervisorEditSchema
|
||||||
|
from .students import ProjectSupervisorSchema, GroupSchema, StudentSchema, StudentsPaginationSchema, \
|
||||||
|
StudentListFileDownloaderSchema, StudentCreateSchema, StudentEditSchema, MessageSchema, FileSchema, \
|
||||||
|
StudentQuerySchema
|
||||||
|
from .examination_schedule import ExaminationScheduleSchema, ExaminationScheduleUpdateSchema, \
|
||||||
|
ExaminationSchedulesPaginationSchema, ExaminationSchedulesQuerySchema
|
32
backend/app/coordinator/schemas/examination_schedule.py
Normal file
32
backend/app/coordinator/schemas/examination_schedule.py
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
from marshmallow import fields, validate, Schema
|
||||||
|
|
||||||
|
from ..validators import validate_datetime_greater_than_now
|
||||||
|
|
||||||
|
|
||||||
|
class ExaminationScheduleSchema(Schema):
|
||||||
|
title = fields.Str(validate=validate.Length(min=1, max=100), required=True)
|
||||||
|
|
||||||
|
|
||||||
|
class ExaminationScheduleUpdateSchema(Schema):
|
||||||
|
start_date = fields.DateTime(validate=validate_datetime_greater_than_now, required=True)
|
||||||
|
end_date = fields.DateTime(validate=validate_datetime_greater_than_now, required=True)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
datetimeformat = '%Y-%m-%d %H:%M:%S'
|
||||||
|
|
||||||
|
|
||||||
|
class ExaminationScheduleListItemSchema(Schema):
|
||||||
|
id = fields.Integer(required=True)
|
||||||
|
title = fields.Str(validate=validate.Length(min=1, max=100), required=True)
|
||||||
|
start_date = fields.DateTime(validate=validate_datetime_greater_than_now, required=True)
|
||||||
|
end_date = fields.DateTime(validate=validate_datetime_greater_than_now, required=True)
|
||||||
|
|
||||||
|
|
||||||
|
class ExaminationSchedulesPaginationSchema(Schema):
|
||||||
|
examination_schedules = fields.List(fields.Nested(ExaminationScheduleListItemSchema))
|
||||||
|
max_pages = fields.Integer()
|
||||||
|
|
||||||
|
|
||||||
|
class ExaminationSchedulesQuerySchema(Schema):
|
||||||
|
page = fields.Integer()
|
||||||
|
per_page = fields.Integer()
|
28
backend/app/coordinator/schemas/groups.py
Normal file
28
backend/app/coordinator/schemas/groups.py
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
from marshmallow import fields, validate
|
||||||
|
|
||||||
|
from ...dependencies import ma
|
||||||
|
from ..validators import validate_index
|
||||||
|
from .students import GroupSchema, StudentSchema
|
||||||
|
|
||||||
|
|
||||||
|
class GroupQuerySchema(ma.Schema):
|
||||||
|
name = fields.Str()
|
||||||
|
page = fields.Integer()
|
||||||
|
per_page = fields.Integer()
|
||||||
|
|
||||||
|
|
||||||
|
class GroupsPaginationSchema(ma.Schema):
|
||||||
|
groups = fields.List(fields.Nested(GroupSchema))
|
||||||
|
max_pages = fields.Integer()
|
||||||
|
|
||||||
|
|
||||||
|
class GroupCreateSchema(ma.Schema):
|
||||||
|
name = fields.Str(validate=validate.Length(min=1, max=255), required=True)
|
||||||
|
project_supervisor_id = fields.Integer(required=True)
|
||||||
|
students = fields.List(fields.Integer(validate=validate_index, required=True))
|
||||||
|
|
||||||
|
|
||||||
|
class GroupEditSchema(ma.Schema):
|
||||||
|
name = fields.Str(validate=validate.Length(min=1, max=255))
|
||||||
|
project_supervisor_id = fields.Integer(validate=validate_index)
|
||||||
|
students = fields.List(fields.Nested(StudentSchema), validate=validate.Length(min=1, max=255))
|
36
backend/app/coordinator/schemas/project_supervisor.py
Normal file
36
backend/app/coordinator/schemas/project_supervisor.py
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
from marshmallow import fields, validate
|
||||||
|
|
||||||
|
from ...dependencies import ma
|
||||||
|
from ..validators import validate_index
|
||||||
|
from .students import ProjectSupervisorSchema
|
||||||
|
|
||||||
|
|
||||||
|
class ProjectSupervisorQuerySchema(ma.Schema):
|
||||||
|
fullname = fields.Str()
|
||||||
|
order_by_first_name = fields.Str()
|
||||||
|
order_by_last_name = fields.Str()
|
||||||
|
page = fields.Integer()
|
||||||
|
per_page = fields.Integer()
|
||||||
|
mode = fields.Integer()
|
||||||
|
|
||||||
|
|
||||||
|
class ProjectSupervisorsPaginationSchema(ma.Schema):
|
||||||
|
project_supervisors = fields.List(fields.Nested(ProjectSupervisorSchema))
|
||||||
|
max_pages = fields.Integer()
|
||||||
|
|
||||||
|
|
||||||
|
class ProjectSupervisorCreateSchema(ma.Schema):
|
||||||
|
first_name = fields.Str(validate=validate.Length(min=1, max=255), required=True)
|
||||||
|
last_name = fields.Str(validate=validate.Length(min=1, max=255), required=True)
|
||||||
|
email = fields.Str(validate=validate.Length(min=1, max=255), required=True)
|
||||||
|
limit_group = fields.Integer()
|
||||||
|
mode = fields.Integer(required=True)
|
||||||
|
|
||||||
|
|
||||||
|
class ProjectSupervisorEditSchema(ma.Schema):
|
||||||
|
first_name = fields.Str(validate=validate.Length(min=1, max=255), required=True)
|
||||||
|
last_name = fields.Str(validate=validate.Length(min=1, max=255), required=True)
|
||||||
|
email = fields.Str(validate=validate.Length(min=0, max=11), required=True)
|
||||||
|
limit_group = fields.Integer(validate=validate_index)
|
||||||
|
count_groups = fields.Integer(validate=validate_index)
|
||||||
|
mode = fields.Integer(required=True)
|
68
backend/app/coordinator/schemas/students.py
Normal file
68
backend/app/coordinator/schemas/students.py
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
from marshmallow import fields, validate
|
||||||
|
|
||||||
|
from ...dependencies import ma
|
||||||
|
from ...students.models import Student, Group
|
||||||
|
from ...project_supervisor.models import ProjectSupervisor
|
||||||
|
from ..validators import validate_index
|
||||||
|
|
||||||
|
|
||||||
|
class ProjectSupervisorSchema(ma.SQLAlchemyAutoSchema):
|
||||||
|
class Meta:
|
||||||
|
model = ProjectSupervisor
|
||||||
|
include_relationships = False
|
||||||
|
|
||||||
|
|
||||||
|
class GroupSchema(ma.SQLAlchemyAutoSchema):
|
||||||
|
project_supervisor = fields.Nested(ProjectSupervisorSchema)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = Group
|
||||||
|
|
||||||
|
|
||||||
|
class StudentSchema(ma.SQLAlchemyAutoSchema):
|
||||||
|
group = fields.Nested(GroupSchema)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = Student
|
||||||
|
|
||||||
|
|
||||||
|
class StudentsPaginationSchema(ma.Schema):
|
||||||
|
students = fields.List(fields.Nested(StudentSchema))
|
||||||
|
max_pages = fields.Integer()
|
||||||
|
|
||||||
|
|
||||||
|
class StudentListFileDownloaderSchema(ma.Schema):
|
||||||
|
mode = fields.Integer()
|
||||||
|
|
||||||
|
|
||||||
|
class StudentCreateSchema(ma.Schema):
|
||||||
|
first_name = fields.Str(validate=validate.Length(min=1, max=255), required=True)
|
||||||
|
last_name = fields.Str(validate=validate.Length(min=1, max=255), required=True)
|
||||||
|
pesel = fields.Str(validate=validate.Length(min=0, max=11), required=True)
|
||||||
|
index = fields.Integer(validate=validate_index, required=True)
|
||||||
|
mode = fields.Boolean(required=True)
|
||||||
|
|
||||||
|
|
||||||
|
class StudentEditSchema(ma.Schema):
|
||||||
|
first_name = fields.Str(validate=validate.Length(min=1, max=255))
|
||||||
|
last_name = fields.Str(validate=validate.Length(min=1, max=255))
|
||||||
|
pesel = fields.Str(validate=validate.Length(min=0, max=11))
|
||||||
|
index = fields.Integer(validate=validate_index)
|
||||||
|
mode = fields.Boolean()
|
||||||
|
|
||||||
|
|
||||||
|
class MessageSchema(ma.Schema):
|
||||||
|
message = fields.Str(required=True)
|
||||||
|
|
||||||
|
|
||||||
|
class FileSchema(ma.Schema):
|
||||||
|
file = fields.Raw(type='file', required=True)
|
||||||
|
|
||||||
|
|
||||||
|
class StudentQuerySchema(ma.Schema):
|
||||||
|
fullname = fields.Str()
|
||||||
|
order_by_first_name = fields.Str()
|
||||||
|
order_by_last_name = fields.Str()
|
||||||
|
page = fields.Integer()
|
||||||
|
per_page = fields.Integer()
|
||||||
|
mode = fields.Boolean()
|
15
backend/app/coordinator/validators.py
Normal file
15
backend/app/coordinator/validators.py
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
from marshmallow import ValidationError
|
||||||
|
|
||||||
|
|
||||||
|
def validate_index(index: int) -> None:
|
||||||
|
if len(str(index)) > 6:
|
||||||
|
raise ValidationError("Length of index is too long!")
|
||||||
|
elif len(str(index)) < 6:
|
||||||
|
raise ValidationError("Length of index is too short!")
|
||||||
|
|
||||||
|
|
||||||
|
def validate_datetime_greater_than_now(date: datetime) -> None:
|
||||||
|
if date < datetime.now():
|
||||||
|
raise ValidationError("Date must be greater than NOW!")
|
@ -6,8 +6,8 @@ class ExaminationSchedule(Base):
|
|||||||
__tablename__ = 'examination_schedules'
|
__tablename__ = 'examination_schedules'
|
||||||
|
|
||||||
title = db.Column(db.String(100), unique=True, nullable=False)
|
title = db.Column(db.String(100), unique=True, nullable=False)
|
||||||
start_date = db.Column(db.DateTime, nullable=False)
|
start_date = db.Column(db.DateTime)
|
||||||
end_date = db.Column(db.DateTime, nullable=False)
|
end_date = db.Column(db.DateTime)
|
||||||
|
|
||||||
|
|
||||||
class Enrollment(Base):
|
class Enrollment(Base):
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
"""empty message
|
"""empty message
|
||||||
|
|
||||||
Revision ID: c7adfbd3c67f
|
Revision ID: 9874e26f2b87
|
||||||
Revises: ceaefb33117e
|
Revises: ceaefb33117e
|
||||||
Create Date: 2022-10-26 08:11:00.965906
|
Create Date: 2022-10-26 09:46:09.397814
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from alembic import op
|
from alembic import op
|
||||||
@ -10,7 +10,7 @@ import sqlalchemy as sa
|
|||||||
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
# revision identifiers, used by Alembic.
|
||||||
revision = 'c7adfbd3c67f'
|
revision = '9874e26f2b87'
|
||||||
down_revision = 'ceaefb33117e'
|
down_revision = 'ceaefb33117e'
|
||||||
branch_labels = None
|
branch_labels = None
|
||||||
depends_on = None
|
depends_on = None
|
||||||
@ -21,8 +21,8 @@ def upgrade():
|
|||||||
op.create_table('examination_schedules',
|
op.create_table('examination_schedules',
|
||||||
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
|
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
|
||||||
sa.Column('title', sa.String(length=100), nullable=False),
|
sa.Column('title', sa.String(length=100), nullable=False),
|
||||||
sa.Column('start_date', sa.DateTime(), nullable=False),
|
sa.Column('start_date', sa.DateTime(), nullable=True),
|
||||||
sa.Column('end_date', sa.DateTime(), nullable=False),
|
sa.Column('end_date', sa.DateTime(), nullable=True),
|
||||||
sa.PrimaryKeyConstraint('id'),
|
sa.PrimaryKeyConstraint('id'),
|
||||||
sa.UniqueConstraint('title')
|
sa.UniqueConstraint('title')
|
||||||
)
|
)
|
Loading…
Reference in New Issue
Block a user