update endpoints for download and upload students list in csv file

This commit is contained in:
dominik24c 2022-11-17 14:56:19 +01:00
parent 247dfe3f31
commit 0722eb9648
5 changed files with 54 additions and 28 deletions

View File

@ -80,7 +80,7 @@ def create_group(year_group_id: int, data: dict) -> dict:
return {"message": "Group was created!"}
@bp.get("/<int:id>/")
@bp.get("/<int:id>/detail/")
@bp.output(GroupSchema)
def detail_group(id: int) -> Group:
group = Group.query.filter_by(id=id).first()

View File

@ -3,12 +3,12 @@ from itertools import islice
from flask import Response, abort
from apiflask import APIBlueprint
from sqlalchemy.exc import IntegrityError
from sqlalchemy import or_
from flask_sqlalchemy import get_debug_queries
from ...students.models import Student, Group, YearGroup, YearGroupStudents
from ...project_supervisor.models import ProjectSupervisor
from ..schemas import StudentSchema, StudentEditSchema, StudentsPaginationSchema, \
from ..schemas import StudentSchema, StudentEditSchema, StudentsPaginationSchema, YearGroupInfoQuery, \
StudentCreateSchema, MessageSchema, FileSchema, StudentQuerySchema, StudentListFileDownloaderSchema
from ...dependencies import db
from ..utils import parse_csv, generate_csv
@ -109,27 +109,49 @@ def create_student(data: dict) -> dict:
@bp.post("/upload/")
@bp.input(YearGroupInfoQuery, location='query')
@bp.input(FileSchema, location='form_and_files')
@bp.output(MessageSchema)
def upload_students(file: dict) -> dict:
def upload_students(query: dict, file: dict) -> dict:
"""Add only Students to chosen year group if students exist in db and assigned to correct year group,
they will be omitted"""
year_group_id = query.get('id')
yg = YearGroup.query.filter(YearGroup.id == year_group_id).first()
if yg is None:
abort(404, "Not found year group!")
uploaded_file = file.get('file')
if uploaded_file and is_allowed_extensions(uploaded_file.filename):
try:
students = parse_csv(uploaded_file, mode=True)
students = parse_csv(uploaded_file)
while True:
sliced_students = islice(students, 5)
list_of_students = list(sliced_students)
if len(list_of_students) == 0:
break
db.session.add_all(list_of_students)
students_in_db = Student.query.filter(or_(Student.index == s.index for s in list_of_students)).all()
students_in_db_and_assigned_to_year_group = Student.query.join(YearGroupStudents, isouter=True). \
filter(YearGroupStudents.year_group_id == year_group_id). \
filter(or_(Student.index == s.index for s in list_of_students)).all()
student_index_in_db = [s.index for s in students_in_db]
student_index_in_year_group = [s.index for s in students_in_db_and_assigned_to_year_group]
students_in_db_and_not_assigned_to_year_group = list(
filter(lambda s: s.index not in student_index_in_year_group, students_in_db))
students_not_exists_in_db = list(filter(lambda s: s.index not in student_index_in_db, list_of_students))
db.session.add_all(students_not_exists_in_db)
db.session.commit()
ygs = [YearGroupStudents(year_group_id=year_group_id, student_index=student.index) for student in
students_in_db_and_not_assigned_to_year_group + students_not_exists_in_db]
db.session.add_all(ygs)
db.session.commit()
except InvalidNameOrTypeHeaderException:
abort(400, "Invalid format of csv file!")
except IntegrityError as e:
# in the future create sql query checks index and add only these students, which didn't exist in db
abort(400, "These students have already exist!")
else:
abort(400, "Invalid extension of file")
@ -139,14 +161,15 @@ def upload_students(file: dict) -> dict:
@bp.post("/download/")
@bp.input(StudentListFileDownloaderSchema, location='query')
def download_students(query: dict) -> Response:
mode = query.get('mode')
mode = mode if mode is not None else True
students = db.session.query(Student).join(Group). \
join(ProjectSupervisor).filter(Student.mode == mode).all()
year_group_id = query.get('year_group_id')
students_and_groups = db.session.query(Student, Group).join(Group, Student.groups). \
filter(Group.year_group_id == year_group_id). \
join(ProjectSupervisor).all()
if len(students) == 0:
if len(students_and_groups) == 0:
abort(404, "Not found students, which are assigned to group!")
csv_file = generate_csv(students)
csv_file = generate_csv(students_and_groups)
response = Response(csv_file, mimetype='text/csv')
response.headers.set("Content-Disposition", "attachment", filename="students_list.csv")
return response

