1

典型的なデータ階層を持つ POS アプリケーションを作成しています: Company->branches->Sales->SaleData、これはモデル定義です (User モデルは既に準備されており、flask-login 互換モデルとして機能していることに注意してください) :

from flask_sqlalchemy import SQLAlchemy
from main import db
from collections import OrderedDict


class Users(db.Model,object):                                                                                                                                                                                                     
    '''                                                                                                                                                                                                                           
    Adding object to trun sqlalchemy into json object                                                                                                                                                                             
    '''                                                                                                                                                                                                                           
    id = db.Column(db.Integer, primary_key=True)                                                                                                                                                                                  
    username = db.Column(db.String(60), unique=True)                                                                                                                                                                              
    firstname = db.Column(db.String(20))                                                                                                                                                                                          
    lastname = db.Column(db.String(20))                                                                                                                                                                                           
    password = db.Column(db.String)                                                                                                                                                                                               
    email = db.Column(db.String(100), unique=True)                                                                                                                                                                                
    role = db.Column(db.String(20))                                                                                                                                                                                               
    active = db.Column(db.Boolean)                                                                                                                                                                                                
    company_id = db.Column(db.Integer, db.ForeignKey('companies.id'))                                                                                                                                                             

    def __init__(self, username=None, password=None, email=None, firstname=None, lastname=None):                                                                                                                                  
        self.username = username                                                                                                                                                                                                  
        self.email = email                                                                                                                                                                                                        
        self.firstname = firstname                                                                                                                                                                                                
        self.lastname = lastname                                                                                                                                                                                                  
        self.password = password                                                                                                                                                                                                  
        self.active = True                                                                                                                                                                                                        
        self.role = 'Admin'                                                                                                                                                                                                       

    def is_authenticated(self):                                                                                                                                                                                                   
        return True                                                                                                                                                                                                               

    def is_active(self):                                                                                                                                                                                                          
        return self.active                                                                                                                                                                                                        

    def is_anonymous(self):                                                                                                                                                                                                       
        return False                                                                                                                                                                                                              

    def get_id(self):                                                                                                                                                                                                             
        return unicode(self.id)                                                                                                                                                                                                   

    def _asdict(self):                                                                                                                                                                                                            
        '''                                                                                                                                                                                                                       
        Thanks to http://stackoverflow.com/questions/7102754/jsonify-a-sqlalchemy-result-set-in-flask                                                                                                                             
    '''                                                                                                                                                                                                                       
        result = OrderedDict()                                                                                                                                                                                                    
        for key in self.__mapper__.c.keys():                                                                                                                                                                                      
            result[key] = getattr(self, key)                                                                                                                                                                                      
        return result 


class Companies(db.Model):                                                                                                                                                                                                        
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(100), unique=True)                                                                                                                                                                                 
    address = db.Column(db.String)                                                                                                                                                                                                
    users = db.relation('Users', backref=db.backref('users'))                                                                                                                                                                     
    token = db.Column(db.String) #for identification of client                                                                                                                                                                    
    branches = db.relationship("Branches")                                                                                                                                                                                        

    def __init__(self, name=None, address=None, token=None):                                                                                                                                                                      
        self.name = name                                                                                                                                                                                                          
        self.address = address                                                                                                                                                                                                    
        self.token = token             

class Branches(db.Model):                                                                                                                                                                                                         
    id = db.Column(db.Integer, primary_key=True)                                                                                                                                                                                  
    name = db.Column(db.String(255), unique=True)                                                                                                                                                                                 
    address = db.Column(db.String)                                                                                                                                                                                                
    user_id = db.Column(db.Integer, db.ForeignKey('users.id'))                                                                                                                                                                    
    token = db.Column(db.String) #for identification of client                                                                                                                                                                    
    company_id = db.Column(db.Integer, db.ForeignKey('companies.id'))                                                                        
    sales = db.relation('Sales',                                                                                                                                                                                                  
                    backref=db.backref('sales', lazy='dynamic'),                                                                                                                                                              
                    cascade="all, delete-orphan",                                                                                                                                                                             
                    lazy='dynamic',                                                                                                                                                                                           
                    passive_deletes=True)                                                                                                                                                                                     

    def __init__(self, name=None, address=None, token=None, user_id=None):                                                                                                                                                        
        self.name = name                                                                                                                                                                                                          
        self.address = address                                                                                                                                                                                                    
        self.token = token                                                                                                                                                                                                        
        self.user_id = user_id                                                                                                                                                                                                    

class Sales(db.Model):                                                                                                                                                                                                            
    id = db.Column(db.Integer, primary_key=True)                                                                                                                                                                                  
    day = db.Column(db.Date)                                                                                                                                                                                                      
    branch_id = db.Column(db.Integer, db.ForeignKey('branches.id'))                                                                                                                                                               
    data = db.relationship("SaleData")                                                                                                                                                                                            

    def __init__(self, day=None):                                                                                                                                                                                                 
        self.day = day                                                                                                                                                                                                            

class SaleData(db.Model):                                                                                                                                                                                                         
    id = db.Column(db.Integer, primary_key=True)                                                                                                                                                                                  
    sale_id = db.Column(db.Integer, db.ForeignKey('sales.id'))                                                                                                                                                                    
    cash_start_of_day = db.Column(db.Integer)                                                                                                                                                                                     
    cash_end_of_day = db.Column(db.Integer)                                                                                                                                                                                       
    income = db.Column(db.Integer) # which is end - start                                                                                                                                                                         

    def __init__(self, cash_start_of_day = None, cash_end_of_day = None, income = None):                                                                                                                                          
        self.cash_start_of_day = cash_start_of_day                                                                                                                                                                                
        self.cash_end_of_day = cash_end_of_day                                                                                                                                                                                    
        self.income = income                                                                           

