создайте модель фляги с 4 классами, содержащими соединение 1: M и соединение M: M с участием класса User.

Я новичок в Flask. Я пытаюсь создать фляжное приложение для местной группы сообщества, где они могут добавлять комментарии и организовывать мероприятия или поддержку. Я создал систему входа в систему (используя онлайн-ресурсы) и установил flask-admin, поэтому есть обзор входящих сообщений.

Я хочу ограничить доступ к панели администратора, чтобы только тот, кто является администратором, мог видеть все сообщения/сообщения. Некоторые сообщения могут быть конфиденциальными.

Я подумал, что для этого подойдет базовая аутентификация. Я исследовал модель данных для ролей фляг, чтобы я мог назначить роль администратора и «остальное». (Мне просто нужен один пользователь-администратор), и я пошел дальше и создал то, что я считал разумной моделью, в которой класс пользователя имеет класс 1: M с классом сообщений и класс M: M с классом ролей через класс userroles.


from datetime import datetime
from flaskblog import db, login_manager
from flaskblog import app
from flask_login import UserMixin
from flaskblog import routes
from flask_admin import Admin
from flask_admin.contrib.sqla import ModelView
from sqlalchemy.orm import relationship
admin = Admin(app, name='Dashboard')

@login_manager.user_loader
def load_user(user_id):
return User.query.get(int(user_id))

class UserRoles(db.Model):
__tablename__ = 'user_roles'
id = db.Column(db.Integer(), primary_key=True)
user_id = db.Column(db.Integer(), db.ForeignKey('user.id', ondelete='CASCADE'))
role_id = db.Column(db.Integer(), db.ForeignKey('role.id', ondelete='CASCADE'))


class User(db.Model, UserMixin):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(20), unique=True, nullable=False)
email = db.Column(db.String(120), unique=True, nullable=False)
image_file = db.Column(db.String(20), nullable=False, default='default.jpg')
password = db.Column(db.String(60), nullable=False)

def __repr__(self):
return f"User('{self.username}', '{self.email}', '{self.image_file}')"


class Post(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(100), nullable=False)
date_related = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
date_posted = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
content = db.Column(db.Text, nullable=False)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
user = relationship("User")

def __repr__(self):
return f"Post('{self.title}', '{self.date_posted},', '{self.date_related},')"

class Role(db.Model):
__tablename__ = 'role'
id = db.Column(db.Integer(), primary_key=True)
name = db.Column(db.String(50), unique=True)

admin.add_view(ModelView(User, db.session))
admin.add_view(ModelView(Post, db.session))

Я застрял в течение нескольких дней, пытаясь заставить это работать. Я исследовал множество различных способов заставить его работать, но все время получаю одно и то же сообщение об ошибке. Любые идеи? Я полностью лаю не на то дерево? Когда я захожу в интерфейс командной строки python и использую «модели импорта из flaskblog», это сообщение об ошибке.

sqlalchemy.exc.InvalidRequestError: One or more mappers failed to initialize - can't proceed with initialization of other mappers. Triggering mapper: 'mapped class User->user'. Original exception was: Could not determine join condition between parent/child tables on relationship User.roles - there are no foreign keys linking these tables via secondary table 'user_roles'.  Ensure that referencing columns are associated with a ForeignKey or ForeignKeyConstraint, or specify 'primaryjoin' and 'secondaryjoin' expressions.

person David Harris    schedule 23.05.2020    source источник


Ответы (2)


Хотя это не критично, я предлагаю сделать роли атрибутом пользователей, а не наоборот. Итак, вы бы обновили UserRoles следующим образом:

class UserRoles(db.Model):
  __tablename__ = 'user_roles'
  id = db.Column(db.Integer(), primary_key=True)
  user_id = db.Column(db.Integer(), db.ForeignKey('user.id', ondelete='CASCADE'))
  role_id = db.Column(db.Integer(), db.ForeignKey('role.id', ondelete='CASCADE'))

и пользователями:

