Я испытываю трудности при обработке отношения «многие ко многим» (здесь: пользователи и группы) в форме 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
, который выглядит слишком сложный.
В целом, я подозреваю, что я пытаюсь реализовать все это слишком неловко ...