View File

@ -6,5 +6,5 @@ from .project_supervisor import ProjectSupervisorQuerySchema, ProjectSupervisors
ProjectSupervisorCreateSchema, ProjectSupervisorEditSchema, ProjectSupervisorYearGroupSchema
from .students import ProjectSupervisorSchema, GroupSchema, StudentSchema, StudentsPaginationSchema, \
StudentListFileDownloaderSchema, StudentCreateSchema, StudentEditSchema, MessageSchema, FileSchema, \
StudentQuerySchema
StudentQuerySchema, YearGroupInfoQuery
from .year_group import YearGroupSchema, YearGroupPaginationSchema, YearGroupQuerySchema

View File

@ -1,4 +1,4 @@
from marshmallow import fields, validate
from marshmallow import fields, validate, Schema
from ...dependencies import ma
from ...students.models import Student, Group
@ -32,7 +32,7 @@ class StudentsPaginationSchema(ma.Schema):
class StudentListFileDownloaderSchema(ma.Schema):
mode = fields.Integer()
year_group_id = fields.Integer(required=True)
class StudentCreateSchema(ma.Schema):
@ -64,3 +64,7 @@ class StudentQuerySchema(ma.Schema):
order_by_last_name = fields.Str()
page = fields.Integer()
per_page = fields.Integer()
class YearGroupInfoQuery(Schema):
id = fields.Integer(required=True)

View File

@ -2,7 +2,7 @@ import datetime
from collections import defaultdict
from io import BytesIO
from itertools import chain
from typing import Generator, Any, List
from typing import Generator, Any, List, Tuple
import pandas as pd
from reportlab.lib import colors
@ -10,10 +10,10 @@ from reportlab.lib.enums import TA_CENTER
from reportlab.lib.styles import getSampleStyleSheet
from reportlab.lib.units import mm, inch
from reportlab.platypus import SimpleDocTemplate, Paragraph, PageBreak, Table
from werkzeug.datastructures import FileStorage
from .exceptions import InvalidNameOrTypeHeaderException
from ..students.models import Student
# from ..examination_schedule.models import Enrollment
from ..students.models import Student, Group
def check_columns(df: pd.DataFrame) -> bool:
@ -34,7 +34,7 @@ def check_columns(df: pd.DataFrame) -> bool:
return flag
def parse_csv(file, mode) -> Generator[Student, Any, None]:
def parse_csv(file: FileStorage) -> Generator[Student, Any, None]:
df = pd.read_csv(file)
if not check_columns(df):
@ -45,18 +45,17 @@ def parse_csv(file, mode) -> Generator[Student, Any, None]:
index=dict(item.items())['INDEKS'],
pesel=str(int(dict(item.items())['PESEL'])) if not pd.isna(
dict(item.items())['PESEL']) else None,
email=dict(item.items())['EMAIL'],
mode=mode)
email=dict(item.items())['EMAIL'])
for _, item in df.iterrows())
return students
def generate_csv(students: List[Student]) -> str:
def generate_csv(students_and_groups: List[Tuple[Student, Group]]) -> str:
headers = ['PESEL', 'INDEKS', 'IMIE', 'NAZWISKO', 'EMAIL', 'CDYD_KOD', 'PRZ_KOD', 'TZAJ_KOD', 'GR_NR', 'PRG_KOD']
data = [(student.pesel, student.index, student.first_name, student.last_name, student.email,
student.group.cdyd_kod, student.group.prz_kod, student.group.tzaj_kod, student.group.project_supervisor_id,
None) for student in students]
group.cdyd_kod, group.prz_kod, group.tzaj_kod, group.project_supervisor_id,
None) for student, group in students_and_groups]
dataframe = defaultdict(list)
for row in data:
for idx, item in enumerate(row):