Модели Django / SQLAlchemy раздуты! Какие-нибудь действительно Pythonic модели DB там? - PullRequest
6 голосов
/ 05 июня 2010

" Сделать все как можно проще, но не проще. "

Можем ли мы найти решения, которые исправят мир баз данных Python?

Обновление: Алекс Мартелли написал прототип 'lustdb' - если вы знаете какие-нибудь легковесные высокоуровневые библиотеки баз данных с несколькими бэкэндами, которые можно было бы обернуть в синтаксис сахарного меда,Пожалуйста, взвесьте!

from someAmazingDB import *  
#we imported a smart model class and db object which talk to database adapter/s
class Task (model): 
    title = ''
    done = False #native types not a custom object we have to think about!

db.taskList = []
#or
db.taskList = expandableTypeCollection(Task) #not sure what this syntax would be

db['taskList'].append(Task(title='Beat old sql interfaces',done=False))
db.taskList.append(Task('Illustrate different syntax modes',True)) # ok maybe we should just use kwargs

#at this point it should be autosaved to a default db option

#by default we should be able to reload the console and access the default db:

>> from someAmazingDB import *
>> print 'Done tasks:'
>> for task in db.taskList:
>>     if task.done:
>>         print task.title
'Illustrate different syntax modes'

Я фанат Python , webPy и Cherry Py, и KISS в целом.

Мы говорим автоматический Python в SQL перевод типа или NoSQL. Нам не обязательно быть полностью совместимыми с SQL!Просто масштабируемое подмножество или игнорируйте его!

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

Вот проблема: Приведенный выше код должен работать с минимальными изменениями или необходимыми размышлениями.Почему мы должны мириться с компромиссом, когда знаем лучше?

Это 2010 год, мы должны быть в состоянии кодировать масштабируемые, простые базы данных во сне.

Если вы думаете,это важно, пожалуйста, upvote!

Ответы [ 8 ]

9 голосов
/ 05 июня 2010

То, что вы запрашиваете, не может быть выполнено в Python 2. независимо от по очень конкретной причине. Вы хотите написать:

class Task(model): 
    title = ''
    isDone = False

В Python 2. что-нибудь , независимо от того, что model может быть, это не может когда-либо позволить вам предсказать любой "порядок" для двух полей потому что семантика оператора class:

  1. выполнить тело, таким образом готовя dict
  2. найдите метакласс и запустите его специальные методы

Каким бы ни был метакласс, шаг 1 разрушил любую предсказуемость порядка полей.

Следовательно, желаемое использование позиционных параметров в фрагменте:

Task('Illustrate different syntax modes', True)

не может связать значения аргументов с различными полями модели. (Попытка угадать по типу ассоциации - надеясь, что никакие два поля никогда не будут иметь один и тот же тип - будет еще более ужасной, чем у вас выраженное желание использовать db.tasklist и db['tasklist'] безразлично и взаимозаменяемо).

Одно из обратно несовместимых изменений в Python 3 было введено специально для решения подобных ситуаций. В Python 3 пользовательский метакласс может определять функцию __prepare__, которая запускается за до «шага 1» в приведенном выше упрощенном списке, и это позволяет ему иметь больше контроля над телом класса. В частности, цитата PEP 3115 ...:

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

...

Примером может служить метакласс, который использует информацию о упорядочение объявлений членов для создания структуры Си. Метакласс будет предоставлять пользовательский словарь, который просто ведет запись порядок вставок.

Вы не хотите «создавать структуру C», как в этом примере, но порядок полей имеет решающее значение (чтобы разрешить использование требуемых позиционных параметров), и поэтому пользовательский метакласс (полученный с помощью base * 1050) *) будет иметь метод класса __prepare__, возвращающий упорядоченный словарь. Это устраняет конкретную проблему, но, конечно, только , если вы хотите переключить весь свой код с помощью этой «магической ORM» на Python 3. Вы бы хотели?

Как только это будет решено, вопрос в том, какие операции с базой данных вы хотите выполнить и как. Ваш пример, конечно, не проясняет это вообще. Является ли имя атрибута taskList особенным или любой другой атрибут, назначенный объекту db, должен быть "автоматически сохранен" (по имени и каким другим характеристикам [s]?) И "автоматически восстановлен" при использовании ? Есть ли способы удалить сущности, изменить их, найти их (иначе, чем когда-то в списке в том же атрибуте объекта db)? Как ваш пример кода знает, какую службу БД использовать и как к ней аутентифицироваться (например, с помощью идентификатора пользователя и пароля), если она требует аутентификации?

