✅ Решения заданий
⚡ Ответы кратко
- request.get_json() → None при отсутствии JSON.
- create_question при успехе → 201 Created.
- Question.query.get(id) → db.session.get(Question, id).
- Забытый commit → объект не сохраняется в БД, изменения теряются.
Задание 1. Объект request — ответы
-
Query-параметр
category:category = request.args.get('category') # 'books' page = request.args.get('page', 1, type=int) # 2, с дефолтом -
JSON тело:
data = request.get_json() name = data.get('name') # 'Flask' -
Поле HTML-формы:
username = request.form.get('username') -
Проверить метод DELETE:
if request.method == 'DELETE': pass # Или декоратор: methods=['DELETE'] -
Заголовок Authorization:
auth = request.headers.get('Authorization')
Задание 2. HTTP статус-коды — ответы
- Создан вопрос → 201 Created
- Вопрос с ID=999 не найден → 404 Not Found
- Отсутствует поле
text→ 400 Bad Request - Список вопросов → 200 OK
- Удалён, без тела ответа → 204 No Content
- Нет токена → 401 Unauthorized
Задание 3. SQLAlchemy 2.x — решение
from sqlalchemy import select
# Фрагмент A
questions = db.session.execute(select(Question)).scalars().all()
# Фрагмент B
question = db.session.get(Question, id)
# Фрагмент C
stat = db.session.execute(
select(Statistic).filter_by(question_id=q_id)
).scalar_one_or_none()
# Фрагмент D
active = db.session.execute(
select(Item).where(Item.active == True).order_by(Item.name)
).scalars().all()
Задание 4. Найти ошибку — решение
В коде три ошибки:
- Строка A: нет проверки, что
questionне None. Если ID не найден — будетAttributeError. - Строка A: нет проверки, что
dataне None и содержит ключ'text'. Если JSON не передан —TypeError. - Строка B: нет
db.session.commit()— изменения не сохранятся.
@questions_bp.route('/<int:id>', methods=['PUT'])
def update_question(id):
question = db.session.get(Question, id) # исправлено
if question is None: # добавлено
return jsonify({'message': 'Не найден'}), 404
data = request.get_json()
if not data or 'text' not in data: # добавлено
return jsonify({'message': 'Нет text'}), 400
question.text = data['text']
db.session.commit() # добавлено
return jsonify({'message': 'ok'}), 200
Задание 5. PATCH эндпоинт — решение
@questions_bp.route('/<int:id>', methods=['PATCH'])
def patch_question(id):
"""Частичное обновление вопроса."""
question = db.session.get(Question, id)
if question is None:
return jsonify({'message': 'Вопрос не найден'}), 404
data = request.get_json()
if not data:
return jsonify({'message': 'Тело запроса пустое'}), 400
# Обновляем только переданные поля
if 'text' in data:
question.text = data['text']
db.session.commit()
return jsonify({
'id': question.id,
'text': question.text
}), 200
PATCH vs PUT: PUT заменяет весь объект; PATCH обновляет только переданные поля. В нашем случае у Question только одно поле text, поэтому они идентичны — но паттерн PATCH важен при наличии нескольких полей.
Задание 6. Логика add_response — ответы
-
Единственный commit в конце:
commit()отправляет транзакцию в БД. Если вызвать его дважды, первый сохранит толькоResponse, ноStatisticокажется несинхронизированной при сбое между двумяcommit(). Единственныйcommit()гарантирует атомарность: либо оба объекта сохраняются, либо оба откатываются. -
Двойная отправка is_agree=true:
agree_countстанет 2. Каждый вызов инкрементирует счётчик. Защиты от дубликатов нет (нужна отдельная логика — IP/сессии). -
Первый ответ is_agree=false для вопроса без Statistic: создаётся запись
Statistic(agree_count=0, disagree_count=0), затемdisagree_count += 1. Итоговое состояние:agree_count=0, disagree_count=1.