Какова лучшая практика для поиска значений в SQLAlchemy? - PullRequest
1 голос
/ 26 февраля 2020

Я пишу довольно простое c Flask приложение, использующее Flask-SQLAlchemy для отслеживания запасов и распределения. Я мог бы использовать некоторые рекомендации о том, как лучше всего обращаться с таблицей поиска для общих значений. Моя база данных будет MySQL и ElasticSearch для поиска.

Если у меня есть общая структура отображения, где все данные, входящие в конкретную c таблицу, скажем Vehicle, имеют общий список значений чтобы посмотреть на столбец Vehicle.make, каким будет наилучший способ добиться этого?

Я думаю, что подойти к этому можно одним из двух способов:

Таблица поиска

Я мог бы создать нечто похожее на это, где у меня есть отношения, и сохранить марку в VehicleMake. Однако, если мой ожидаемый список производителей низок (скажем, 10), это кажется ненужным.

class VehicleMake(Model):
    id = Column(Integer, primary_key=True)
    name = Column(String(16))
    cars = relationship('Vehicle', backref='make', lazy='dynamic')

class Vehicle(Model):
    id = Column(Integer, primary_key=True)
    name = Column(String(32))

Сохранить как строку

Я мог бы просто сохранить это как строку на Vehicle модели. Но будет ли пустая трата места для хранения общего значения в виде строки?

class Vehicle(Model):
    id = Column(Integer, primary_key=True)
    name = Column(String(32))
    make = Column(String(16))

Моя первоначальная идея состояла в том, чтобы просто иметь диктовку, содержащую подобное отображение, и ссылаться на нее по мере необходимости в модели. Я просто не понимаю, как это сделать ie при возврате модели автомобиля.

MAKE_LIST = {
    1: 'Ford',
    2: 'Dodge',
    3: 'Chevrolet'
}

Любые отзывы приветствуются - и если есть документация, которая описывает этот конкретный c сценарий, я счастлив прочитать это и ответить на этот вопрос сам. Мой ожидаемый объем будет низким (40-80 записей в неделю), поэтому он не должен быть смехотворно быстрым, я просто хочу следовать передовым методам.

1 Ответ

1 голос
/ 26 февраля 2020

Короткий ответ: , это зависит.

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

Если вам нужно хранить не только название каждой марки, но и некоторые дополнительные метаданные, такие как размер бензобака, размер автомобиля go или даже сортировочный ключ, go для дополнительная таблица. Затраты на такую ​​маленькую таблицу минимальны, и если вы общаетесь с внешним интерфейсом, используя make ids вместо make names , с этим вообще не возникает никаких проблем. Просто не забудьте добавить индекс к vehicle.make_id, чтобы сделать поиск более эффективным.

class VehicleMake(Model):
    id = Column(Integer, primary_key=True)
    name = Column(String(16))
    cars = relationship('Vehicle', back_populates="make", lazy='dynamic')

class Vehicle(Model):
    id = Column(Integer, primary_key=True)
    name = Column(String(32))
    make_id = Column(Integer, ForeignKey('vehicle_make.id'), nullable=False)
    make = relationship("VehicleType", innerjoin=True)

Vehicle.query.get(1).make.name # == 'Ford', the make for vehicle 1
Vehicle.query.filter(Vehicle.make_id == 2).all() # all Vehicles with make id 2
Vehicle.query.join(VehicleMake)\
    .filter(VehicleMake.name == 'Ford').all() # all Vehicles with make name 'Ford'

Если вам не нужно хранить какие-либо из этих метаданных, то необходимость в отдельной таблице исчезает. Тем не менее, общая проблема со строками состоит в том, что существует высокий риск орфографических ошибок и заглавных / строчных букв, которые нарушают целостность данных. Если вам не нужно много добавлять новых марок, гораздо лучше просто использовать Enums , в SQLAlchemy есть даже MySQL speci c.

import enum

class VehicleMake(enum.Enum):
    FORD = 1
    DODGE = 2
    CHEVROLET = 3

class Vehicle(Model):
    id = Column(Integer, primary_key=True)
    name = Column(String(32))
    make = Column(Enum(VehicleMake), nullable=False)

Vehicle.query.get(1).make.name # == 'FORD', the make for vehicle 1
Vehicle.query.filter(Vehicle.make == VehicleMake(2)).all() # all Vehicles with make id 2
Vehicle.query.filter(Vehicle.make == VehicleMake.FORD).all() # all Vehicles with make name 'Ford'

Основной недостаток перечислений в том, что их может быть сложно расширить новыми значениями, хотя по крайней мере для Postgres версия диалекта c была намного лучше, чем общая версия SQLAlchemy, посмотрите на sqlalchemy.dialects.mysql.ENUM вместо. Хотя, если вы хотите расширить существующий enum, вы всегда можете просто выполнить raw SQL в ваших Flask -Migrate / Alembi c миграциях.

Наконец, преимущества используя строки. Главным образом, это то, что вы всегда можете программно обеспечить согласованность данных. Но это происходит за счет того, что вы должны программно обеспечить согласованность данных. Если внешний вид автомобиля может быть изменен или вставлен внешними пользователями, даже коллегами, это доставит вам неприятности, если вы не будете очень строги в отношении того, что входит в вашу базу данных. Например, было бы неплохо прописать все значения в верхнем регистре для упрощения группировки, поскольку это эффективно уменьшает то, что go может ошибаться. Вы можете сделать это во время записи или добавить индекс на sqlalchemy.func.upper(Vehicle.make) и использовать гибридные свойства , чтобы всегда запрашивать значение в верхнем регистре.

class Vehicle(Model):
    id = Column(Integer, primary_key=True)
    name = Column(String(32))
    _make = Column('make', String(16))

    @hybrid_property
    def make(self):
        return self._make.upper()

    @make.expression
    def make(cls):
        return func.upper(cls._make)

Vehicle.query.get(1).make.upper() # == 'FORD', the make for vehicle 1
Vehicle.query.filter(Vehicle.make == 'FORD').all() # all Vehicles with make name 'FORD'

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

...