如何使用Flask-SQLAlchemy使用csv填充具有外键的模型?

时间:2013-05-10 05:27:31

标签: python csv flask-sqlalchemy

我有2个模型类,如下所示:

class Domain(db.Model):
    __tablename__ = 'domain'
    id = db.Column(db.Integer, primary_key=True)
    domain_name = db.Column(db.String(30), unique=True)
    mailboxes = db.Column(db.Integer, default=0)

    def __init__(self, **kwargs):
        self.__dict__.update(kwargs)

    def __repr__(self):
        return '%s'  % self.domain_name


class EmailAccount(db.Model):
    __tablename__ = 'email_account'
    __table_args__ = (
        db.UniqueConstraint('username', 'domain_id', 
                            name='_uq_username_domain'),{}
    )
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(30))
    domain_id = db.Column(db.Integer, db.ForeignKey('domain.id'))
    domain = db.relationship('Domain', backref=db.backref('emailaccounts',
                            lazy='dynamic'))
    def __init__(self,**kwargs):
        self.__dict__.update(kwargs)

    def __repr__(self):
         return  '%s@%s ' % (self.username, self.domain)

我在示例中仅添加了此处所需的相关属性。我希望通过读取数据的csv文件来使用脚本填充模型。域表的脚本使用Flask-SQLAlchemy运行良好,但emailaccount表的脚本抛出了异常。脚本如下:

#Populate domains from csv
domain_file = "domain.csv"
csv_file = csv.DictReader(open(domain_file, 'rb'), delimiter=',')
for row in csv_file:
    #data type conversion from (csv)string before inserting to table
    for key, value in row.items():
          #some code omitted
        print key, value    
    domain = Domain(**row)
    db.session.add(domain)
    db.session.commit()

#Populate accounts from csv
accounts_file = "accounts.csv"
csv_file = csv.DictReader(open(accounts_file, 'rb'), delimiter=',')

for row in csv_file:
    mdomain_name = ''
    #data type conversion from (csv)string before inserting to table
    for key, value in row.items():
        print key, value
        if key == 'domain':
            mdomain = Domain.query.filter_by(domain_name = value).first()
            mdomain_name = mdomain.domain_name
            mdomain_id = mdomain.id
        if key == 'domain_id':
            value = mdomain_id
    account = EmailAccount(**row)
    db.session.add(account)
    db.session.commit()

抛出的异常是:

  

文件“data.py”,第55行,在db.session.add(帐户)中   文件“... / local / lib / python2.7 / site-packages / sqlalchemy / orm / scoping.py”,第149行,在do中返回getattr(self.registry(),name)(* args,** kwargs )
  文件“... / local / lib / python2.7 / site-packages / sqlalchemy / orm / session.py”,第1397行,添加self._save_or_update_state(state)
  文件“... / local / lib / python2.7 / site-packages / sqlalchemy / orm / session.py”,第1415行,在_save_or_update_state中halt_on = self._contains_state):
  文件“... / local / lib / python2.7 / site-packages / sqlalchemy / orm / mapper.py”,第1986行,cascade_iterator parent_dict,visited_states,halt_on))
  文件“... / local / lib / python2.7 / site-packages / sqlalchemy / orm / properties.py”,第930行,cascade_iterator get_all_pending(state,dict_)
  文件“... / local / lib / python2.7 / site-packages / sqlalchemy / orm / attributes.py”,第761行,在get_all_pending中返回ret = [(instance_state(current),current)] AttributeError:'str'对象没有属性'_sa_instance_state'

PL。恢复data.py脚本中代码的更改,即上传具有Domain类外键的EmailAccount模型数据的脚本。我只想使用Flask-SQLAlchemy。

accounts.csv文件的摘录:

Email Account,legacy_username,password,full_name,quota,is_domain_admin,is_catch_all,disabled_login,disabled_delivery
info@abc.com,,,,104857600,,,,
internal@abc.com,,,Internal,102400000,,,,
kiran.rs@abc.com,,,,102400000,,,, kishorepr,xyz.com,,,,209715200,,,,

1 个答案:

答案 0 :(得分:2)

如果某行包含domain密钥,则会检索域以获取其密钥,但不会使用域ID更新row

然后当你这样做:

account = EmailAccount(**row)

row对象仍然具有与域名关联的密钥domain。由于您的EmailAccount类使用名称domain作为关系,因此db认为它将获得Domain对象,实际上它正在获得string(名称)。这就是您收到错误AttributeError: 'str' object has no attribute '_sa_instance_state'

的原因

更新:这应该有效

for row in csv_file:
    account_values = {}
    for key, value in row.items():
        if key == 'domain':
            mdomain = Domain.query.filter_by(domain_name = value).first()
            account_values['domain'] = mdomain
        else:
            account_values[key] = value
    account = EmailAccount(account_values)
    db.session.add(account)
    db.session.commit()