Конкретные задачи, которые вы перечислите, не составит труда реализовать (например, в верхней части службы хранения Google App Engine, которая не требует аутентификации или указания «какую службу БД использовать»). Метакласс model будет анализировать поля класса и генерировать GAE Model для класса, объект db будет использовать __setattr__ для установки триггера atexit для хранения окончательного значения атрибута (как сущности в другом виде Model, конечно) и __getattr__ для извлечения информации об этом атрибуте из хранилища. Конечно, без какой-либо дополнительной функциональности базы данных все это было бы довольно бесполезно; -).

Редактировать : поэтому я сделал небольшой прототип (Python 2.6 и на основе sqlite) и поставил его на http://www.aleax.it/lustdb.zip - это 3K-файл zipfile, включающий 225 строк lustdb.py (слишком длинный, чтобы публиковать здесь) и два небольших тестовых файла, примерно эквивалентных оригиналам ОП: test0.py is ...:

from lustdb import *  

class Task(Model): 
    title = ''
    done = False

db.taskList = []    
db.taskList.append(Task(title='Beat old sql interfaces', done=False))
db.taskList.append(Task(title='Illustrate different syntax modes', done=True))

и test1.p1 - это ...:

from lustdb import *

print 'Done tasks:'
for task in db.taskList:
    if task.done:
        print task

Запуск test0.py (на машине с доступным для записи каталогом /tmp - т. Е. Любой ОС Unix-y или, в Windows, на которой mkdir \tmp был запущен в любое предыдущее время ;-) не имеет выхода; после этого работает test1.py выводит:

Done tasks:
Task(done=True, title=u'Illustrate different syntax modes')

Обратите внимание, что они гораздо менее "безумно волшебны", чем примеры ОП, во многих отношениях, например ...:

1. no (expletive delete) redundancy whereby `db.taskList` is a synonym of `db['taskList']`, only the sensible former syntax (attribute-access) is supported
2. no mysterious (and totally crazy) way whereby a `done` attribute magically becomes `isDone` instead midway through the code
3. no mysterious (and utterly batty) way whereby a `print task` arbitrarily (or magically?) picks and prints just one of the attributes of the task
4. no weird gyrations and incantations to allow positional-attributes in lieu of named ones (this one the OP agreed to)

Конечно, прототип (как и прототипы ;-) оставляет желать лучшего во многих отношениях (ясность, документация, модульные тесты, оптимизация, проверка ошибок и диагностика, переносимость между различными бэк-эндами и особенно функции БД за пределами возможностей те, которые подразумеваются в вопросе). Отсутствующие функции БД - легион (например, оригинальные примеры OP не дают возможности идентифицировать «первичный ключ» для модели или любые другие виды ограничений уникальности, поэтому дубликатов может быть достаточно, и от этого только ухудшается; - ). Тем не менее, для 225 строк (190 пустых строк, комментариев и строк документации ;-), по моему предвзятому мнению, это не так уж и плохо.

Надлежащим способом продолжения игры с этим проектом будет, конечно, инициирование нового lustdb проекта с открытым исходным кодом на хостинговой части code.google.com (или на любом другом хорошем хостинг-сайте с открытым исходным кодом с трекером проблем, вики). , поддержка обзоров кода, онлайн-просмотр, поддержка DVCS и т. д., и т. д.) - Я бы сделал это сам, но я близок к ограничению по количеству проектов с открытым исходным кодом, которые я могу инициировать на code.google.com и не могу не хочу «сжечь» последние один или два таким образом; -).

Кстати, имя lustdb для модуля - игра слов с инициалами ОП (первые две буквы - имена и фамилии), в традиции awk и друзей - я думаю, это звучит красиво (и большинство других очевидных имен, таких как simpledb и dumbdb взяты; -).

3 голосов
/ 05 июня 2010

Я думаю, вы должны попробовать ZODB . Это объектно-ориентированная база данных, предназначенная для хранения объектов Python. Его API очень близок к примеру, который вы предоставили в своем вопросе, просто посмотрите учебник .

