2011-03-08 4 views
7

現在、ほとんどのWebフレームワークと同様に、シリアライゼーションの作業には、モデルをある種の形式にダンプするメソッド呼び出しがあります。私たちの場合、フィールド名と値をインスタンス変数とするキー値辞書を作成して返すすべてのモデルに対して、to_dict()メソッドがあります。アクセス制御を尊重しながらREST APIのSQLAlchemyモデルをシリアライズしますか?

コード全体に次のようなスニペットがあります。json.dumps(**some_model_object.to_dict())some_model_objectをjsonにシリアル化します。最近、我々はいくつかの内部リソースをユーザーに公開することに決めましたが、これらのリソースの中には、要求ユーザーがスーパーユーザーでない場合にシリアル化中に返信したくない特定のプライベートインスタンス値があります。

私はjson以外の形式にシリアル化できるようにするだけでなく、シリアライズを容易にするクリーンなデザインを考え出しています。私はこれがAspect Oriented Design/Programmingのかなり良いユースケースだと思っています.Aspect Oriented Design/Programmingでは、アスペクトがリクエストしているアクセスコントロールを尊重し、リクエストするユーザの欲求に基づいてオブジェクトをシリアライズします。今、私はカップルに現在のリクエストでデータベースのモデルを持っているので、

from framework import current_request 


class User(SQLAlchemyDeclarativeModel): 
    __tablename__ = 'users' 

    id = Column(Integer, primary_key=True) 
    first_name = Column(Unicode(255)) 
    last_name = Column(Unicode(255)) 
    private_token = Column(Unicode(4096)) 

    def to_dict(self): 
     serialized = dict((column_name, getattr(self, column_name)) 
          for column_name in self.__table__.c.keys()) 

     # current request might not be bound yet, could be in a unit test etc. 
     if current_request and not current_request.user.is_superuser(): 
      # we explicitly define the allowed items because if we accidentally add 
      # a private variable to the User table, then it might be exposed. 
      allowed = ['id', 'first_name', 'last_name'] 
      serialized = dict((k, v) for k, v in serialized.iteritems() if k in allowed) 

     return serialized 

1が見ることができるように、これは理想的な未満です:

は、ここで私が今持っているものに似たものです。これは非常に明白ですが、リクエストカップリングはコードの匂いです。私はこれをきれいに行う方法を見出そうとしています。私はそれがそうのようなモデルにいくつかのフィールドを登録することであることについて考えた

一つの方法:

class User(SQLAlchemyDeclarativeModel): 
    __tablename__ = 'users' 
    __public__ = ['id', 'first_name', 'last_name'] 
    __internal__ = User.__exposed__ + ['private_token'] 

    id = Column(Integer, primary_key=True) 
    first_name = Column(Unicode(255)) 
    last_name = Column(Unicode(255)) 
    private_token = Column(Unicode(4096)) 

その後、私はすべてのWSGIコールに現在のリクエストにバインドされたシリアライザクラスを持っているでしょう必要なシリアライザを使用します。たとえば、次のように

import simplejson 

from framework import JSONSerializer # json serialization strategy 
from framework import serializer 

# assume response format was requested as json 
serializer.register_serializer(JSONSerializer(simplejson.dumps)) 
serializer.bind(current_request) 

はその後、私のビューのどこかに、私はどうなる:次のように

from framework import Response 

user = session.query(User).first() 
return Response(code=200, serializer.serialize(user)) 

serializeが実施される。このアプローチの読みやすさと明快に

def serialize(self, db_model_obj): 
    attributes = '__public__' 
    if self.current_request.user.is_superuser(): 
     attributes = '__private__' 

    payload = dict((c, getattr(db_model_obj, c)) 
        for c in getattr(db_model_obj, attributes)) 

    return self.serialization_strategy.execute(payload) 

思考?これは問題のpythonicアプローチですか?

ありがとうございます。

+0

変数Cの名前はわかりません。 :)そして私はserialization_strategyのようなものについて私の予約を持っています。クラスはすでにシリアライザであるため、冗長であり、デザインパターンの名前が落ちているようです。これは、関連するクラスを訪れる戦略のように、より具体的なものであると私は想定していますか?私はあなたが実際にあなたのフレームワーク「フレームワーク」に名前をつけるつもりはないことを願っています。 :) –

答えて

7

はミックスインを経由して「シリアライズ」契約を確立します。

class Serializer(object): 
    __public__ = None 
    "Must be implemented by implementors" 

    __internal__ = None 
    "Must be implemented by implementors" 

    def to_serializable_dict(self): 
     # do stuff with __public__, __internal__ 
     # ... 

はWSGIの統合とそれをシンプルに保ちます。 "register"、オブジェクトとしてのJSONSerializer、そしてJava/Springのようなものですが、そのようなものは必要ありません。以下は私のパイロン1.0スタイルの解法ですが、私はピラミッドではありません。

def my_controller(self): 
    # ... 

    return to_response(request, response, myobject) 


# elsewhere 
def to_response(req, resp, obj): 
    # this would be more robust, look in 
    # req, resp, catch key errors, whatever. 
    # xxx_serialize are just functions. don't need state 
    serializer = { 
     'application/json':json_serialize, 
     'application/xml':xml_serialize, 
     # ... 
    }[req.headers['content-type']] 

    return serializer(obj) 
+0

すばらしいアドバイス。ありがとうマイケル。 –

関連する問題