add pagination, query searching by fullname and ordering by firstname and lastname for list students route

This commit is contained in:
dominik24c 2022-05-18 17:36:16 +02:00
parent 5607f3cd08
commit 40e65c518c
3 changed files with 77 additions and 3 deletions

38
backend/app/base/utils.py Normal file
View File

@ -0,0 +1,38 @@
from typing import TypedDict, Tuple
from flask_sqlalchemy import BaseQuery
from sqlalchemy import desc
class PaginationResponse(TypedDict):
items: list
max_pages: int
def order_by_column_name(query: BaseQuery, model_field: str, order_by_col_name: str) -> BaseQuery:
if order_by_col_name is not None:
if order_by_col_name == 'asc':
query = query.order_by(model_field)
elif order_by_col_name == 'desc':
query = query.order_by(desc(model_field))
return query
def paginate_models(page: str, query: BaseQuery) -> PaginationResponse or Tuple[dict, int]:
per_page = 10
default_page = 1
if page is not None:
try:
page = int(page)
except ValueError:
return {"error": f"Invalid page! Page must be integer!"}, 400
query = query.paginate(page=page, per_page=per_page, error_out=False)
else:
query = query.paginate(page=default_page, per_page=per_page, error_out=False)
return {
'items': query.items,
'max_pages': query.pages
}

View File

@ -1,14 +1,16 @@
from typing import Tuple from typing import Tuple
from random import randint from random import randint
from flask import Blueprint, request, make_response, jsonify, Response from flask import Blueprint, request, Response
from marshmallow import ValidationError from marshmallow import ValidationError
from flask_sqlalchemy import get_debug_queries
from ...students.models import Student from ...students.models import Student
from ..schemas import StudentSchema, StudentEditSchema, StudentCreateSchema from ..schemas import StudentSchema, StudentEditSchema, StudentCreateSchema
from ...dependencies import db from ...dependencies import db
from ..utils import parse_csv from ..utils import parse_csv
from ..exceptions import InvalidNameOrTypeHeaderException from ..exceptions import InvalidNameOrTypeHeaderException
from ...base.utils import paginate_models
bp = Blueprint("students", __name__, url_prefix="/students") bp = Blueprint("students", __name__, url_prefix="/students")
@ -16,8 +18,20 @@ bp = Blueprint("students", __name__, url_prefix="/students")
@bp.route("/", methods=["GET"]) @bp.route("/", methods=["GET"])
def list_students() -> Tuple[dict, int]: def list_students() -> Tuple[dict, int]:
students_schema = StudentSchema(many=True) students_schema = StudentSchema(many=True)
students = Student.query.all()
return {"students": students_schema.dump(students)}, 200 fullname = request.args.get('fullname')
order_by_first_name = request.args.get('order_by_first_name')
order_by_last_name = request.args.get('order_by_last_name')
page = request.args.get('page')
student_query = Student.search_by_fullname_and_order_by_first_name_or_last_name(fullname, order_by_first_name,
order_by_last_name)
response = paginate_models(page, student_query)
if isinstance(response, tuple):
return response
print(get_debug_queries()[0])
return {"students": students_schema.dump(response['items']), "max_pages": response['max_pages']}, 200
@bp.route("/<int:index>/", methods=["GET"]) @bp.route("/<int:index>/", methods=["GET"])

View File

@ -1,5 +1,9 @@
from sqlalchemy.sql import text
from flask_sqlalchemy import BaseQuery
from ..dependencies import db from ..dependencies import db
from ..base.models import Person, Base from ..base.models import Person, Base
from ..base.utils import order_by_column_name
class ProjectSupervisor(Base, Person): class ProjectSupervisor(Base, Person):
@ -26,3 +30,21 @@ class Student(Person):
group_id = db.Column(db.Integer, db.ForeignKey('groups.id')) group_id = db.Column(db.Integer, db.ForeignKey('groups.id'))
group = db.relationship('Group', backref='students', lazy=True) group = db.relationship('Group', backref='students', lazy=True)
mode = db.Column(db.Boolean, default=True, nullable=False) # True - stationary, False - non-stationary mode = db.Column(db.Boolean, default=True, nullable=False) # True - stationary, False - non-stationary
@classmethod
def search_by_fullname_and_order_by_first_name_or_last_name(cls, fullname: str = None,
order_by_first_name: str = None,
order_by_last_name: str = None) -> BaseQuery:
student_query = cls.query
if fullname is not None:
"""This works only for sqlite3 database - concat function doesn't exist so i used builtin concat
operator specific only for sqlite db - || """
student_query = student_query.filter(
text("students_first_name || ' ' || students_last_name LIKE :fullname ")
).params(fullname=f'{fullname}%')
student_query = order_by_column_name(student_query, Student.first_name, order_by_first_name)
student_query = order_by_column_name(student_query, Student.last_name, order_by_last_name)
return student_query