From c903a852037a5198c9f759626fd7844c3bb303ac Mon Sep 17 00:00:00 2001 From: Martin Mares <mj@ucw.cz> Date: Sat, 12 Nov 2022 15:54:01 +0100 Subject: [PATCH] =?UTF-8?q?P=C5=99edchoz=C3=AD=20kolo=20m=C5=AF=C5=BEe=20m?= =?UTF-8?q?=C3=ADt=20ni=C5=BE=C5=A1=C3=AD=20level?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Letos nastává v kategorii P na přechodu z domácího (level=1) do krajského (level=2) kola. Upravuji jak automatické zakládání soutěží, tak postup mezi koly, aby s tímto případem počítaly. Také místo CTE na hledání v hierarchii regionů používám view RegionDescendant. Možná to je pomalejší, ale zde není rychlost nijak kritická, takže je preferuji jednodušší kód. Closes #296. --- mo/web/org_contest.py | 30 +++++++++++++++++------------- mo/web/org_round.py | 21 +++++++++++++-------- 2 files changed, 30 insertions(+), 21 deletions(-) diff --git a/mo/web/org_contest.py b/mo/web/org_contest.py index 6bbc463d..552a569e 100644 --- a/mo/web/org_contest.py +++ b/mo/web/org_contest.py @@ -8,7 +8,7 @@ import json import locale import magic from markupsafe import Markup -from sqlalchemy import func, and_, select, not_ +from sqlalchemy import func, and_, not_ from sqlalchemy.orm import joinedload, aliased from sqlalchemy.orm.query import Query from sqlalchemy.dialects.postgresql import insert as pgsql_insert @@ -28,6 +28,7 @@ import mo.jobs.protocols import mo.jobs.submit from mo.rights import Right, RoundRights import mo.util +from mo.util import assert_not_none from mo.util_format import inflect_number, inflect_by_number, inflect_with_number from mo.web import app import mo.web.fields as mo_fields @@ -1533,12 +1534,12 @@ def org_contest_advance(ct_id: int): reject_by_place_id: Dict[int, int] = {} prev_pions_by_place_id: Dict[int, List[Tuple[db.Participation, Optional[decimal.Decimal], bool]]] = {} - desc_cte = db.place_descendant_cte(contest.place, max_level=prev_round.level) - prev_contests = (sess.query(db.Contest) - .filter(db.Contest.round == prev_round) - .filter(db.Contest.place_id.in_(select([desc_cte]))) - .options(joinedload(db.Contest.place)) - .all()) + prev_contests_q = sess.query(db.Contest).filter(db.Contest.round == prev_round) + if prev_round.level >= round.level: + prev_contests_q = prev_contests_q.join(db.RegionDescendant, and_(db.RegionDescendant.region == contest.place_id, db.RegionDescendant.descendant == db.Contest.place_id)) + else: + prev_contests_q = prev_contests_q.join(db.RegionDescendant, and_(db.RegionDescendant.descendant == contest.place_id, db.RegionDescendant.region == db.Contest.place_id)) + prev_contests = prev_contests_q.options(joinedload(db.Contest.place)).all() prev_contests.sort(key=lambda c: locale.strxfrm(c.place.name or "")) form = AdvanceForm() @@ -1553,6 +1554,12 @@ def org_contest_advance(ct_id: int): prev_pion_query = (sess.query(db.Participation) .filter(db.Participation.contest_id.in_([c.contest_id for c in prev_contests])) .filter_by(state=db.PartState.active)) + if prev_round.level < round.level: + prev_pion_query = (prev_pion_query + .join(db.Participant, and_(db.Participant.user_id == db.Participation.user_id, + db.Participant.year == round.year)) + .join(db.RegionDescendant, and_(db.RegionDescendant.descendant == db.Participant.school, + db.RegionDescendant.region == contest.place_id))) if want_select: prev_pions = prev_pion_query.options(joinedload(db.Participation.user)).all() else: @@ -1581,9 +1588,9 @@ def org_contest_advance(ct_id: int): really_inserted = 0 for pp in prev_pions: # This incurs no real queries as we have all the contests cached - prev_place_id = sess.query(db.Contest).get(pp.contest_id).place_id - points = points_map[pp.user_id] if pp.user_id in points_map else None - checked = points is not None and points >= form.boundary.data + prev_place_id = assert_not_none(sess.query(db.Contest).get(pp.contest_id)).place_id + points = points_map.get(pp.user_id, 0) + checked = points >= form.boundary.data prev_pions_by_place_id[prev_place_id].append((pp, points, checked)) if want_execute and want_select: @@ -1665,9 +1672,6 @@ def get_prev_round(round: db.Round) -> Optional[db.Round]: if prev_round is None: flash('Předchozí kolo nenalezeno', 'danger') return None - elif prev_round.level < round.level: - flash('Předchozí kolo se koná ve vyšší oblasti než toto kolo', 'danger') - return None return prev_round diff --git a/mo/web/org_round.py b/mo/web/org_round.py index fec02c95..9b10d069 100644 --- a/mo/web/org_round.py +++ b/mo/web/org_round.py @@ -678,14 +678,19 @@ def org_round_create_contests(round_id: int): have_places_subq = (sess.query(db.Contest.place_id) .filter_by(round=round)) - new_places = (sess.query(db.Place) - .select_from(db.Contest) - .filter(db.Contest.round == prev_round) - .join(db.RegionDescendant, db.RegionDescendant.descendant == db.Contest.place_id) - .join(db.Place, db.Place.place_id == db.RegionDescendant.region) - .filter(db.Place.level == round.level) - .filter(db.Place.place_id.notin_(have_places_subq)) - .all()) + new_places_q = sess.query(db.Place).select_from(db.Contest).filter(db.Contest.round == prev_round) + if prev_round.level >= round.level: + new_places_q = (new_places_q + .join(db.RegionDescendant, db.RegionDescendant.descendant == db.Contest.place_id) + .join(db.Place, db.Place.place_id == db.RegionDescendant.region)) + else: + new_places_q = (new_places_q + .join(db.RegionDescendant, db.RegionDescendant.region == db.Contest.place_id) + .join(db.Place, db.Place.place_id == db.RegionDescendant.descendant)) + new_places = (new_places_q + .filter(db.Place.level == round.level) + .filter(db.Place.place_id.notin_(have_places_subq)) + .all()) form = CreateContestsForm() if form.validate_on_submit(): -- GitLab