Правильно ли в этом случае выполнять запрос к базе данных?

Я начинаю осваивать SQLAlchemy, валидацию данных и бэкенд в целом. После дня, посвященного чтению статей, я решил создать что-то самостоятельно и сумел интегрировать валидацию данных через Pydantic в свою модель таблицы. 

Вот как выглядят моя модель таблицы и модель данных для её валидации (так как SQLAlchemy не поддерживает кастомную валидацию): 

```python
class Base(DeclarativeBase):
    pass

# Модель Pydantic для валидации данных
class StudentValidation(BaseModel):
    student_first_name: str
    student_last_name: str | None
    specialty: str  # Если это список строк
    enrolment: str

    @field_validator("student_first_name")
    def validate_student_first_name(cls, value):
        if len(value) > 50:
            raise ValueError("Длина имени не должна превышать 50 символов.")
        if value[0].isdigit():
            raise ValueError(f"Имя не должно начинаться с цифры: {value}")
        return value

    @field_validator("student_last_name")
    def validate_student_last_name(cls, value):
        if len(value) > 50:
            raise ValueError("Длина фамилии не должна превышать 50 символов.")
        if value[0].isdigit():
            raise ValueError(f"Фамилия не должна начинаться с цифры: {value}")
        return value
    
    @field_validator("specialty")
    def validate_specialty(cls, value):
        if value not in specialties:
            raise ValueError(f"Приведенная специальность -> {value}, в то время как список допустимых -> {specialties}")
        return value

# Модель SQLAlchemy для таблицы students
class Student(Base):
    __tablename__ = "students"
    student_id: Mapped[int] = mapped_column(primary_key=True)
    student_...
```

Можете дать советы по улучшению структуры или подхода к реализации?
  • 22 апреля 2025 г. 21:15
Ответы на вопрос 2
Ваш подход к интеграции валидации данных с использованием Pydantic и SQLAlchemy выглядит достаточно здраво, и вы уже сделали немало шагов в правильном направлении. Однако есть несколько аспектов, которые вы можете рассмотреть для улучшения структуры и подхода к реализации.

### Рекомендации по улучшению структуры и подхода

1. **Разделите слои приложения**:
   - Хорошей практикой является разделение структур данных и бизнес-логики. Если ваша модель Pydantic используется только для валидации входящих данных, вы можете вынести её в отдельный модуль или файл. Это сделает ваш код более организованным и удобным для сопровождения.

2. **Обработка ошибок**:
   - Рассмотрите способ обработки ошибок, которые могут возникать при валидации. Используйте механизм обработки исключений, чтобы вернуть пользователю понятное сообщение об ошибке.

3. **Сложные проверки (например, уникальность)**:
   - Для таких проверок, как уникальность (если требуется), лучше выполнять их на уровне базы данных, поскольку это может привести к гонкам данных.

4. **Используйте аннотации типов для SQLAlchemy**:
   - Если вы используете Python 3.9 или новее, рекомендуется использовать синтаксис `list[str]` вместо `str | None` для типизации списков, чтобы избежать путаницы. Например:
     ```python
     specialty: list[str]
     ```

5. **Специальности валидации**:
   - Проверьте, что ваша переменная `specialties`, используемая в `validate_specialty`, объявлена и инициализирована заранее. Это может быть список из базы данных, чтобы актуализировать значения специальностей.

6. **Логика взаимодействия с базой данных**:
   - Убедитесь, что вы правильно обрабатываете создание, обновление и удаление записей в базе данных. Используйте контексты транзакций для безопасного выполнения запросов к базе данных.

7. **Изолированное тестирование**:
   - Напишите тесты для вашей валидации. Использование библиотеки, такой как `pytest`, может помочь вам проверить корректность вашей логики.

### Пример улучшенной реализации

Ниже приведен пример возможной структуры классов с учётом некоторых рекомендаций:

```python
# models.py
from sqlalchemy.orm import Mapped, mapped_column
from sqlalchemy.ext.declarative import DeclarativeBase
from pydantic import BaseModel, field_validator

class Base(DeclarativeBase):
    pass

class Student(Base):
    __tablename__ = "students"
    student_id: Mapped[int] = mapped_column(primary_key=True)
    student_first_name: Mapped[str]
    student_last_name: Mapped[str | None]
    specialty: Mapped[str]
    enrolment: Mapped[str]

# validation.py
class StudentValidation(BaseModel):
    student_first_name: str
    student_last_name: str | None
    specialty: str
    enrolment: str

    @field_validator("student_first_name")
    def validate_student_first_name(cls, value):
        if len(value) > 50:
            raise ValueError("Длина имени не должна превышать 50 символов.")
        if value[0].isdigit():
            raise ValueError(f"Имя не должно начинаться с цифры: {value}")
        return value

    @field_validator("student_last_name")
    def validate_student_last_name(cls, value):
        if value and len(value) > 50:
            raise ValueError("Длина фамилии не должна превышать 50 символов.")
        if value and value[0].isdigit():
            raise ValueError(f"Фамилия не должна начинаться с цифры: {value}")
        return value

    @field_validator("specialty")
    def validate_specialty(cls, value):
        if value not in specialties:  # убедитесь, что specialties определены
            raise ValueError(f"Приведенная специальность -> {value}, в то время как список допустимых -> {specialties}")
        return value
```

---

Такое разделение может помочь вам легче управлять кодом и соблюдать принципы SOLID. Удачи в ваших дальнейших усилиях по разработке с использованием SQLAlchemy и Pydantic!
Есть сомнения по поводу корректности схемы, правил валидаций, названий полей но их нет смысла озвучивать, если нет описания решаемой задачи. 

Например странно, что в модели студента есть поле "имя студента", как будто там может быть какое-то ещё имя, а просто "имя" будет не именем студента, а чем-то иным.

В остальном выглядит ок.
Похожие вопросы