Как гарантировать, что вставки принимают только значения, определенные в Enum?

Я пытаюсь создать простое приложение для записи платежей, в котором будут храниться сумма и тип платежа. Для типа оплаты у меня есть «наличные» и «кредит», которые определены в режиме:

from enum import Enum

class Mode(Enum):
    cash: str
    upi: str

Затем я определяю создаваемую таблицу с ее полем как:

from sqlalchemy import Column, Integer, Float, Enum
from utils.database import Base
from utils.paytype import Mode


class Records(Base):
    __tablename__ = "records"

    id = Column(Integer, primary_key=True, index=True)
    amount = Column(Float, nullable=False)
    payment_type = Column(Enum(Mode), nullable=False)

Когда я пытаюсь добавить запись в таблицу, я могу предоставить любую строку в качестве входных данных для payment_type, что не было идеей. Как гарантировать, что записи принимают только один из двух определенных?

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
0
56
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вы на самом деле не можете. В sqlite нет типа Enum: https://www.sqlite.org/datatype3.html

Что вы можете сделать, так это использовать pydantic, чтобы проверить входные данные и в конечном итоге поднять ValidationError

from sqlalchemy import Column, Integer, Float, String
from pydantic import BaseModel
from utils.database import Base
from typing import Literal

class Records(Base):
    __tablename__ = "records"

    id = Column(Integer, primary_key=True, index=True)
    amount = Column(Float, nullable=False)
    payment_type = Column(String, nullable=False)

class RecordCreate(BaseModel):
    amount: float
    payment_type: Literal["cash", "credit"]

Сюда

record = RecordCreate(amount=3.14, payment_type = "credit") # this is OK
record = RecordCreate(amount=3.14, payment_type = "foo")    # this raises a ValidationError

Затем вам следует отправить в базу данных сериализованный объект RecordCreate, т.е.

**record.model_dump()  # with Pydantic v2
**record.dict()        # with Pydantic v1

и используйте Records для чтения данных из БД.

Спасибо за совет. Есть ли способ сделать то, что я хотел, в MySQL или Postgres?

mraabhijit 02.08.2024 18:13

Да, есть docs.sqlalchemy.org/en/20/core/…

ychiucco 02.08.2024 19:30
Ответ принят как подходящий

Ваше определение перечисления неверно — оно использует подсказки типов, которые фактически не создают никаких членов. Что вам нужно:

class Mode(Enum):
    cash = "cash"
    upi = "upi"

Чтобы сделать его доступным для использования в sqlite, добавьте метод адаптера в ваше перечисление:

class Mode(Enum):
    #
    cash = "cash"
    upi = "upi"
    #
    def __conform__(self, protocol):
        if protocol is sqlite3.PrepareProtocol:
            return self.name

Если у вас есть несколько перечислений, которые будут использоваться sqlite, создайте свой собственный базовый класс и используйте его:

import enum
import sqlite

class SqliteEnum(enum.Enum):
    def __conform__(self, protocol):
        if protocol is sqlite3.PrepareProtocol:
            return self.name

class Mode(SqliteEnum):
    cash = "cash"
    upi = "upi"

спасибо за правильный путь. К сожалению, не могу проголосовать за ответ из-за отсутствия репутации.!

mraabhijit 03.08.2024 09:51

Другие вопросы по теме