ここで、営業データをブランチに追加しようとしても、これを行うと発生しませんでした:

 branch1 = company1.branches.filter().all()

私はこれを行うことができます:

 branch1 = company1.branches[0]

その[]演算子を使用していない場合、次のエラー メッセージが表示されます: AttributeError: 'InstrumentedList' object has no attribute'. 私はすでにSOで別の回答を参照していますlazy.backref定義のことと関係があるので、現在のモデルをすでに変更しています

しかし、ここで何かが欠けているようです..手がかりはありますか? ありがとう!

EDIT 1:ユニットテストが追加され、ユーザーモデルも追加されました

すでに Mark Hildreth から簡潔な回答を得ており、非常に助かっています! そのため、このモデルの完全な単体テストをここに置きます。SQLAlchemy の最初のステップで初心者に役立つと確信しています。だから、ここに行きます:

import unittest
from main import db
import models
import md5
import helper


class DbTest(unittest.TestCase):                                                                                                                                                                                                  
    def setUp(self):                                                                                                                                                                                                              
        db.drop_all()                                                                                                                                                                                                             
        db.create_all()                                                                                                                                                                                                           

    def test_user_and_company(self):                                                                                                                                                                                              
        """admin of a company"""                                                                                                                                                                                                  

        user1 = models.Users('eko', helper.hash_pass('rahasia'), 'swdev.bali@gmail.com')                                                                                                                                          
        db.session.add(user1)                                                                                                                                                                                                     
        db.session.commit()                                                                                                                                                                                                       

        """the company"""                                                                                                                                                                                                         
        company1 = models.Companies('CDI','Glagah Kidul', 'empty')                                                                                                                                                                
        db.session.add(company1)                                                                                                                                                                                                  
        company1.users.append(user1)                                                                                                                                                                                              
        db.session.commit()                                                                                                                                                                                                       
        assert company1.users[0].id == user1.id                                                                                                                                                                                   

        """branches"""                                                                                                                                                                                                            
        company1.branches.append(models.Branches(name='Kopjar',address='Penjara Malaysia', token='empty token', user_id=user1.id))                                                                                                
        company1.branches.append(models.Branches(name='Selangor',address='Koperasi Selangor', token='empty token',  user_id=user1.id))                                                                                            
        db.session.commit()                                                                                                                                                                                                       

        '''sales'''
        branch1 = company1.branches.filter(models.Branches.name=='Kopjar').first()
        assert branch1.name=='Kopjar' and branch1.company_id == company1.id


        sale = models.Sales(day='2013-02-02')
        sale.data.append(models.SaleData(cash_start_of_day = 0, cash_end_of_day = 500000, income = 500000))
        branch1.sales.append(sale)
        db.session.commit()

        assert sale.id is not None


    if __name__ == '__main__':                                                                                                                                                                                                        
        unittest.main()   

このモデルまたは単体テストには悪い習慣があるかもしれません。それを指摘していただければ幸いです:)

ありがとう!

4

1 に答える 1

6

ドキュメントの「コレクションの構成」セクションを確認することをお勧めします。SQLAlchemy でリレーションシップがどのように処理されるかを扱うには、いくつかの主な組み込みの方法があり、ドキュメントのそのセクションではさまざまな方法が示されています。

デフォルトでは、次の場合...

class Companies(db.Model):                                                                                                                                                                                                        
    ...
    branches = db.relationship("Branches")                                                                                                                                                                                        
    ...

Company をロードすると、すべてのブランチがロードされます (デフォルトでは、リストにロードされます)。したがって、会社を取得した後、company.branchesは支店のリストを返します。リストなので、filter()やなどの機能はありませんall()。ブランチの大きなリストを想定していない場合は、クエリ オブジェクトとしてではなくリストとしてブランチを使用する方が理にかなっている可能性があるため、これをお勧めします。これをリストとして持つと、次のようなことができます...

company = session.query(Companies).first()
my_branch = Branches(...)
company.branches.append(my_branch)
session.commit()

これにより、特にセッションに追加する必要なく、新しいBranchesオブジェクトが適切に作成されます (これはかなり気の利いたことだと思います)。

補足として、この魔法を実行するために、SQLAlchemy は実際にはリストのように機能するオブジェクト型に設定されますが、実際には追加の SQLAlchemy 固有の情報があるため、type(company.branches)を取得することはできません。ご想像のとおり、このオブジェクト タイプは、エラー メッセージが表示されている "InstrumentedList" です。<type 'list'>branches

ただし、これを行いたくない場合があります。具体的には、これには一度にすべてのブランチをロードする必要があり、数千のブランチがあるため、一度にいくつかロードしたい場合があります (会社には数千のブランチがあります。官僚機構を想像してみてください...)。

したがって、ドキュメントが言うように、関係を変更します...

大規模なコレクションの管理を可能にする重要な機能は、いわゆる「動的」関係です。これは、アクセス時にコレクションの代わりに Query オブジェクトを返す relationship() のオプションの形式です。filter() 基準は、明示的にまたは配列スライスを介して、制限とオフセットと同様に適用できます。

のようなことができるようになりたい場合、これがあなたのやりたいことのようcompany.branches.filter(...).all()です。これを行うにlazyは、関係の属性を「動的」にすることにより、ドキュメントが示すように行います...

class Companies(db.Model):                                                                                                                                                                                                        
    ...
    branches = db.relationship("Branches", lazy='dynamic')                                                                                                                                                                                        
    ...

支店 - >販売関係についてはすでにこれを行っているようですが、会社 - >支店関係については行っていないため、エラーが発生しています。

于 2013-10-07T19:40:11.153 に答える