2 голосов
/ 05 июня 2010

Как насчет использования Эликсир ?

1 голос
/ 05 июля 2010

Я был занят, вот он, выпущен под LGPL: http://github.com/lukestanley/lustdb

Он использует JSON в качестве бэкэнда на данный момент.

Это не та же кодовая база Алекс Мартелли сделал. Я хотел сделать код более читабельным и многоразовым бэкэнды и прочее.

В других местах я работал над объектно-ориентированными элементами HTML. доступны в Python похожими способами и библиотекой для создания web.py более минималистский.

Я думаю о способах использования всех трех элементов вместе с автоматическим Конструкция прототипа MVC или интеллектуальное картографирование.

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

См. Список рассылки для тех, кто заинтересован.

1 голос
/ 05 июня 2010

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

(А из них все равно будет ВЫ , что потребуется , необходимых для передачи информации / конфигурации в механизм интерфейса базы данных, где-то, каким-то образом.)

Назовите только один пример:

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

1 голос
/ 05 июня 2010

Чем больше я думаю, тем больше модель работы Smalltalk кажется более актуальной. В самом деле, ОП, возможно, не достиг достаточно далеко, используя термин «база данных», чтобы описать то, что не должно называться.

У работающего интерпретатора Python есть куча объектов, которые живут в памяти. Их взаимосвязи могут быть сколь угодно сложными, но пространства имен и «теги», к которым привязаны объекты, очень гибки. И поскольку pickle может явно сериализовать произвольные структуры для сохранения, кажется, не слишком много возможностей для рассмотрения каждого интерпретатора Python, живущего в этом объектном пространстве. Почему пространство этого объекта испаряется при закрытии переводчика? Семантически, это можно рассматривать как расширение anydbm связанных словарей. И поскольку почти все в Python похоже на словарь, механизм почти уже существует.

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

class Book:
    def __init__(self, attributes):
        self.attributes = attributes
    def __getattr__(....): pass

$ python
>>> import book
>>> my_stuff.library = {'garp': 
    Book({'author': 'John Irving', 'title': 'The World According to Garp', 
      'isbn': '0-525-23770-4', 'location': 'kitchen table', 
      'bookmark': 'page 127'}),
    ...
    }
>>> exit

[где-то на следующей неделе]

$ python
>>> import my_stuff
>>> print my_stuff.library['garp'].location
'kitchen table'
# or even
>>> for book in my_stuff.library where book.location.contains('kitchen'):
   print book.title

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

Существует естественная напряженность между внутренней структурой, навязываемой - и иногда желаемой - RDBM, и довольно пристальным взглядом на пуп, изложенным здесь, но базы данных NoSQLy уже приближаются к модели адресуемой памяти контента и, вероятно, лучше приближаются к тому, как наши умы следить за вещами. Наоборот, вы не хотели бы хранить все корпоративные заказы на покупку, такие как система хранения, но, возможно, вы могли бы.

1 голос
/ 05 июня 2010

Забудь ОРМ! Мне нравится ванильный SQL. Оболочки Python, такие как psycopg2 для postgreSQL, выполняют автоматическое преобразование типов, предлагают довольно хорошую защиту от SQL-инъекций и просты и приятны.

sql = "SELECT * FROM table WHERE id=%s"
data = (5,)
cursor.execute(sql, data)
0 голосов
/ 15 апреля 2011

Если вам нравится CherryPy, вам могут понравиться дополнительные ORM, которые я написал: GeniuSQL (который следует модели шлюза табличных данных) и Dejavu (который является полным Data Mapper).

Слишком много в этом вопросе и во всех его подкомментариях для полного рассмотрения, но я хотел бы отметить одну вещь: GeniuSQL и Dejavu имеют очень надежную систему для сопоставления нативных типов Python с типами, которые использует ваш конкретный бэкэнд , Существуют очень разумные значения по умолчанию, которые могут быть переопределены по мере необходимости и даже расширены, если вы создаете новый бэкэнд или используете типы из бэкэнда, который еще не поддерживается. Подробнее об этом см. http://www.aminus.net/geniusql/chrome/common/doc/trunk/advanced.html#custom.

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