new shems
This commit is contained in:
@@ -7,53 +7,137 @@ from bd import make_engine
|
||||
from bd.tables.poll import Poll
|
||||
from bd.tables.question import Question
|
||||
from bd.tables.choice import Choice
|
||||
from bd.tables.scale import ScaleDimension, ChoiceScore
|
||||
|
||||
router = APIRouter(tags=["polls"], prefix="/polls")
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Вопросы теста — модификация Г.В. Резапкиной
|
||||
# Пары профессий: (вариант А, вариант В)
|
||||
# ---------------------------------------------------------------------------
|
||||
PAIRS = [
|
||||
("инженер-техник", "инженер-контролер"),
|
||||
("вязальщик", "санитарный врач"),
|
||||
("повар", "наборщик"),
|
||||
("фотограф", "зав. магазином"),
|
||||
("чертежник", "дизайнер"),
|
||||
("философ", "психиатр"),
|
||||
("ученый-химик", "бухгалтер"),
|
||||
("редактор научного журнала", "адвокат"),
|
||||
("лингвист", "переводчик художественной литературы"),
|
||||
("педиатр", "статистик"),
|
||||
("организатор воспитательной работы", "председатель профсоюза"),
|
||||
("спортивный врач", "фельетонист"),
|
||||
("нотариус", "снабженец"),
|
||||
("перфоратор", "карикатурист"),
|
||||
("политический деятель", "писатель"),
|
||||
("садовник", "метеоролог"),
|
||||
("водитель", "медсестра"),
|
||||
("инженер-электрик", "секретарь-машинистка"),
|
||||
("маляр", "художник по металлу"),
|
||||
("биолог", "главный врач"),
|
||||
("телеоператор", "режиссер"),
|
||||
("гидролог", "ревизор"),
|
||||
("зоолог", "зоотехник"),
|
||||
("математик", "архитектор"),
|
||||
("работник ИДН", "счетовод"),
|
||||
("учитель", "милиционер"),
|
||||
("воспитатель", "художник по керамике"),
|
||||
("экономист", "заведующий отделом"),
|
||||
("корректор", "критик"),
|
||||
("завхоз", "директор"),
|
||||
("радиоинженер", "специалист по ядерной физике"),
|
||||
("водопроводчик", "наборщик"),
|
||||
("агроном", "председатель сельхозкооператива"),
|
||||
("закройщик-модельер", "декоратор"),
|
||||
("археолог", "эксперт"),
|
||||
("работник музея", "консультант"),
|
||||
("ученый", "актер"),
|
||||
("логопед", "стенографист"),
|
||||
("врач", "дипломат"),
|
||||
("главный бухгалтер", "директор"),
|
||||
("поэт", "психолог"),
|
||||
("архивариус", "скульптор"),
|
||||
("инженер-технолог", "инженер-конструктор"), # 1
|
||||
("электрорадиотехник", "врач-терапевт"), # 2
|
||||
("оператор станков с числовым программным управлением", "кодировщик (обработка информации)"), # 3
|
||||
("фотограф", "коммерсант"), # 4
|
||||
("спасатель МЧС", "дизайнер"), # 5
|
||||
("политолог", "психиатр"), # 6
|
||||
("ученый химик", "бухгалтер"), # 7
|
||||
("философ", "частный предприниматель"), # 8
|
||||
("лингвист", "модельер"), # 9
|
||||
("инспектор службы занятости населения", "статист"), # 10
|
||||
("социальный педагог", "биржевой маклер"), # 11
|
||||
("тренер", "искусствовед"), # 12
|
||||
("нотариус", "менеджер"), # 13
|
||||
("перфораторщик", "художник"), # 14
|
||||
("лидер политической партии, общего движения", "писатель"), # 15
|
||||
("закройщик", "метеоролог"), # 16
|
||||
("водитель", "работник пресс-службы"), # 17
|
||||
("чертежник", "риэлтер"), # 18
|
||||
("специалист по ремонту компьютеров и оргтехники", "секретарь-референт"), # 19
|
||||
("микробиолог", "психолог"), # 20
|
||||
("видеооператор", "режиссер"), # 21
|
||||
("экономист", "провизор"), # 22
|
||||
("зоолог", "главный инженер"), # 23
|
||||
("программист", "архитектор"), # 24
|
||||
("работник инспекции по делам несовершеннолетних", "коммивояжер (сетевой маркетинг)"), # 25
|
||||
("преподаватель", "биржевой маклер"), # 26
|
||||
("воспитатель", "декоратор"), # 27
|
||||
("реставратор", "зав. отделом предприятия"), # 28
|
||||
("корректор", "литератор и кинокритик"), # 29
|
||||
("фермер", "визажист"), # 30
|
||||
("парикмахер", "социолог"), # 31
|
||||
("экспедитор", "редактор"), # 32
|
||||
("ветеринар", "директор (финансовый)"), # 33
|
||||
("автомеханик", "стилист"), # 34
|
||||
("археолог", "эксперт"), # 35
|
||||
("библиограф", "корреспондент"), # 36
|
||||
("эколог", "актер"), # 37
|
||||
("логопед", "контролер"), # 38
|
||||
("адвокат", "директор (глава АО)"), # 39
|
||||
("кассир", "продюсер"), # 40
|
||||
("поэт, писатель", "продавец"), # 41
|
||||
("криминалист (баллистик)", "композитор"), # 42
|
||||
]
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Ключ расшифровки: номер пары → (тип выбора А, тип выбора В)
|
||||
# Типы: Р=Реалистический, И=Интеллектуальный, С=Социальный,
|
||||
# К=Конвенциональный, П=Предприимчивый, А=Художественный
|
||||
# Источник: Тест Дж. Голланда, модификация Г.В. Резапкиной
|
||||
# ---------------------------------------------------------------------------
|
||||
CHOICE_KEY: dict[int, tuple[str, str]] = {
|
||||
1: ("Р", "И"), 2: ("Р", "С"), 3: ("Р", "К"), 4: ("Р", "П"), 5: ("Р", "А"),
|
||||
6: ("И", "С"), 7: ("И", "К"), 8: ("И", "П"), 9: ("И", "А"), 10: ("С", "К"),
|
||||
11: ("С", "П"), 12: ("С", "А"), 13: ("К", "П"), 14: ("К", "А"), 15: ("П", "А"),
|
||||
16: ("Р", "И"), 17: ("Р", "С"), 18: ("К", "П"), 19: ("Р", "К"), 20: ("И", "С"),
|
||||
21: ("Р", "А"), 22: ("И", "К"), 23: ("И", "П"), 24: ("И", "А"), 25: ("С", "П"),
|
||||
26: ("С", "П"), 27: ("С", "А"), 28: ("Р", "П"), 29: ("К", "А"), 30: ("П", "А"),
|
||||
31: ("Р", "И"), 32: ("Р", "К"), 33: ("Р", "П"), 34: ("Р", "А"), 35: ("И", "К"),
|
||||
36: ("И", "С"), 37: ("И", "А"), 38: ("С", "К"), 39: ("С", "П"), 40: ("К", "П"),
|
||||
41: ("А", "С"), 42: ("К", "А"),
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Описания шести типов личности по Голланду
|
||||
# ---------------------------------------------------------------------------
|
||||
DIMENSIONS = [
|
||||
{
|
||||
"code": "Р", "name": "Реалистический", "position": 1, "color": "#6B8E5E",
|
||||
"description": (
|
||||
"Предпочитает работать с вещами, а не с людьми. Несоциальный, эмоционально-стабильный тип. "
|
||||
"Ориентирован на настоящее, определённое. Занимается конкретными объектами и их использованием "
|
||||
"(вещи, инструменты, техника). Трудолюбив, пластичен. Преобладают невербальные и математические "
|
||||
"способности. Охотнее делает, чем говорит; настойчив, уверен в себе. "
|
||||
"Рекомендуемые профессии: оператор ПК, техник, шофёр, ювелир, автомеханик, фермер, инженер."
|
||||
),
|
||||
},
|
||||
{
|
||||
"code": "И", "name": "Интеллектуальный", "position": 2, "color": "#4A7FA5",
|
||||
"description": (
|
||||
"Ориентирован на труд с идеями и объектами. Любознательный, методичный, любит работать в одиночку. "
|
||||
"Аналитические способности, рационализм, независимость и оригинальность мышления. "
|
||||
"Нередко выбирает научную и исследовательскую работу. Мир идей для него важнее, чем общение с людьми. "
|
||||
"Рекомендуемые профессии: метеоролог, научный работник, физик, химик, хирург, биолог."
|
||||
),
|
||||
},
|
||||
{
|
||||
"code": "С", "name": "Социальный", "position": 3, "color": "#D4A84B",
|
||||
"description": (
|
||||
"Ориентирован на общение и взаимодействие с людьми. Ответственен, терпелив, эмпатичен. "
|
||||
"Развитые вербальные способности. Предпочитает деятельность, связанную с обучением, воспитанием, "
|
||||
"лечением, консультированием. Гуманен, чувствителен, активен. "
|
||||
"Рекомендуемые профессии: учитель, психолог, логопед, врач, продавец."
|
||||
),
|
||||
},
|
||||
{
|
||||
"code": "К", "name": "Конвенциональный", "position": 4, "color": "#8B7355",
|
||||
"description": (
|
||||
"Отдаёт предпочтение чётко структурированной деятельности. Консервативен, аккуратен, пунктуален. "
|
||||
"Хорошо работает с информацией в виде цифр, формул, текстов. Прекрасный исполнитель. "
|
||||
"Склонен к канцелярской и конторской работе. "
|
||||
"Рекомендуемые профессии: экономист, бухгалтер, нотариус, кассир, архивариус, налоговый инспектор."
|
||||
),
|
||||
},
|
||||
{
|
||||
"code": "П", "name": "Предприимчивый", "position": 5, "color": "#C0392B",
|
||||
"description": (
|
||||
"Выбирает цели и задачи, которые позволяют проявить энергию и энтузиазм. Самоуверен, настойчив. "
|
||||
"Находчив, практичен, быстро ориентируется в сложной обстановке. Социально активен, готов рисковать. "
|
||||
"Предпочитает деятельность, связанную с руководством и влиянием на людей. "
|
||||
"Рекомендуемые профессии: руководитель, директор, судья, адвокат, брокер, предприниматель, риэлтор."
|
||||
),
|
||||
},
|
||||
{
|
||||
"code": "А", "name": "Художественный", "position": 6, "color": "#8E44AD",
|
||||
"description": (
|
||||
"Сложный взгляд на жизнь, гибкость и независимость в принятии решений. Богатое воображение, "
|
||||
"склонность к творческой деятельности. Оригинален, эмоционален, не терпит жёсткой регламентации. "
|
||||
"Преобладают вербальные способности. "
|
||||
"Рекомендуемые профессии: писатель, фотограф, музыкант, художник, журналист, архитектор, дизайнер."
|
||||
),
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
@@ -66,15 +150,19 @@ def get_session():
|
||||
def create_holland_poll(author_id: Optional[str] = None):
|
||||
Session = get_session()
|
||||
with Session() as session:
|
||||
poll = Poll(title="Тест Д. Голланда — определение типа личности",
|
||||
description="Тест Д. Голланда: выберите из каждой пары предпочитаемую профессию.")
|
||||
# polls are anonymous; ignore author_id
|
||||
poll = Poll(
|
||||
title="Тест Дж. Голланда — определение типа личности",
|
||||
description=(
|
||||
"Тест Дж. Голланда (модификация Г.В. Резапкиной): выберите из каждой пары "
|
||||
"предпочитаемую профессию. Из 42 пар профессий отметьте ту, которая вам больше нравится."
|
||||
),
|
||||
)
|
||||
session.add(poll)
|
||||
for idx, (a, b) in enumerate(PAIRS, start=1):
|
||||
q = Question(text=f"Вариант {idx}", position=idx, type="single", poll=poll)
|
||||
session.add(q)
|
||||
ch1 = Choice(question=q, text=f"а) {a}", position=1)
|
||||
ch2 = Choice(question=q, text=f"б) {b}", position=2)
|
||||
ch1 = Choice(question=q, text=f"А) {a}", position=1)
|
||||
ch2 = Choice(question=q, text=f"В) {b}", position=2)
|
||||
session.add(ch1)
|
||||
session.add(ch2)
|
||||
session.commit()
|
||||
@@ -88,3 +176,88 @@ def list_holland_polls():
|
||||
with Session() as session:
|
||||
rows = session.query(Poll).filter(Poll.title.like("%Голланда%")).all()
|
||||
return [{"id": str(p.id), "title": p.title, "description": p.description} for p in rows]
|
||||
|
||||
|
||||
@router.post("/holland/{poll_id}/seed-scores", status_code=201)
|
||||
def seed_holland_scores(poll_id: str):
|
||||
"""
|
||||
Загружает расшифровку теста Голланда (модификация Резапкиной) в базу данных:
|
||||
- создаёт 6 осей диаграммы (ScaleDimension) для указанного теста
|
||||
- для каждого из 42 вопросов привязывает оба варианта ответа к своей оси (ChoiceScore)
|
||||
|
||||
При повторном вызове старые оси и расшифровки пересоздаются.
|
||||
"""
|
||||
Session = get_session()
|
||||
try:
|
||||
pid = uuid.UUID(poll_id)
|
||||
except Exception:
|
||||
raise HTTPException(status_code=400, detail="Invalid poll UUID")
|
||||
|
||||
with Session() as session:
|
||||
poll = session.get(Poll, pid)
|
||||
if not poll:
|
||||
raise HTTPException(status_code=404, detail="Poll not found")
|
||||
|
||||
# Получаем вопросы упорядоченно по позиции
|
||||
questions = (
|
||||
session.query(Question)
|
||||
.filter(Question.poll_id == pid)
|
||||
.order_by(Question.position.asc())
|
||||
.all()
|
||||
)
|
||||
if len(questions) != 42:
|
||||
raise HTTPException(
|
||||
status_code=422,
|
||||
detail=f"Ожидается 42 вопроса, найдено {len(questions)}. Убедитесь, что тест создан через POST /polls/holland.",
|
||||
)
|
||||
|
||||
# Удаляем старые оси (и ChoiceScore через cascade)
|
||||
old_dims = session.query(ScaleDimension).filter(ScaleDimension.poll_id == pid).all()
|
||||
for d in old_dims:
|
||||
session.delete(d)
|
||||
session.flush()
|
||||
|
||||
# Создаём 6 осей: код → объект
|
||||
dim_map: dict[str, ScaleDimension] = {}
|
||||
for d_data in DIMENSIONS:
|
||||
dim = ScaleDimension(
|
||||
poll_id=pid,
|
||||
name=d_data["name"],
|
||||
description=d_data["description"],
|
||||
color=d_data["color"],
|
||||
position=d_data["position"],
|
||||
)
|
||||
session.add(dim)
|
||||
session.flush()
|
||||
dim_map[d_data["code"]] = dim
|
||||
|
||||
# Для каждого вопроса привязываем варианты к осям
|
||||
scores_created = 0
|
||||
for q in questions:
|
||||
pair_num = q.position # 1..42
|
||||
if pair_num not in CHOICE_KEY:
|
||||
continue
|
||||
type_a, type_b = CHOICE_KEY[pair_num]
|
||||
|
||||
choices = (
|
||||
session.query(Choice)
|
||||
.filter(Choice.question_id == q.id)
|
||||
.order_by(Choice.position.asc())
|
||||
.all()
|
||||
)
|
||||
if len(choices) < 2:
|
||||
continue
|
||||
|
||||
choice_a, choice_b = choices[0], choices[1]
|
||||
session.add(ChoiceScore(choice_id=choice_a.id, dimension_id=dim_map[type_a].id, score=1.0))
|
||||
session.add(ChoiceScore(choice_id=choice_b.id, dimension_id=dim_map[type_b].id, score=1.0))
|
||||
scores_created += 2
|
||||
|
||||
session.commit()
|
||||
|
||||
return {
|
||||
"status": "ok",
|
||||
"dimensions": len(DIMENSIONS),
|
||||
"choice_scores": scores_created,
|
||||
"message": "Расшифровка теста Голланда успешно загружена в базу данных.",
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user