Как мне переписать это на что-то более сухое и удобное в обслуживании?
риложение для фляги сосредоточено вокруг модификации моделей на основе SQLAlchemy. Поэтому я считаю, что flask-admin отличный плагин, потому что он отображает мои модели SQLA на формы с представлениями, уже определенными с настраиваемым интерфейсом, который опробован и протестирован.
Я понимаю, что Flask-admin предназначен для плагинов дляадминистраторы управление данными своего сайта. Однако я не понимаю, почему я не могу использовать FA в качестве основы для своих пользователей, чтобы CRUD их данные.
Для этого я написал следующее:
class AuthorizationRequiredView(BaseView):
def get_roles(self):
raise NotImplemented("Override AuthorizationRequiredView.get_roles not set.")
def is_accessible(self):
if not is_authenticated():
return False
if not current_user.has_role(*self.get_roles()):
return False
return True
def inaccessible_callback(self, name, **kwargs):
if not is_authenticated():
return current_app.user_manager.unauthenticated_view_function()
if not current_user.has_role(*self.get_roles()):
return current_app.user_manager.unauthorized_view_function()
class InstructionModelView(DefaultModelView, AuthorizationRequiredView):
def get_roles(self):
return ["admin", "member"]
def get_query(self):
"""Jails the user to only see their instructions.
"""
base = super(InstructionModelView, self).get_query()
if current_user.has_role('admin'):
return base
else:
return base.filter(Instruction.user_id == current_user.id)
@expose('/edit/', methods=('GET', 'POST'))
def edit_view(self):
if not current_user.has_role('admin'):
instruction_id = request.args.get('id', None)
if instruction_id:
m = self.get_one(instruction_id)
if m.user_id != current_user.id:
return current_app.user_manager.unauthorized_view_function()
return super(InstructionModelView, self).edit_view()
@expose('/delete/', methods=('POST',))
def delete_view(self):
return_url = get_redirect_target() or self.get_url('.index_view')
if not self.can_delete:
return redirect(return_url)
form = self.delete_form()
if self.validate_form(form):
# id is InputRequired()
id = form.id.data
model = self.get_one(id)
if model is None:
flash(gettext('Record does not exist.'), 'error')
return redirect(return_url)
# message is flashed from within delete_model if it fails
if self.delete_model(model):
if not current_user.has_role('admin') \
and model.user_id != current_user.id:
# Denial: NOT admin AND NOT user_id match
return current_app.user_manager.unauthorized_view_function()
flash(gettext('Record was successfully deleted.'), 'success')
return redirect(return_url)
else:
flash_errors(form, message='Failed to delete record. %(error)s')
return redirect(return_url)
Примечание: я использую Flask-User, который построен поверх Flask-Login.
Код выше работает. Тем не менее, трудно абстрагироваться как базовый класс для других моделей, в которых я хотел бы реализовать контроль доступа для операций CRUD и представлений Индекс / Правка / Детали / Удалить.
В основном проблемы:
метод API,is_accessible
, не предоставляет первичный ключ модели. Этот ключ необходим, потому что почти во всех случаях отношения между пользователями и объектами почти всегда хранятся через отношения или непосредственно в таблице модели (то есть, имея user_id в таблице модели).
некоторые взгляды, такие какdelete_view
, не предоставляйте идентификатор экземпляра, который можно легко получить. Вdelete_view
Мне пришлось скопировать всю функцию, чтобы добавить еще одну строку, чтобы проверить, принадлежит ли она нужному пользователю.
Конечно, кто-то думал об этих проблемах.
Как мне переписать это на что-то более сухое и удобное в обслуживании?