Python 为了避免错误消息,SQLAlchemy的正确模型定义是什么:AttributeError:';仪表化列表';对象没有属性';?

Python 为了避免错误消息,SQLAlchemy的正确模型定义是什么:AttributeError:';仪表化列表';对象没有属性';?,python,sqlalchemy,flask,flask-login,Python,Sqlalchemy,Flask,Flask Login,我正在创建一个具有典型数据层次结构的销售点应用程序: 公司->分支机构->销售->销售数据,这是模型定义(注意,用户模型已经准备好并作为一个兼容的模型工作): 现在,如果我尝试向分支机构添加销售数据,如果我这样做,则不会发生: branch1 = company1.branches.filter().all() branch1 = company1.branches[0] 我能做到这一点: branch1 = company1.branches.filter().all() bra

我正在创建一个具有典型数据层次结构的销售点应用程序: 公司->分支机构->销售->销售数据,这是模型定义(注意,用户模型已经准备好并作为一个兼容的模型工作):

现在,如果我尝试向分支机构添加销售数据,如果我这样做,则不会发生:

 branch1 = company1.branches.filter().all()
 branch1 = company1.branches[0]
我能做到这一点:

 branch1 = company1.branches.filter().all()
 branch1 = company1.branches[0]
如果不使用该
[]
运算符,我会收到错误消息:AttributeError:“InstrumentedList”对象没有属性。我已经在这里浏览了另一个答案,它与backref定义中的
惰性
有关,所以我已经修改了我当前的模型

但是我好像错过了什么。。有线索吗? 谢谢

编辑1:添加单元测试和用户模型

我已经从马克·希尔德雷思那里得到了一个简洁的答案,这为我节省了很多!因此,我将在这里对这个模型进行完整的单元测试。我相信这将帮助新手在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()   
在这个模型或单元测试中可能有不好的做法,如果您指出这一点,我将非常高兴:)


谢谢

您可能希望查看文档的这一部分。有几种主要的、内置的方法来处理SQLAlchemy中如何处理关系,文档的这一部分展示了各种方法

默认情况下,当您有

class Companies(db.Model):                                                                                                                                                                                                        
    ...
    branches = db.relationship("Branches")                                                                                                                                                                                        
    ...
加载公司将加载中的所有分支机构(默认情况下,它将它们加载到列表中)。因此,在检索公司后,
company.branches
会向您返回分支机构列表。因为它是一个列表,所以它没有诸如
filter()
all()
之类的函数。如果您不希望看到大量分支列表,那么这可能是首选,因为将分支用作列表而不是查询对象可能更有意义。将此作为一个列表允许您执行以下操作

company = session.query(Companies).first()
my_branch = Branches(...)
company.branches.append(my_branch)
session.commit()
这将正确地创建新的
分支
对象,而无需将其专门添加到会话中(我认为这非常漂亮)

作为旁注,如果您要执行
类型(company.branchs)
,您将不会得到
,因为为了实现这一魔法,SQLAlchemy实际上会将
分支
设置为一个类似于列表的对象类型,但实际上具有额外的SQLAlchemy特定信息。如果您没有猜到的话,这个对象类型就是您得到错误消息的“InstrumentedList”

但是,您可能不想这样做;具体来说,这要求您一次加载所有分支机构,您可能一次只想加载几个分支机构,因为您有数千个分支机构(一家公司中有数千个分支机构,想象一下官僚机构……)

所以,你改变关系

支持管理大型集合的一个关键特性是 所谓的“动态”关系。这是一种可选的 relationship(),它返回一个查询对象来代替集合 访问时。可以应用filter()标准以及限制和 偏移量,无论是显式偏移还是通过数组切片偏移:

如果您希望能够执行诸如
company.branchs.filter(…).all()之类的操作,那么这就是您希望执行的操作。要做到这一点,您可以按照文档显示的那样,将关系的
属性设置为lazy
“dynamic”


看起来您已经为“分支机构->销售”关系执行了此操作,但没有为“公司->分支机构”关系执行此操作,这就是导致错误的原因。

您可能希望查看文档的部分。有几种主要的、内置的方法来处理SQLAlchemy中如何处理关系,文档的这一部分展示了各种方法

默认情况下,当您有

class Companies(db.Model):                                                                                                                                                                                                        
    ...
    branches = db.relationship("Branches")                                                                                                                                                                                        
    ...
加载公司将加载中的所有分支机构(默认情况下,它将它们加载到列表中)。因此,在检索公司后,
company.branches
会向您返回分支机构列表。因为它是一个列表,所以它没有诸如
filter()
all()
之类的函数。如果您不希望看到大量分支列表,那么这可能是首选,因为将分支用作列表而不是查询对象可能更有意义。将此作为一个列表允许您执行以下操作

company = session.query(Companies).first()
my_branch = Branches(...)
company.branches.append(my_branch)
session.commit()
这将正确地创建新的
分支
对象,而无需将其专门添加到会话中(我认为这非常漂亮)

作为旁注,如果您要执行
类型(company.branchs)
,您将不会得到
,因为为了实现这一魔法,SQLAlchemy实际上会将
分支
设置为一个类似于列表的对象类型,但实际上具有额外的SQLAlchemy特定信息。如果您没有猜到的话,这个对象类型就是您得到错误消息的“InstrumentedList”

但是,您可能不想这样做;具体来说,这要求您一次加载所有分支机构,您可能一次只想加载几个分支机构,因为您有数千个分支机构(一家公司中有数千个分支机构,想象一下官僚机构……)

所以,你改变关系

支持管理大型集合的一个关键特性是 所谓的“动态”关系。这是一种可选的 relationship(),它返回一个查询对象来代替集合 访问时。可以应用filter()标准以及限制和 偏移量,无论是显式偏移还是通过数组切片偏移:

如果您希望能够执行诸如
company.branchs.filter(…).all()之类的操作,那么这就是您希望执行的操作。要做到这一点,您可以按照文档显示的那样,通过使
la