0

db クエリを使用する適切な方法を見つけるのに問題があります。私は Web 開発の経験があまりありません。勤務時間外に 6 か月間 (つまり、週に最大 10 時間) 働いているようなものです。私が Pyramid を選んだのは、主に Py3k をサポートしているためです。django やチュートリアルほど多くのコミュニティ サポートがないため、間違ったことをしている可能性があります。そう...

私は Pyramid(1.4) と SQLAlchemy (0.8) を使用しています。Pyramid のチュートリアルで説明されているとおりにプロジェクトを作成しました。

の使用に関するこの優れた投稿 ( https://stackoverflow.com/a/11547942/1498245 )を既に読みましたscoped_session

しかし..私は、DBオブジェクトの処理に対する適切な(存在する場合)アプローチに苦労しています。

だからここに私が始めたものがあります:

## Project layout
myproject
├── models
│   ├── somemodel1.py
│   ├── somemodel2.py
│   ├── __init__.py
│   ├── meta.py
│   └── somemodel3.py
├── schemas
│   ├── some_colander_schema1.py
│   ├── some_colander_schema2.py
│   └── some_colander_schema3.py
├── scripts
│   ├── __init__.py
│   └── initializedb.py
├── static
│   ├── bootstrap
│   ├── favicon.ico
│   ├── jquery-1.9.1.min.js
│   └── transparent.gif
├── templates
│   ├── some_chameleon_template.pt
│   ├── some_chameleon_template1.pt
│   ├── some_chameleon_template2.pt
│   ├── forbidden_view.pt
│   ├── global_layout_noauth.pt
│   └── global_layout.pt
├── views
│   ├── someviewclass1.py
│   ├── someviewclass2.py
│   └── someviewclass3.py
└── __init__.py


# models/meta.py PRE @contextmaker
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import scoped_session, sessionmaker

DBSession   = scoped_session(sessionmaker())
Base        = declarative_base()

さて、要点です。

私の見解では、次の構成を使用していました。

class SomeView1(Layout): #in Layout class request is saved to self.request
    @view_config(...)
    def list(self):
        DBSession()
        try:
            somethings = DBSession.query(SomeModel).options(eagerload(...)).filter(...).all()
        except: #it's bad to catch everything I know, but had to close session properly
            somethings = []
            DBSession.rollback()
        DBSession.remove()

        ... #do something more

        DBSession()
        try:
            somethingMores = DBSession.query(SomeModel2).options(eagerload(...)).filter(...).all()
        except: #it's bad to catch everything I know, but had to close session properly
            somethingMores = []
            DBSession.rollback()
        DBSession.remove()

        return {"values" : somethings,
                "others" : somethingMores}

    @view_config(...)
    def edit(self):
        # here's recently implemented "update"
        DBSession()
        try:
            somethings = DBSession.query(SomeModel1)...all()
            somethingsMore = DBSession.query(SomeModel2)...all()
        finally:
            DBSession.remove()
        return {"somethings":somethings,
                "somethingsMore": somethingsMore}

しかし、そのようなクエリがたくさんあることに気付きました..それで、それらをモデルに移動しました。

私の見解では、私はただ電話しなければなりませんでした:

somethings = SomeModel1.all()
#or
something = SomeModel.by_id(some_id)

その中でSomeModel1、例えば:

class SomeModel(Base):
    __tablename__ = "somemodel"
    idsomeModel = Column(Integer, primary_key=True)

    @classmethod
    def all(cls):
        DBSession()
        try:
            retval = ...
        except:
            retval = None
        finally:
            DBSession.remove()
        return retval

それはすべて素晴らしいです(実際にはそうではありませんが、待って..)が、たとえばソート順やwhere句を配置する必要がある場合は厄介になります。次に、次のような多くのs にdef all(cls)変わりました。def all(cls, **kwargs)if

query = DBSession.query(SomeModel)
if "forPeriod" in kwargs:
    query = query.filter(SomeModel.date > kwargs["forPeriod"])
if "sortOrder" in kwargs:
    query = query.order_by(kwargs["sort"])

retval = query.all()

大丈夫ですか?または、ビューにクエリを記述する必要がありますか? 「良い方法」はないと思いますが、このアプローチの方が保守しやすいと思います。

そして、それは良くありません。今、私は sqlalchemy サイトで、セッションをモデルに渡す方がはるかに優れていることを読みました。このように、私の見解では、次のように使用します。

@view_config(...)
def some_function(self):
    with get_db_session as session:
        somethings = SomeModel.all(session, some_arguments)

その関数get_db_sessionは new からのものですmodels/meta.py:

# models/meta.py
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import scoped_session, sessionmaker
from contextlib import contextmanager

DBSession   = scoped_session(sessionmaker())
Base        = declarative_base()

@contextmanager
def get_scoped_session():
    try:
        yield DBSession()
    finally:
        DBSession.remove()

とんでもない投稿ですが、誰かに「よし、いい方向に進んでいる」とか「いや、クソ野郎、何してるの?」と言ってもらいたいです。

すべてを要約すると:

  1. モデルでクエリを非表示にすることは良い考えですか? (時にはたくさんのifs on kwargs; とあいまいな例外があります - そのようなことが起こった場合、私の戻り値は None です。なぜなら、私は理由が何であったか気にしないので、(モデルで) ログに記録しました)

  2. このような scoped_session@contextmanagerwithステートメントの使用は良いアプローチですか?

  3. いいえ、3 番目の質問はありません.. 2 つの質問をするためだけにテキストが多すぎます :/

4

2 に答える 2

2

#1の場合:

クエリには scoped_session.query_property() を使用し、それらをあまり非表示にせず、ベースを次のようにセットアップします。

from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import scoped_session, sessionmaker

DBSession = scoped_session(
    sessionmaker(
        extension='ZopeTransactionExtension'  # for your 2nd question
    )
)

class ORMClass(object):
    query = DBSession.query_property()

Base = declarative_base(cls=ORMClass)

通常どおり、この Base クラスからモデルを派生させます。

class MyModel(Base):
    ...

これで、次のことができるようになります:

MyModel.query.filter_by(attr1='something').all()

#2について:梅星に同意します。トランザクションマネージャーを使用します

于 2014-02-01T01:08:17.507 に答える
1

#2に関する限り、トランザクションを使用します

with transaction.manager:
    p = Page()
    p.title = "Page Title"
    p.content = "Page Content"
    dbsession.add(p)
p = dbsession.merge(p)
于 2013-12-02T16:48:43.037 に答える