Python, SQLAlchemy и Postgresql: понимание наследования - PullRequest
1 голос
/ 06 октября 2011

Совсем недавно (но не для новорожденных) в Python, SQLAlchemy и Postgresql, и очень трудно понять наследование.

Поскольку я беру код другого программиста, мне нужно понять, что необходимо, игде, чтобы концепция наследования сработала.

Мои вопросы:

  1. Можно ли полагаться только на SQLAlchemy для наследования?Другими словами, может ли SQLAlchemy применять наследование к таблицам базы данных Postgresql, которые были созданы без указания INHERITS =?

  2. Является ли технология Declarative_base (SQLAlchemy) необходимой для правильного использования наследования.Если это так, нам придется все переписать, поэтому, пожалуйста, не отчаивайтесь.

  3. Предполагая, что мы можем использовать экземпляр Table, пустые классы Entity и mapper (), не могли бы вы дать мне(очень простой) пример того, как правильно пройти процесс (или ссылка на легко понятный учебник - я пока не нашел достаточно простого).

Реальный мир, который мыработаем над объектами недвижимости.Таким образом, мы в основном имеем - один объект immobject (id, createtime) - один атрибут объекта таблицы (id, immoobject_id, oatype) - несколько таблиц атрибутов: oa_attributename (oa_id, attributevalue)

Заранее спасибо за помощь.

Винсент

Ответы [ 2 ]

4 голосов
/ 06 октября 2011

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

Наследование таблиц в postgres - это совсем другое дело, и оно решает другой набор проблем по сравнению с наследованием классов в python, и sqlalchemy не пытается объединить их.

Когда вы используете наследование таблиц в postgres, вы делаете некоторые хитрости на уровне схемы, чтобы можно было применять более сложные ограничения, которые могут быть легко выражены другими способами; Как только вы разработали свою схему; приложения обычно не знают о наследовании; Если они вставят строку; это просто волшебно появляется в родительской таблице (очень похоже на представление). Это полезно, например, для повышения эффективности некоторых видов массовых операций (вы можете просто отбросить таблицу на январь месяц).

Это принципиально отличная идея от наследования, как видно из ООП (в python или иным образом, с реляционным постоянством или иным образом). В этом случае приложение знает , что два типа связаны и что подтип является допустимой заменой надтипа. «Удержание - это адрес, у контакта есть адрес, поэтому у контакта может быть удержание».

Какой из этих (в основном ортогональных) инструментов вам нужен, зависит от приложения. Вам может не понадобиться ни то, ни другое.


  1. Механизмы Sqlalchemy для работы с наследованием объектов являются гибкими и надежными, вы должны использовать их в пользу домашнего решения, если оно совместимо с вашими конкретными потребностями (это должно быть верно почти для всех приложений).

  2. Декларативное расширение - это удобство; Это позволяет вам описать сопоставленную таблицу, класс python и отображение между двумя в одной «вещи» вместо трех. Это делает ваш код более «сухим»; Однако это всего лишь удобство, наложенное поверх «классической sqlalchemy», и в этом нет никакой необходимости.

  3. Если вы обнаружите, что вам нужно наследование таблиц, которое видно из sqlalchemy; ваши сопоставленные классы не будут отличаться от неиспользования этих функций; Таблицы с наследованием по-прежнему являются нормальными отношениями (например, таблицы или представления) и могут отображаться без знания наследования в коде Python.

0 голосов
/ 06 октября 2011

Для вашего # 3 вам необязательно объявлять пустые классы сущностей, чтобы использовать mapper.Если вашему приложению не нужны причудливые свойства, вы можете просто использовать интроспекцию и метаклассы для моделирования существующих таблиц, не определяя их.Вот что я сделал:

mymetadata = sqlalchemy.MetaData()
myengine = sqlalchemy.create_engine(...)

def named_table(tablename):
  u"return a sqlalchemy.Table object given a SQL table name"
  return sqlalchemy.Table(tablename, mymetadata, autoload=True, autoload_with=myengine)

def new_bound_class(engine, table):
  u"returns a new ORM class (processed by sqlalchemy.orm.mapper) given a sqlalchemy.Table object"
  fieldnames = table.c.__dict__['_data']
  def format_attributes(obj, transform):
    attributes = [u'%s=%s' % (x, transform(x)) for x in fieldnames]
    return u', '.join(attributes)
  class DynamicORMClass(object):
    def __init__(self, **kw):
      u"Keyword arguments may be used to initialize fields/columns"
      for key in kw:
        if key in fieldnames: setattr(self, key, kw[key])
        else: raise KeyError, '%s is not a valid field/column' % (key,)
    def __repr__(self):
      return u'%s(%s)' % (self.__class__.__name__, format_attributes(self, repr))
    def __str__(self):
      return u'%s(%s)' % (str(self.__class__), format_attributes(self, str))
  DynamicORMClass.__doc__ = u"This is a dynamic class created using SQLAlchemy based on table %s" % (table,)
  return sqlalchemy.orm.mapper(DynamicORMClass, table)

def named_orm_class(table):
  u"returns a new ORM class (processed by sqlalchemy.orm.mapper) given a table name or object"
  if not isinstance(table, Table):
    table = named_table(table)
  return new_bound_class(table)

Пример использования:

>>> myclass = named_orm_class('mytable')
>>> session = Session()
>>> obj = myclass(name='Fred', age=25, ...)
>>> session.add(obj)
>>> session.commit()
>>> print str(obj)  # will print all column=value pairs

Я немного расширил свои версии new_bound_class и named_orm_class с помощью декораторов и т. Д., Чтобы обеспечитьдополнительные возможности, и вы тоже можете.Конечно, под прикрытием означает , объявив пустой класс сущностей.Но вам не нужно это делать, кроме этого один раз.

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

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