class User(db.Model, UserMixin):
  __tablename__ = 'users'
  id = db.Column(db.Integer, primary_key=True)
  username = db.Column(db.String(20), unique=True, nullable=False)
  email = db.Column(db.String(120), unique=True, nullable=False)
  image_file = db.Column(db.String(20), nullable=False, default='default.jpg')
  password = db.Column(db.String(60), nullable=False)
  roles = relationship("UserRoles")

и роль:

class Role(db.Model):
  __tablename__ = 'role'
  id = db.Column(db.Integer(), primary_key=True, db.ForeignKey(User.id))
  name = db.Column(db.String(50), unique=True)

Таким образом, когда вы вызываете объект User, вы можете получить доступ к списку их ролей, вызвав атрибут «roles» и перебирая список.

Я думаю, что следует решить проблему FK not found. Если нет, дайте мне знать, что такое пересмотренная трассировка стека.

person RyanH    schedule 23.05.2020

Спасибо, очень благодарен за быстрый ответ. Я попробовал то, что вы предложили, и я все еще получаю ту же раздражающую ошибку. Мне интересно, не следует ли мне просто создать флаг в пользовательской модели, а затем установить для него значение true, если я хочу, чтобы пользователь имел доступ к панели администратора.

Чтобы было ясно, следующее происходит, когда я набираю из «моделей импорта flaskblog»

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/david/course/project1/overton_playgroup/flaskblog/__init__.py", line 23, in <module>
    from flaskblog import routes
  File "/home/david/course/project1/overton_playgroup/flaskblog/routes.py", line 6, in <module>
    from flaskblog.forms import RegistrationForm, LoginForm, UpdateAccountForm, PostForm
  File "/home/david/course/project1/overton_playgroup/flaskblog/forms.py", line 7, in <module>
    from flaskblog.models import User
  File "/home/david/course/project1/overton_playgroup/flaskblog/models.py", line 64, in <module>
    admin.add_view(ModelView(User, db.session))
  File "/home/david/course/project1/venv_name/lib/python3.6/site-packages/flask_admin/contrib/sqla/view.py", line 330, in __init__
    menu_icon_value=menu_icon_value)
  File "/home/david/course/project1/venv_name/lib/python3.6/site-packages/flask_admin/model/base.py", line 818, in __init__
    self._refresh_cache()
  File "/home/david/course/project1/venv_name/lib/python3.6/site-packages/flask_admin/model/base.py", line 895, in _refresh_cache
    self._list_columns = self.get_list_columns()
  File "/home/david/course/project1/venv_name/lib/python3.6/site-packages/flask_admin/model/base.py", line 1035, in get_list_columns
    only_columns=self.column_list or self.scaffold_list_columns(),
  File "/home/david/course/project1/venv_name/lib/python3.6/site-packages/flask_admin/contrib/sqla/view.py", line 418, in scaffold_list_columns
    for p in self._get_model_iterator():
  File "/home/david/course/project1/venv_name/lib/python3.6/site-packages/flask_admin/contrib/sqla/view.py", line 354, in _get_model_iterator
    return model._sa_class_manager.mapper.iterate_properties
  File "/home/david/course/project1/venv_name/lib/python3.6/site-packages/sqlalchemy/orm/mapper.py", line 2065, in iterate_properties
    configure_mappers()
  File "/home/david/course/project1/venv_name/lib/python3.6/site-packages/sqlalchemy/orm/mapper.py", line 3251, in configure_mappers
    raise e
sqlalchemy.exc.InvalidRequestError: One or more mappers failed to initialize - can't proceed with initialization of other mappers. Triggering mapper: 'mapped class User->user'. Original exception was: Could not determine join condition between parent/child tables on relationship User.roles - there are no foreign keys linking these tables via secondary table 'user_roles'.  Ensure that referencing columns are associated with a ForeignKey or ForeignKeyConstraint, or specify 'primaryjoin' and 'secondaryjoin' expressions.
person David Harris    schedule 24.05.2020