简体   繁体   中英

SQLAlchemy, appending association objects with extra fields in association proxy relationship

I have a many-to-many relationship between objects User and Groups . I have an association object called Attends which contains the extra field role . I want to reduce the verbosity of the association object relationship by using association proxy. Unfortunately, the documentation was not very clear on how to explicitly add the extra field role when I am appending a new user to a group.

Group class

class Group(db.Model):
    __tablename__ = 'group'

    gid = db.Column(db.Integer, primary_key=True, autoincrement=True)
    oid = db.Column(db.Integer, db.ForeignKey('organization.oid'), nullable=False)
    start_time= db.Column(db.DateTime, nullable=False)
    end_time = db.Column(db.DateTime, db.CheckConstraint('end_time > start_time'), nullable=False)
    location = db.Column(db.String, nullable=False)
    description = db.Column(db.Text)

    organization = db.relationship('Organization', back_populates='groups')

    #many-to-many db.relationship with users
    registered_users = association_proxy('user_groups', 'user')

    #one to many db.relationship with tags
    tags = db.relationship('Tag', back_populates='group')

    def add_user(self, user, role):
        if not self.has_user(user):
            self.registered_users.append(Attend(user, self, role)) <-- error 
        else:
            raise ValueError('user %s already exists', user)

Attend class

class Attend(db.Model):
    __tablename__ = 'attend'
    uid = db.Column(db.Integer, db.ForeignKey('user.uid'), primary_key=True)
    gid = db.Column(db.Integer, db.ForeignKey('group.gid'), primary_key=True)
    user_role = db.Column(db.Enum(*GroupRoles.roles, name='role'))

    group = db.relationship('Group', 
        backref=db.backref('user_groups', cascade='all, delete-orphan'))

    user = db.relationship('User')

    def __init__(self, user, group, role):
        self.user = user
        self.group = group
        self.user_role = role

I receive the following error when executing add_user method:

        def _create(self, value):
>       return self.creator(value)
E       TypeError: __init__() missing 2 required positional arguments: 'group' and 'role'

user_groups should be aa list of Attend objects (ie a relationship to Attend ), and registered_users should be a list of User objects. When you append to registered_users , you need to let the association_proxy know how to construct the corresponding Attend object in user_groups ( docs ):

registered_users = association_proxy('user_groups', 'user',
                                     creator=lambda u: Attend(user=u, user_role='some_default_role'))

Note: SQLAlchemy doesn't know what role is, so you'll need to provide a default value. It does know what the group should be, by virtue of the user_groups relationship being on Group . If you want to be able to do add_user(user, role) , you can simply append directly to the relationship yourself:

def add_user(self, user, role):
    if not self.has_user(user):
        self.user_groups.append(Attend(user=user, user_role=role))
    else:
        raise ValueError('user %s already exists', user)

Note that this assumes you change your Attend class to use the default constructor.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM