Заявки за външен ключ в SQLAlchemy

Аз съм нов в SQLAlchemy, след като дойдох от Django ORM. Опитвам се да създам прост модел на вложен набор и бих искал да направя родителско търсене. Което бих направил така в Django ORM:

Page.objects.get(slug="currentlevel",parent__slug="secondlevel",parent__parent__slug="firstlevel")

Това би направило автоматично запитване към базата данни за всеки родителски елемент, връщайки съответния ред на страницата.

В SQLAlchemy най-доброто, което мога да измисля, е:

session.query(Page).join(Page.parent, aliased=True).filter_by(slug="child")

Така че мога да отправя заявка към непосредствения родителски елемент, но как мога да продължа нагоре по веригата с една заявка? Динамично, ако е възможно (произволен брой нива)

Моля, имайте предвид, че съм нов в SQLAlchemy и идвам от относително защитената Django ORM. Сигурен съм, че има информация в документите на SQLAchemy, но я прочетох и не мога да я намеря.

Благодаря за вашата помощ.


person NeonMonk    schedule 16.03.2014    source източник
comment
Желанието ви да правите всичко в рамките на една заявка не е нищо друго освен преждевременна оптимизация :) Издаването на 2-3-5 отделни прости заявки, всяка от които извлича единичен обект от неговия PK, всъщност може да бъде по-бърза от една чудовищна заявка с 2-3-5 нива на самореферентни съединения, особено ако имате много редове в таблицата. Дори ако отделните заявки са малко по-бавни - говорим за микросекунди, което е пренебрежимо малко в общата схема на нещата. Ако вземете предвид това, нещата стават много по-прости :)   -  person Sergey    schedule 18.03.2014
comment
Друго предложение: този случай на използване е учебникарски пример, при който обхождането на URL адреса на Pyramid ще блести. Traversal е страхотен, опитайте :)   -  person Sergey    schedule 18.03.2014
comment
Всъщност използвам Traversal, но го използвам за подреждане на команди за присъединяване. Ще направя малко профилиране, но като цяло се опитвам да избягвам обажданията към базата данни, доколкото е възможно. Все пак има голям шанс да го мисля погрешно,   -  person NeonMonk    schedule 19.03.2014
comment
на моята машина извличането на един ред от таблица чрез нейния PK отнема 0,5 ms. Извличането на единичен ред от заявка с най-простото възможно самореферентно свързване (SELECT * FROM mytable a JOIN mytable b ON a.id=b.id WHERE a.id='boo') отнема 0,9 ms. Извличането на един ред от заявка с 2 самореферентни съединявания е около 1,2 ms. Така че е почти същото. Също така имайте предвид, че най-вероятно ще трябва да извлечете родителските страници така или иначе, дори само за да покажете техните заглавия в навигационните трохи или в менюто.   -  person Sergey    schedule 19.03.2014
comment
Добро мислене с галета.   -  person NeonMonk    schedule 19.03.2014


Отговори (1)


Прав сте, цялата информация в документите на sqlalchemy под Self-Referential Query Strategies . В този случай първоначалната ви заявка ще изглежда така:

from sqlalchemy.orm import aliased
page1 = aliased(Page)
page2 = aliased(Page)
qry = (session
        .query(Page).filter(Page.slug=='currentlevel')
        .join(page1, Page.parent).filter(page1.slug=="secondlevel")
        .join(page2, page1.parent).filter(page2.slug=="firstlevel")
        )

Или, използвайки aliasedfrom_joinpoint) аргументи, малко по-кратко:

qry = (session
        .query(Page).filter(Page.slug=='currentlevel')
        .join(Page.parent, aliased=True).filter(Page.slug=="secondlevel")
        .join(Page.parent, aliased=True, from_joinpoint=True).filter(Page.slug=="firstlevel")
        )
person van    schedule 16.03.2014
comment
Благодаря за това, псевдонимът с from_joinpoint беше точно това, което ми липсваше. - person NeonMonk; 19.03.2014