2013-05-10 1 views
4

У меня есть 2 классов модели, как показано ниже:Как заполнить модель с внешним ключом с помощью csv с помощью Flask-SQLAlchemy?

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 '%[email protected]%s ' % (self.username, self.domain) 

Я добавил только соответствующие атрибуты, необходимые здесь в примере. Я хочу заполнить модель с помощью скрипта, прочитав файл csv для данных. Скрипт для таблицы доменов хорошо работает с использованием Flask-SQLAlchemy, но скрипт для таблицы электронной почты исключает исключение. Сценарий выглядит следующим образом:

#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() 

Исключение брошено является:

File "data.py", line 55, in db.session.add(account)
File ".../local/lib/python2.7/site-packages/sqlalchemy/orm/scoping.py", line 149, in do return getattr(self.registry(), name)(*args, **kwargs)
File ".../local/lib/python2.7/site-packages/sqlalchemy/orm/session.py", line 1397, in add self._save_or_update_state(state)
File ".../local/lib/python2.7/site-packages/sqlalchemy/orm/session.py", line 1415, in _save_or_update_state halt_on=self._contains_state):
File ".../local/lib/python2.7/site-packages/sqlalchemy/orm/mapper.py", line 1986, in cascade_iterator parent_dict, visited_states, halt_on))
File ".../local/lib/python2.7/site-packages/sqlalchemy/orm/properties.py", line 930, in cascade_iterator get_all_pending(state, dict_)
File ".../local/lib/python2.7/site-packages/sqlalchemy/orm/attributes.py", line 761, in get_all_pending ret = [(instance_state(current), current)] AttributeError: 'str' object has no attribute '_sa_instance_state'

Pl. вернитесь с изменениями кода в скрипте для файла data.py i.e для загрузки данных для модели EmailAccount, которая имеет внешний ключ класса Domain. Я хочу использовать только Flask-SQLAlchemy.

Экстракт accounts.csv файла:

Email Account,legacy_username,password,full_name,quota,is_domain_admin,is_catch_all,disabled_login,disabled_delivery 
[email protected],,,,104857600,,,, 
[email protected],,,Internal,102400000,,,, 
[email protected],,,,102400000,,,, kishorepr,xyz.com,,,,209715200,,,, 

ответ

2

Когда строка содержит ключ domain, вы получите домен, чтобы получить свой ключ, но не обновить ваш row с доменным идентификатором.

Затем, когда вы делаете:

account = EmailAccount(**row) 

row объекта все еще имеет ключ domain, связанные с доменным именем. Поскольку ваш класс EmailAccount использует имя domain для отношений, db считает, что он получит объект Domain, когда на самом деле он получает string (имя). Вот почему вы получаете ошибку AttributeError: 'str' object has no attribute '_sa_instance_state'.

Update: это должно работать

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() 
+0

@http: //stackoverflow.com/users/1193366/morphyn Спасибо за быстрый ответ. Можете ли вы сказать мне, что изменения кода исправить. Заранее спасибо – user956424

+0

Не могли бы вы вывести выписку из csv-файла ваших учетных записей? –

+0

http://stackoverflow.com/users/1193366/morphyn вставил выдержку из csv выше. – user956424