Изменить отношение «многие ко многим» в Flask -Alchemy с помощью WTForms - PullRequest
1 голос
/ 16 февраля 2020

Я испытываю трудности при обработке отношения «многие ко многим» (здесь: пользователи и группы) в форме Flask. Моя структура базы данных (упрощенная) выглядит следующим образом:

association_user_group = db.Table(
    'association_user_group',
    db.Column('user_id', db.Integer, db.ForeignKey('user.id')),
    db.Column('group_id', db.Integer, db.ForeignKey('group.id'))
)

class Group(db.Model):
    __tablename__ = 'group'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(32))
    users = db.relationship(
        'User',
        secondary=association_user_group,
        backref=db.backref('groups', lazy='dynamic'))

class User(UserMixin, db.Model):
    __tablename__ = 'user'
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(64), index=True, unique=True)

    @property
    def group_ids(self):
        return [u.id for u in self.groups]

Для обработки формы, позволяющей администратору редактировать пользователей, у меня есть:

class MultiCheckboxField(SelectMultipleField):
    widget = widgets.ListWidget(prefix_label=False)
    option_widget = widgets.CheckboxInput()

class UserEditForm(FlaskForm):
    username = StringField('Username', validators=[DataRequired()])
    password = PasswordField('Password')
    groups = MultiCheckboxField('Groups', coerce=int)
    submit = SubmitField('Apply changes')

и следующий маршрут:

@bp.route('/user_edit/<int:id>', methods=['GET', 'POST'])
@login_required
@admin_required
def user_edit(id):
    user = User.query.get(id)
    if request.method == 'GET':
        form = UserEditForm(obj=user)
        form.groups.data = [grp.id for grp in user.groups]
    else:
        form = UserEditForm(request.form)
    form.groups.choices = [(grp.id, grp.name) for grp in Group.query.all()]

    if form.validate_on_submit():
        #form.populate_obj(user) <-- does not work
        user.username = form.data.username
        if form.password.data != '':
            user.set_password(form.password.data)
        # how do I update the 'groups'?
        db.session.add(user)
        db.session.commit()
        return "Data={}".format(form.data)

База данных и форма работают, но я не могу скопировать содержимое формы groups обратно в базу данных. В идеале я мог бы «заполнить» содержимое формы до объекта User, но это не удалось из-за groups (и я думаю, что это также может произойти сбой с пустым полем пароля, если нет изменений запросил).

Затем я попытался удалить все groups из user и заново добавить те, которые мне нужны, но не нашел разумного способа добиться этого. Я могу добавить членство в группе с user.groups.append(grp), где grp - соответствующий объект базы данных. Я также могу remove членство в группе таким же образом, но с учетом идентификаторов групп это будет означать циклический просмотр всех идентификаторов групп, получение объекта группы и затем использование этого объекта для вызова метода remove, который выглядит слишком сложный.

В целом, я подозреваю, что я пытаюсь реализовать все это слишком неловко ...

...