2016-12-19 3 views
0

SQLAlchemy, несомненно, очень мощный, но документация подразумевает, что предполагает много предшествующих знаний и по теме отношений, смешивает между backref и новостями -предоставляемые методы back_populates(), которые я нахожу очень запутанными.SQLAlchemy: __init __() принимает 1 позиционный аргумент, но 2 дано (многие из многих)

Следующая модельная диаграмма представляет собой точное зеркало руководства в документации, касающейся Association Objects for many-to-many relationships. Вы можете видеть, что комментарии по-прежнему идентичны комментариям в оригинальной статье, и я только изменил фактический код.

class MatchTeams(db.Model): 
    match_id = db.Column(db.String, db.ForeignKey('match.id'), primary_key=True) 
    team_id = db.Column(db.String, db.ForeignKey('team.id'), primary_key=True) 
    team_score = db.Column(db.Integer, nullable="True") 

    # bidirectional attribute/collection of "user"/"user_keywords" 
    match = db.relationship("Match", 
          backref=db.backref("match_teams", 
              cascade="all, delete-orphan") 
          ) 
    # reference to the "Keyword" object 
    team = db.relationship("Team") 


class Match(db.Model): 
    id = db.Column(db.String, primary_key=True) 

    # Many side of many to one with Round 
    round_id = db.Column(db.Integer, ForeignKey('round.id')) 
    round = db.relationship("Round", back_populates="matches") 
    # Start of M2M 

    # association proxy of "match_teams" collection 
    # to "team" attribute 
    teams = association_proxy('match_teams', 'team') 

    def __repr__(self): 
     return '<Match: %r>' % (self.id) 


class Team(db.Model): 
    id = db.Column(db.Integer, primary_key=True) 
    name = db.Column(db.String, nullable=False) 
    goals_for = db.Column(db.Integer) 
    goals_against = db.Column(db.Integer) 
    wins = db.Column(db.Integer) 
    losses = db.Column(db.Integer) 
    points = db.Column(db.Integer) 
    matches_played = db.Column(db.Integer) 

    def __repr__(self): 
     return '<Team %r with ID: %r>' % (self.name, self.id) 

Но этот фрагмент, который должен связать экземпляр команды find_liverpool с экземпляром матча find_match (оба стереотипных объектов), не работает:

find_liverpool = Team.query.filter(Team.id==1).first() 
print(find_liverpool) 
find_match = Match.query.filter(Match.id=="123").first() 
print(find_match) 

find_match.teams.append(find_liverpool) 

И выводит следующее:

Traceback (most recent call last): 
File "/REDACT/temp.py", line 12, in <module> 
find_match.teams.append(find_liverpool) 
File "/REDACT/lib/python3.4/site-packages/sqlalchemy/ext/associationproxy.py", line 609, in append 
item = self._create(value) 
File "/REDACT/lib/python3.4/site-packages/sqlalchemy/ext/associationproxy.py", line 532, in _create 
return self.creator(value) 
TypeError: __init__() takes 1 positional argument but 2 were given  
<Team 'Liverpool' with ID: 1> 
<Match: '123'> 
+0

Вы будете необходимо предоставить дополнительную информацию. Что порождает эту ошибку? Это не может быть фрагмент, который вы опубликовали, потому что если первая строка подняла ошибку, то 'find_liverpool' не будет заполнен, но это явно так. Пожалуйста, покажите полный код и трассировку. –

+0

@ DanielRoseman код, который я опубликовал, - это то, что порождает ошибку. Я добавил полную трассу. find_liverpool заполняется до 'TypeError', но по какой-то причине после него выводятся отпечатки. – zerohedge

ответ

4

вызов append пытается create a new instance из MatchTeams, как можно видеть е с документацией. Это также упоминается в разделе "Упрощение ассоциации объектов", что вы связаны с:

Где выше, каждая .keywords.append() операция эквивалентна:

>>> user.user_keywords.append(UserKeyword(Keyword('its_heavy')))

Следовательно ваш

find_match.teams.append(find_liverpool) 

эквивалентен

find_match.match_teams.append(MatchTeams(find_liverpool)) 

Поскольку MatchTeams не имеет четко определены __init__, он с помощью _default_constructor() в constructor (если вы не переопределен его), который принимает только именованные аргументы в дополнении к self, единственному позиционному аргументу.

Чтобы исправить это или передать creator фабрику вашей ассоциации прокси:

class Match(db.Model): 

    teams = association_proxy('match_teams', 'team', 
           creator=lambda team: MatchTeams(team=team)) 

или определить __init__ на MatchTeams, чтобы удовлетворить ваши потребности, например:

class MatchTeams(db.Model): 

    # Accepts as positional arguments as well 
    def __init__(self, team=None, match=None): 
     self.team = team 
     self.match = match 

или создать объект ассоциации явно :

db.session.add(MatchTeams(match=find_match, team=find_liverpool)) 
# etc.