diff --git a/mo/web/org_contest.py b/mo/web/org_contest.py
index 446992a185f0e08802178522c6e545071f10eaeb..7b8379bae55cc03b0a595e1c38478b8fe2337fbf 100644
--- a/mo/web/org_contest.py
+++ b/mo/web/org_contest.py
@@ -7,6 +7,7 @@ from sqlalchemy import func, and_, select
 from sqlalchemy.orm import joinedload, aliased
 from sqlalchemy.orm.query import Query
 from sqlalchemy.dialects.postgresql import insert as pgsql_insert
+import sqlalchemy.sql.schema
 from typing import Any, List, Tuple, Optional, Dict
 import urllib.parse
 import werkzeug.exceptions
@@ -483,8 +484,11 @@ def org_generic_import(round_id: Optional[int] = None, ct_id: Optional[int] = No
 @app.route('/org/contest/c/<int:ct_id>/site/<int:site_id>/participants/emails', endpoint="org_generic_list_emails")
 @app.route('/org/contest/r/<int:round_id>/participants', methods=('GET', 'POST'))
 @app.route('/org/contest/r/<int:round_id>/participants/emails', endpoint="org_generic_list_emails")
-def org_generic_list(round_id: Optional[int] = None, ct_id: Optional[int] = None, site_id: Optional[int] = None):
-    ctx = get_context(round_id=round_id, ct_id=ct_id, site_id=site_id, right_needed=Right.view_contestants)
+@app.route('/org/contest/r/<int:round_id>/h/<int:hier_id>/participants', methods=('GET', 'POST'))
+@app.route('/org/contest/r/<int:round_id>/h/<int:hier_id>/participants/emails', endpoint="org_generic_list_emails")
+def org_generic_list(round_id: Optional[int] = None, hier_id: Optional[int] = None,
+                     ct_id: Optional[int] = None, site_id: Optional[int] = None):
+    ctx = get_context(round_id=round_id, hier_id=hier_id, ct_id=ct_id, site_id=site_id, right_needed=Right.view_contestants)
     round, contest = ctx.master_round, ctx.master_contest
     rr = ctx.rights
     can_edit = rr.have_right(Right.manage_contest) and request.endpoint != 'org_generic_list_emails'
@@ -495,7 +499,7 @@ def org_generic_list(round_id: Optional[int] = None, ct_id: Optional[int] = None
         filter.validate()
 
     query = get_contestants_query(
-        round=round, contest=contest, site=ctx.site,
+        ctx=ctx,
         school=filter.school.place,
         contest_place=filter.contest_place.place,
         participation_place=filter.participation_place.place,
@@ -550,8 +554,7 @@ contest_list_columns = (
 
 
 def get_contestants_query(
-        round: db.Round, contest: Optional[db.Contest] = None,
-        site: Optional[db.Place] = None,
+        ctx: Context,
         contest_place: Optional[db.Place] = None,
         participation_place: Optional[db.Place] = None,
         participation_state: Optional[db.PartState] = None,
@@ -561,15 +564,18 @@ def get_contestants_query(
              .select_from(db.Participation)
              .join(db.Participant, db.Participant.user_id == db.Participation.user_id)
              .join(db.User, db.User.user_id == db.Participation.user_id)
-             .filter(db.Participant.year == round.year))
-    if contest:
-        query = query.join(db.Contest, db.Contest.contest_id == contest.contest_id)
+             .join(db.Contest)
+             .filter(db.Participant.year == ctx.round.year)
+             .filter(db.Participation.contest_id == db.Contest.contest_id))
+    if ctx.contest:
+        query = query.filter(db.Contest.contest_id == ctx.contest.contest_id)
+        if ctx.site:
+            query = query.filter(db.Participation.place_id == ctx.site.place_id)
     else:
-        query = query.filter(db.Contest.round == round)
+        query = query.filter(db.Contest.round == ctx.round)
+        if ctx.hier_place:
+            query = db.filter_place_nth_parent(query, db.Contest.place_id, ctx.round.level - ctx.hier_place.level, ctx.hier_place.place_id)
         query = query.options(joinedload(db.Contest.place))
-    query = query.filter(db.Participation.contest_id == db.Contest.contest_id)
-    if site:
-        query = query.filter(db.Participation.place_id == site.place_id)
     if contest_place:
         query = query.filter(db.Contest.place_id == contest_place.place_id)
     if participation_place: