async def get_and_cache(cls, id, model=False): """ Get a user's cachable data and cache it for future use. Replaces data if exists. Similar to the dependency current_user. :param id: User id as str :param model: Also return the UserMod instance :return: DOESN'T NEED cache.restoreuser() since data is from the db not redis. The id key in the hash is already formatted to a str from UUID. Can be None if user doesn't exist. """ from app.auth import userdb query = UserMod.get_or_none(pk=id) \ .prefetch_related( Prefetch('groups', queryset=Group.all().only('id', 'name')), Prefetch('options', queryset=Option.all().only('user_id', 'name', 'value')), Prefetch('permissions', queryset=Permission.filter(deleted_at=None).only('id', 'code')) ) if userdb.oauth_account_model is not None: query = query.prefetch_related("oauth_accounts") usermod = await query.only(*userdb.select_fields) if usermod: user_dict = await usermod.to_dict(prefetch=True) partialkey = s.CACHE_USERNAME.format(id) red.set(partialkey, cache.prepareuser_dict(user_dict), clear=True) if model: return userdb.usercomplete(**user_dict), usermod return userdb.usercomplete(**user_dict)
async def run(): await Tortoise.init(db_url="sqlite://:memory:", modules={"models": ["__main__"]}) await Tortoise.generate_schemas() tournament = await Tournament.create(name="tournament") await Event.create(name="First", tournament=tournament) await Event.create(name="Second", tournament=tournament) tournament_with_filtered = ( await Tournament.all() .prefetch_related(Prefetch("events", queryset=Event.filter(name="First"))) .first() ) print(tournament_with_filtered) print(await Tournament.first().prefetch_related("events")) tournament_with_filtered_to_attr = ( await Tournament.all() .prefetch_related( Prefetch("events", queryset=Event.filter(name="First"), to_attr="to_attr_events_first"), Prefetch( "events", queryset=Event.filter(name="Second"), to_attr="to_attr_events_second" ), ) .first() ) print(tournament_with_filtered_to_attr.to_attr_events_first) print(tournament_with_filtered_to_attr.to_attr_events_second)
async def test_prefetch_m2m_to_attr(self): tournament = await Tournament.create(name="tournament") team = await Team.create(name="1") team_second = await Team.create(name="2") event = await Event.create(name="First", tournament=tournament) await event.participants.add(team, team_second) event = await Event.first().prefetch_related( Prefetch("participants", Team.filter(name="1"), to_attr="to_attr_participants_1"), Prefetch("participants", Team.filter(name="2"), to_attr="to_attr_participants_2"), ) self.assertEqual(list(event.to_attr_participants_1), [team]) self.assertEqual(list(event.to_attr_participants_2), [team_second])
async def low_battery(self, percent: float) -> List[Bike]: """Gets all bikes with less than the given battery level.""" low_battery_ids = { k: v for k, v in self._bike_battery.items() if v <= percent } return await Bike.filter(id__in=low_battery_ids).prefetch_related( "state_updates", Prefetch("location_updates", queryset=LocationUpdate.all().limit(100)), Prefetch("issues", queryset=Issue.filter(status__not=IssueStatus.CLOSED)))
async def get_bikes(*, bike_ids: List[int] = None) -> List[Bike]: """Gets all the bikes from the system.""" if bike_ids is not None: query = Bike.filter(id__in=bike_ids) else: query = Bike.all() return await query.prefetch_related( Prefetch("location_updates", queryset=LocationUpdate.all().limit(100)), "state_updates", Prefetch("issues", queryset=Issue.filter(status__not=IssueStatus.CLOSED)))
async def test_prefetch_nested(self): tournament = await Tournament.create(name='tournament') event = await Event.create(name='First', tournament=tournament) await Event.create(name='Second', tournament=tournament) team = await Team.create(name='1') team_second = await Team.create(name='2') await event.participants.add(team, team_second) fetched_tournaments = await Tournament.all().prefetch_related( Prefetch('events', queryset=Event.filter(name='First')), Prefetch('events__participants', queryset=Team.filter(name='1'))).first() self.assertEqual(len(fetched_tournaments.events[0].participants), 1)
async def test_prefetch_nested(self): tournament = await Tournament.create(name="tournament") event = await Event.create(name="First", tournament=tournament) await Event.create(name="Second", tournament=tournament) team = await Team.create(name="1") team_second = await Team.create(name="2") await event.participants.add(team, team_second) fetched_tournaments = (await Tournament.all().prefetch_related( Prefetch("events", queryset=Event.filter(name="First")), Prefetch("events__participants", queryset=Team.filter(name="1")), ).first()) self.assertEqual(len(fetched_tournaments.events[0].participants), 1)
async def test_prefetch_direct_relation_to_attr(self): tournament = await Tournament.create(name="tournament") await Event.create(name="First", tournament=tournament) event = await Event.first().prefetch_related( Prefetch("tournament", queryset=Tournament.all(), to_attr="to_attr_tournament") ) self.assertEqual(event.to_attr_tournament.id, tournament.id)
async def get_broken_bikes() -> List[Tuple[Bike, List[Issue]]]: """ Gets the list of all broken bikes ie. those with active issues. :returns: A tuple of the list of identifiers, a dictionary mapping the identifier to its bike, and a dictionary mapping the identifier to its list of issues """ active_issues: List[Issue] = await Issue.filter( status__not=IssueStatus.CLOSED, bike_id__not_isnull=True).prefetch_related( 'bike', 'bike__state_updates', Prefetch("bike__issues", queryset=Issue.filter(status__not=IssueStatus.CLOSED))) broken_bikes = {} for issue in active_issues: if issue.bike.identifier not in broken_bikes: broken_bikes[issue.bike.identifier] = (issue.bike, []) bike, issues = broken_bikes[issue.bike.identifier] issues.append(issue) return list(broken_bikes.values())
async def on_get(self, req: Request, resp: Response, space: str) -> None: """ Get a user :param int user_id: The id of the user. """ space_relation = { "student": "student_schools", "headmaster": "principal_schools", "teacher": "teacher_schools", } try: user = None relation = space_relation.get(space, None) if relation is None: resp.status_code = 404 resp.text = "unknown relation type" else: query = User.get_or_none( id=self.current_user.id).prefetch_related( Prefetch(relation, queryset=self.only(req, School.all()))) user = await query SchoolModel.list_model([ SchoolModel.from_orm(school) for school in getattr(user, relation, []) ]).send_json(resp) except Exception as error: # pylint: disable=W0703 error_response(resp, 500, str(error))
async def on_get(self, req: Request, resp: Response, *, right_id: int, role_id: int): """ Returns a role that is associated with a given right. :param int right_id: The id of the right :param int role_id: The id of the role that has to be assiociated with the right. """ try: # Prefetching roles for the right specified by its ID. # Requesting only role fields specified by the filter # criterias from ther request header or all, if no # filter was specified. # TODO: Maybe reverse the query, as we are looking for a specific # role. So start with 'await Role.get(...)'. Tis iliminates the need # for an extra search operation (aka find_role) right = await Right.get(id=right_id).prefetch_related( Prefetch("roles", queryset=self.only(req, Role.filter(id=role_id))) ) role = find_role(right, role_id) if role is not None: RoleModel.from_orm(role).send_json(resp) return resp.status_code = 404 resp.text = f"No role with id '{role_id}' found for right '{right.name} [{right.id}]'." except DoesNotExist: resp.status_code = 404 resp.text = f"No right with id '{right_id}' found." except Exception as error: # pylint: disable=broad-except error_response(resp, 500, error)
async def test_prefetch_unknown_field(self): with self.assertRaises(OperationalError): tournament = await Tournament.create(name="tournament") await Event.create(name="First", tournament=tournament) await Event.create(name="Second", tournament=tournament) await Tournament.all().prefetch_related( Prefetch("events1", queryset=Event.filter(name="First"))).first()
async def test_prefetch_unknown_field(self): with self.assertRaises(OperationalError): tournament = await Tournament.create(name='tournament') await Event.create(name='First', tournament=tournament) await Event.create(name='Second', tournament=tournament) await Tournament.all().prefetch_related( Prefetch('events1', queryset=Event.filter(name='First'))).first()
async def test_prefetch_o2o_to_attr(self): tournament = await Tournament.create(name="tournament") event = await Event.create(name="First", tournament=tournament) address = await Address.create(city="Santa Monica", street="Ocean", event=event) event = await Event.get(pk=event.pk).prefetch_related( Prefetch("address", to_attr="to_address", queryset=Address.all()) ) self.assertEqual(address.pk, event.to_address.pk)
async def _get_lesson_tasks_with_solutions(lesson: Lesson, user: User) -> List[Task]: """Получение списка задач урока с их решением.""" return await (Task.filter(lesson_id=lesson.id).prefetch_related( Prefetch( "solutions", queryset=TaskSolution.filter(student_id=user.id), to_attr="solution", )))
async def find_courses(self, **kwargs) -> List[COURSE]: try: school = await School.get(id=self.id).prefetch_related( Prefetch("courses", queryset=Course.filter(**kwargs)) ) return [CourseModel.from_orm(course) for course in school.courses] except FieldError as error: raise QueryError(str(error)) from error
async def test_prefetch_object(self): tournament = await Tournament.create(name="tournament") await Event.create(name="First", tournament=tournament) await Event.create(name="Second", tournament=tournament) tournament_with_filtered = (await Tournament.all().prefetch_related( Prefetch("events", queryset=Event.filter(name="First"))).first()) tournament = await Tournament.first().prefetch_related("events") self.assertEqual(len(tournament_with_filtered.events), 1) self.assertEqual(len(tournament.events), 2)
async def test_prefetching(self): tournament = await Tournament.create(name='tournament') await Event.create(name='First', tournament=tournament) await Event.create(name='Second', tournament=tournament) tournament_with_filtered = await Tournament.all().prefetch_related( Prefetch('events', queryset=Event.filter(name='First'))).first() tournament = await Tournament.first().prefetch_related('events') self.assertEqual(len(tournament_with_filtered.events), 1) self.assertEqual(len(tournament.events), 2)
async def find_units(self, **kwargs) -> List[UNIT]: try: course = await Course.get(id=self.id).prefetch_related( Prefetch("units", queryset=Unit.filter(**kwargs)) ) return [UnitModel.from_orm(unit) for unit in course.units] except FieldError as error: raise QueryError(str(error)) from error
async def get_available_bikes_out_of(self, bike_ids: List[int]) -> List[Bike]: """Given a list of bike ids, checks if they are free or not and returns the ones that are free.""" used_bikes = { bike_id for rental_id, bike_id in self._active_rentals.values() } available_bikes = set(bike_ids) - used_bikes if not available_bikes: return [] query = Bike.filter(id__in=available_bikes) return await query.prefetch_related( Prefetch("location_updates", queryset=LocationUpdate.all().limit(100)), "state_updates", Prefetch("issues", queryset=Issue.filter(status__not=IssueStatus.CLOSED)))
async def run(): await Tortoise.init(config_file='config.json') await Tortoise.generate_schemas() tournament = await Tournament.create(name='tournament') await Event.create(name='First', tournament=tournament) await Event.create(name='Second', tournament=tournament) tournament_with_filtered = await Tournament.all().prefetch_related( Prefetch('events', queryset=Event.filter(name='First'))).first() print(tournament_with_filtered) print(await Tournament.first().prefetch_related('events'))
async def get_bike(*, identifier: Union[str, bytes] = None, public_key: bytes = None) -> Optional[Bike]: """Gets a bike from the system.""" kwargs: Dict = {} if public_key: kwargs["public_key_hex"] = public_key.hex() if identifier: kwargs["public_key_hex__startswith"] = identifier.hex() if isinstance( identifier, bytes) else identifier try: return await Bike.get(**kwargs).first().prefetch_related( Prefetch("location_updates", queryset=LocationUpdate.all().limit(100)), "state_updates", Prefetch("issues", queryset=Issue.filter(status__not=IssueStatus.CLOSED))) except DoesNotExist: return None
async def run(): client = SqliteClient('example_prefetching.sqlite3') await client.create_connection() Tortoise.init(client) await generate_schema(client) tournament = await Tournament.create(name='tournament') await Event.create(name='First', tournament=tournament) await Event.create(name='Second', tournament=tournament) tournament_with_filtered = await Tournament.all().prefetch_related( Prefetch('events', queryset=Event.filter(name='First'))).first() print(tournament_with_filtered) print(await Tournament.first().prefetch_related('events'))
async def test_prefetch_nested_with_aggregation(self): tournament = await Tournament.create(name='tournament') event = await Event.create(name='First', tournament=tournament) await Event.create(name='Second', tournament=tournament) team = await Team.create(name='1') team_second = await Team.create(name='2') await event.participants.add(team, team_second) fetched_tournaments = await Tournament.all().prefetch_related( Prefetch('events', queryset=Event.annotate( teams=Count('participants')).filter(teams=2)) ).first() self.assertEqual(len(fetched_tournaments.events), 1) self.assertEqual(fetched_tournaments.events[0].id, event.id)
async def test_prefetch_nested_with_aggregation(self): tournament = await Tournament.create(name="tournament") event = await Event.create(name="First", tournament=tournament) await Event.create(name="Second", tournament=tournament) team = await Team.create(name="1") team_second = await Team.create(name="2") await event.participants.add(team, team_second) fetched_tournaments = (await Tournament.all().prefetch_related( Prefetch("events", queryset=Event.annotate( teams=Count("participants")).filter(teams=2)) ).first()) self.assertEqual(len(fetched_tournaments.events), 1) self.assertEqual(fetched_tournaments.events[0].id, event.id)
async def get_jrnl_by_name(user_id: str, jrnl_name: str, deleted: bool = False) -> Optional[Journal]: if deleted: jrnl = await Journal.get_or_none(name_lower=jrnl_name, user_id=user_id) if jrnl is not None: await jrnl.fetch_related("entries__keywords") else: jrnl = await Journal.all()\ .prefetch_related(Prefetch("entries", queryset=Entry.filter(deleted_on=None)))\ .get_or_none(name_lower=jrnl_name, user_id=user_id, deleted_on=None) if jrnl is not None: await Entry.fetch_for_list(list(jrnl.entries), "keywords") return jrnl
async def test_relation_with_unique(self): school1 = await School.create(id=1024, name="School1") student1 = await Student.create(name="Sang-Heon Jeon1", school_id=school1.id) student_schools = await Student.filter(name="Sang-Heon Jeon1").values( "name", "school__name") self.assertEqual(student_schools[0], { "name": "Sang-Heon Jeon1", "school__name": "School1" }) student_schools = await Student.all().values(school="school__name") self.assertEqual(student_schools[0]["school"], school1.name) student_schools = await Student.all().values_list("school__name") self.assertEqual(student_schools[0][0], school1.name) await Student.create(name="Sang-Heon Jeon2", school=school1) school_with_filtered = (await School.all().prefetch_related( Prefetch("students", queryset=Student.filter(name="Sang-Heon Jeon1"))).first()) school_without_filtered = await School.first().prefetch_related( "students") self.assertEqual(len(school_with_filtered.students), 1) self.assertEqual(len(school_without_filtered.students), 2) student_direct_prefetch = await Student.first().prefetch_related( "school") self.assertEqual(student_direct_prefetch.school.id, school1.id) school2 = await School.create(id=2048, name="School2") await Student.all().update(school=school2) student = await Student.first() self.assertEqual(student.school_id, school2.id) await Student.filter(id=student1.id).update(school=school1) schools = await School.all().order_by("students__name") self.assertEqual([school.name for school in schools], ["School1", "School2"]) schools = await School.all().order_by("-students__name") self.assertEqual([school.name for school in schools], ["School2", "School1"]) fetched_principal = await Principal.create(name="Sang-Heon Jeon3", school=school1) self.assertEqual(fetched_principal.name, "Sang-Heon Jeon3") fetched_school = await School.filter( name="School1").prefetch_related("principal").first() self.assertEqual(fetched_school.name, "School1")
async def get_journals_for(user: User, skip: int = 0, limit: int = 100, deleted: bool = False): if deleted: jrnls = await Journal.filter(user_id=user.id ).offset(skip).limit(limit).all() else: jrnls = await Journal.all()\ .prefetch_related(Prefetch("entries", queryset=Entry.filter(deleted_on=None)))\ .filter(user_id=user.id, deleted_on=None).offset(skip).limit(limit).all() await Journal.fetch_for_list(jrnls, "entries") for jrnl in jrnls: await Entry.fetch_for_list(list(jrnl.entries), "keywords") if not deleted: await jrnl.filter(deleted_on=None) return jrnls
async def run(): await Tortoise.init(db_url="sqlite://:memory:", modules={"models": ["__main__"]}) await Tortoise.generate_schemas() school1 = await School.create(id=1024, name="School1") student1 = await Student.create(name="Sang-Heon Jeon1", school_id=school1.id) student_schools = await Student.filter(name="Sang-Heon Jeon1" ).values("name", "school__name") print(student_schools[0]) await Student.create(name="Sang-Heon Jeon2", school=school1) school_with_filtered = (await School.all().prefetch_related( Prefetch("students", queryset=Student.filter(name="Sang-Heon Jeon1"))).first()) school_without_filtered = await School.first().prefetch_related("students") print(len(school_with_filtered.students)) print(len(school_without_filtered.students)) school2 = await School.create(id=2048, name="School2") await Student.all().update(school=school2) student = await Student.first() print(student.school_id) await Student.filter(id=student1.id).update(school=school1) schools = await School.all().order_by("students__name") print([school.name for school in schools]) fetched_principal = await Principal.create(name="Sang-Heon Jeon3", school=school1) print(fetched_principal.name) fetched_school = await School.filter( name="School1").prefetch_related("principal").first() print(fetched_school.name)
async def resolve_place_gallery(cls, parent: PlaceModel, info: ResolveInfo) -> List[FileModel]: gallery = await parent.gallery.all().prefetch_related( Prefetch('file', FileModel.all())) return [gm.file for gm in gallery]