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 random import randint
from flask import Blueprint, request, make_response, jsonify, Response
from flask import Blueprint, request, Response
from marshmallow import ValidationError
from flask_sqlalchemy import get_debug_queries
from ...students.models import Student
from ..schemas import StudentSchema, StudentEditSchema, StudentCreateSchema
from ...dependencies import db
from ..utils import parse_csv
from ..exceptions import InvalidNameOrTypeHeaderException
from ...base.utils import paginate_models
bp = Blueprint("students", __name__, url_prefix="/students")
@ -16,8 +18,20 @@ bp = Blueprint("students", __name__, url_prefix="/students")
@bp.route("/", methods=["GET"])
def list_students() -> Tuple[dict, int]:
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"])

View File

@ -1,5 +1,9 @@
from sqlalchemy.sql import text
from flask_sqlalchemy import BaseQuery
from ..dependencies import db
from ..base.models import Person, Base
from ..base.utils import order_by_column_name
class ProjectSupervisor(Base, Person):
@ -26,3 +30,21 @@ class Student(Person):
group_id = db.Column(db.Integer, db.ForeignKey('groups.id'))
group = db.relationship('Group', backref='students', lazy=True)
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