AttributeError: module 'app.models.PostModel' has no attribute '_sa_class_manager' - python

I was trying to add flask-admin to my application. I am getting the following error
Traceback (most recent call last):
File "/run/media/sanifss/4264239664238C2B/Projects/Personal/Portfolio/run.py", line 3, in <module>
app = create_app()
File "/run/media/sanifss/4264239664238C2B/Projects/Personal/Portfolio/app/__init__.py", line 71, in create_app
admin.add_view(ModelView(PostModel, db.session))
File "/home/sanifss/.local/share/virtualenvs/Portfolio-UVOeSvIO/lib/python3.9/site-packages/flask_admin/contrib/sqla/view.py", line 327, in __init__
super(ModelView, self).__init__(model, name, category, endpoint, url, static_folder,
File "/home/sanifss/.local/share/virtualenvs/Portfolio-UVOeSvIO/lib/python3.9/site-packages/flask_admin/model/base.py", line 818, in __init__
self._refresh_cache()
File "/home/sanifss/.local/share/virtualenvs/Portfolio-UVOeSvIO/lib/python3.9/site-packages/flask_admin/model/base.py", line 895, in _refresh_cache
self._list_columns = self.get_list_columns()
File "/home/sanifss/.local/share/virtualenvs/Portfolio-UVOeSvIO/lib/python3.9/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/sanifss/.local/share/virtualenvs/Portfolio-UVOeSvIO/lib/python3.9/site-packages/flask_admin/contrib/sqla/view.py", line 418, in scaffold_list_columns
for p in self._get_model_iterator():
File "/home/sanifss/.local/share/virtualenvs/Portfolio-UVOeSvIO/lib/python3.9/site-packages/flask_admin/contrib/sqla/view.py", line 354, in _get_model_iterator
return model._sa_class_manager.mapper.iterate_properties
AttributeError: module 'app.models.PostModel' has no attribute '_sa_class_manager'
I think it could be some dependency issue between SQLAlchemy and Flask-Admin. But cannot figure out what exactly is going wrong and how to fix.
My PostModel
# src/models/PostModel.py
import datetime
from marshmallow import Schema, fields
from slugify import slugify
from . import db
class PostModel(db.Model):
"""
Post Model
"""
__tablename__ = 'posts'
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(128), nullable=False, unique=True)
slug = db.Column(db.String(128), nullable=False)
contents = db.Column(db.Text, nullable=False)
owner_id = db.Column(
db.Integer,
db.ForeignKey('users.id'),
nullable=False)
created_at = db.Column(db.DateTime)
modified_at = db.Column(db.DateTime)
def __init__(self, data):
self.title = data.get('title')
self.slug = slugify(data.get('title'))
self.contents = data.get('contents')
self.owner_id = data.get('owner_id')
self.created_at = datetime.datetime.utcnow()
self.modified_at = datetime.datetime.utcnow()
def save(self):
db.session.add(self)
db.session.commit()
def update(self, data):
for key, item in data.items():
setattr(self, key, item)
self.modified_at = datetime.datetime.utcnow()
db.session.commit()
def delete(self):
db.session.delete(self)
db.session.commit()
#staticmethod
def get_all_blogposts():
return PostModel.query.all()
#staticmethod
def get_one_post(id):
return PostModel.query.get(id)
#staticmethod
def get_one_post_by_slug(id):
return PostModel.query.filter_by(slug=id).first()
def __repr__(self):
return '<id {}>'.format(self.id)
Db is created under models/init.py
# app/models/__init__.py
from flask_bcrypt import Bcrypt
from flask_sqlalchemy import SQLAlchemy
# initialize our db
db = SQLAlchemy()
bcrypt = Bcrypt()
at last my app
import logging.config
from os import environ
from celery import Celery
from dotenv import load_dotenv
from flask import Flask
from flask_admin import Admin
from flask_admin.contrib import sqla
from flask_cors import CORS
from app.models import PostModel, UserModel
from .config import config as app_config
from .models import bcrypt, db
celery = Celery(__name__)
def create_app():
"""
Create app
"""
# loading env vars from .env file
load_dotenv()
APPLICATION_ENV = get_environment()
logging.config.dictConfig(app_config[APPLICATION_ENV].LOGGING)
# app initializations
app = Flask(app_config[APPLICATION_ENV].APP_NAME)
app.config.from_object(app_config[APPLICATION_ENV])
CORS(app, resources={r'/api/*': {'origins': '*'}})
celery.config_from_object(app.config, force=True)
# celery is not able to pick result_backend and hence using
# update
celery.conf.update(
result_backend=app.config['RESULT_BACKEND'])
# Other initializations
bcrypt.init_app(app)
db.init_app(app)
# migration
from flask_migrate import Migrate
migrate = Migrate(app, db)
# Blueprints
from .views.CoreView import core as core_blueprint
app.register_blueprint(
core_blueprint,
url_prefix='/api/v1/core'
)
from .views.UserView import user_api as user_blueprint
app.register_blueprint(
user_blueprint,
url_prefix='/api/v1/users'
)
#app.route('/', methods=['GET'])
def index():
"""
Blog endpoint
"""
return 'Server is up and running'
# Admin
admin = Admin(app)
admin.add_view(sqla.ModelView(PostModel, db.session))
return app
def get_environment():
return environ.get('APPLICATION_ENV') or 'development'
I am new to flask and flask-admin any help is much appreciated.

Related

Flask/sqlalchemy | 'Blueprint' object has no attribute 'query'

I am working on a project for one of my courses at college. The project is a web application using flask and python to create the web application. I am having an issue with my project and the error I am returned is AttributeError: 'Blueprint' object has no attribute 'query' which refers to this line in my code "pagination = transaction.query.paginate(page, per_page, error_out=False)".
transaction init file
import csv
import logging
import os
from flask import Blueprint, render_template, abort, url_for,current_app
from flask_login import current_user, login_required
from jinja2 import TemplateNotFound
from app.db import db
from app.db.models import transaction
from app.transactions.forms import csv_upload
from werkzeug.utils import secure_filename, redirect
transaction = Blueprint('transaction', __name__,
template_folder='templates')
#transaction.route('/transactions', methods=['GET'], defaults={"page": 1})
#transaction.route('/transactions/<int:page>', methods=['GET'])
def transaction_browse(page):
page = page
per_page = 1000
pagination = transaction.query.paginate(page, per_page, error_out=False)
data = pagination.items
try:
return render_template('browse_transactions.html',data=data,pagination=pagination)
except TemplateNotFound:
abort(404)
app init file
"""A simple flask web app"""
import os
import flask_login
from flask import Flask
from flask_bootstrap import Bootstrap5
from flask_wtf.csrf import CSRFProtect
from flask_cors import CORS
from flask_mail import Mail
from app.auth import auth
from app.simple_pages import simple_pages
from app.cli import create_database
from app.db import database
from app.db import db
from app.db.models import User
from app.error_handlers import error_handlers
from app.logging_config import log_con, LOGGING_CONFIG
from app.context_processors import utility_text_processors
from app.transactions import transaction
mail = Mail()
login_manager = flask_login.LoginManager()
def create_app():
"""Create and configure an instance of the Flask application."""
app = Flask(__name__)
if os.environ.get("FLASK_ENV") == "production":
app.config.from_object("app.config.ProductionConfig")
elif os.environ.get("FLASK_ENV") == "development":
app.config.from_object("app.config.DevelopmentConfig")
elif os.environ.get("FLASK_ENV") == "testing":
app.config.from_object("app.config.TestingConfig")
app.mail = Mail(app)
login_manager.init_app(app)
login_manager.login_view = "auth.login"
csrf = CSRFProtect(app)
bootstrap = Bootstrap5(app)
app.register_blueprint(simple_pages)
app.register_blueprint(auth)
app.register_blueprint(database)
app.register_blueprint(log_con)
app.register_blueprint(error_handlers)
app.register_blueprint(transaction)
app.context_processor(utility_text_processors)
app.cli.add_command(create_database)
db.init_app(app)
api_v1_cors_config = {
"methods": ["OPTIONS", "GET", "POST"],
}
CORS(app, resources={"/api/*": api_v1_cors_config})
return app
#login_manager.user_loader
def user_loader(user_id):
try:
return User.query.get(int(user_id))
except:
return None
database models init file
from datetime import datetime
from sqlalchemy import Integer, ForeignKey
from sqlalchemy.orm import relationship, declarative_base
from werkzeug.security import check_password_hash, generate_password_hash
from app.db import db
from flask_login import UserMixin
from sqlalchemy_serializer import SerializerMixin
Base = declarative_base()
transaction_user = db.Table('transaction_user', db.Model.metadata,
db.Column('user_id', db.Integer, db.ForeignKey('users.id')),
db.Column('transaction_id', db.Integer, db.ForeignKey('transaction.id'))
)
class transaction(db.Model,SerializerMixin):
__tablename__ = 'transaction'
id = db.Column(db.Integer, primary_key=True)
type = db.Column(db.String(10), nullable=True, unique=False)
amount = db.Column(db.Integer)
user_id = db.Column(db.Integer, db.ForeignKey('users.id'))
user = relationship("User", back_populates="transaction", uselist=False)
def __init__(self, type, amount):
self.type = type
self.amount = amount

Mapping sql alchemy database models defined in a separate file

I have created a website using flask (python). I would like to create my SQLAlchemy database models in a separate file and import them. I have tried the following code but getting import error. I have tried solutions from similar questions but none is working. What modifications are needed to be made in my code?
structure
main.py
from Website import create_app
app = create_app()
if __name__ == '__main__':
app.run(debug=True)
init.py (underscore not displayed)
from flask import Flask
from .routes import routes
from flask_sqlalchemy import SQLAlchemy
from .dbmodels import Subscribers
DB_NAME = "myDatabase.db"
db = SQLAlchemy()
def create_app():
app = Flask(__name__)
#..........................Register blueprint.......................#
app.register_blueprint(routes, url_prefix='/')
#..........................Database config.......................#
app.config['SQLALCHEMY_DATABASE_URI'] = f'sqlite:///{DB_NAME}'
db.init_app(app)
db.create_all()
sub_1 = Subscribers(name="pavan")
db.session.add(sub_1)
db.session.commit()
return app
dbmodels.py
from . import db
from datetime import datetime
class Subscribers(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(50), nullable=False)
date_created = db.Column(db.DateTime, default=datetime.utcnow())
def __repr__(self):
return '<User %r>' % self.name
You import Subscribers from dbModels in __init__ and db from __init__ in dbModelds. It leads to circular imports.
The simpliest solution - put db = SQLAlchemy() in separate file (e.g. extensions.py and import it from this file in __init__ and in dbModels

Getting Error: cannot import name 'DB' from partially initialized module. Not finding the circular import issue

I'm working on a assignment for school.
But When I try to run the flask app I get some kind of circular import error. I've been trying to go back and remove things step by step while still keeping my project functional. I've hit a wall:
Usage: main.py run [OPTIONS]
Error: While importing 'Help.app', an ImportError was raised:
Traceback (most recent call last): FileUsage: main.py run [OPTIONS]
Error: While importing 'Help.app', an ImportError was raised:
Traceback (most recent call last): File
"/home/chris/Help/venv/lib/python3.8/site-packages/flask/cli.py", line
256, in locate_app
__import__(module_name) File "/home/chris/Help/__init__.py", line 1, in <module>
from .app import create_app
File "/home/chris/Help/app.py", line 5, in
from .models import DB, User, insert_example_users
File "/home/chris/Help/models.py", line 3, in
from .twitter import add_or_update_user
File "/home/chris/Help/twitter.py", line 5, in
from .models import DB, Tweet, User
ImportError: cannot import name 'DB' from partially initialized module
'Help.models' (most likely due to a circular import)
(/home/chris/Help/models.py)
app.py file:
# Main app/routing file for Twitoff
from os import getenv
from flask import Flask, render_template
from .models import DB, User, insert_example_users
# creates application
def create_app():
# Creating and configuring an instance of the Flask application
app = Flask(__name__)
app.config["SQLALCHEMY_DATABASE_URI"] = getenv("DATABASE_URI")
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
DB.init_app(app)
# TODO - Make rest of application
#app.route('/')
def root():
DB.drop_all()
DB.create_all()
insert_example_users()
return render_template("base.html", title="home", users=User.query.all())
#app.route("/update")
def update():
insert_example_users()
return render_template("base.html", title="home", users=User.query.all())
#app.route("/reset")
def reset():
DB.drop_all()
DB.create_all()
return render_template(
"base.html",
title="home",
)
return app
Twitter.py file:
"""Retrieve tweets and users then create embeddings and populate DB"""
from os import getenv
import tweepy
import spacy
from .models import DB, Tweet, User
# TODO - Don't include raw keys and tokens (create .env file)
TWITTER_API_KEY = getenv("TWITTER_API_KEY")
TWITTER_API_SECRET_KEY = getenv("TWITTER_API_SECRET_KEY")
TWITTER_OAUTH = tweepy.oAuthHandler(TWITTER_API_KEY, TWITTER_API_SECRET_KEY)
TWITTER = tweepy.API(TWITTER_OAUTH)
# NLP model
nlp = spacy.load("my_model")
def vectorize_tweet(tweet_text):
return nlp(tweet_text).vector
def add_or_update_user(username):
try:
twitter_user = TWITTER.get_user(username)
db_user = (User.query.get(twitter_user.id)) or User(
id=twitter_user.id, name=username
)
DB.session.add(db_user)
tweets = twitter_user.timeline(
count=200, exclude_replies=True, include_rts=False, tweet_mode="extended"
)
if tweets:
db_user.newest_tweet_id = tweets[0].id
for tweet in tweets:
vectorized_tweet = vectorize_tweet(tweet.full_text)
db_tweet = Tweet(id=tweet.id, text=tweet.full_text, vect=vectorized_tweet)
db_user.tweets.append(db_tweet)
DB.session.add(db_tweet)
DB.session.commit()
except Exception as e:
print(f"Error processing {username}: {e}")
raise e
models.py file:
""""SQLAlchemy models and utility functions for Twitoff Application"""
from flask_sqlalchemy import SQLAlchemy
from .twitter import add_or_update_user
DB = SQLAlchemy()
class User(DB.Model):
"""Twitter User table that will correspond to tweets - SQLAlchemy syntax"""
id = DB.Column(DB.BigInteger, primary_key=True)
name = DB.Column(DB.String, nullable=False)
newest_tweet_id = DB.Column(DB.BigInteger)
def __repr__(self):
return f"<User:{self.name}>"
class Tweet(DB.Model):
"""tweet text data - associated with User table"""
id = DB.Column(DB.BigInteger, primary_key=True)
text = DB.Column(DB.Unicode(290))
vect = DB.Column(DB.PickleType, nullable=False)
user_id = DB.Column(DB.BigInteger, DB.ForeignKey("user.id"), nullable=False)
user = DB.relationship("User", backref=DB.backref('tweets', lazy=True))
def __repr__(self):
return f"<Tweet: {self.text}"
def insert_example_users():
"""We will get an error if we run this twice without dropping & creating"""
users = ["elonmusk", "geoffkeighley", "iamjohnoliver", "neiltyson"]
for user in users:
DB.session.add(add_or_update_user(user))
DB.session.commit()
init.py file:
from .app import create_app
APP = create_app()
You could place the app instance not in __init__.py but in app.py. The instance should be a WSGI callable and not a package identifier.

AttributeError when importing flask-SQLAlchemy model

I am following this tutorial to build a JWT based authentication system.
app.py:
from flask import Flask
from flask_restful import Api
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///app.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SECRET_KEY'] = 'd0cad49580952003e6ae01499c7bb190a4b4f9a5babd866f47064707f7b78506'
api = Api(app)
db = SQLAlchemy(app)
#app.before_first_request
def create_tables():
db.create_all()
import resources, models
api.add_resource(resources.UserRegistration, '/registration')
if __name__ == '__main__':
app.run()
models.py:
from app import db
class UserModel(db.Model):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(100), nullable=False)
password = db.Column(db.String(150), nullable=False)
email = db.Column(db.String(100), unique=True, nullable=False)
def __init__(self, name, password, email):
self.name = name
self.password = password
self.email = email
#classmethod
def find_by_username(cls, username):
return cls.query.filter_by(username=username).first()
def save_to_db(self):
db.session.add(self)
db.session.commit()
resources.py:
from flask_restful import Resource, reqparse
from models import UserModel
class UserRegistration(Resource):
def post(self):
parser = reqparse.RequestParser()
parser.add_argument('name', help='This field cannot be blank', required=True)
parser.add_argument('email', help='This field cannot be blank', required=True)
parser.add_argument('password', help='This field cannot be blank', required=True)
data = parser.parse_args()
if UserModel.find_by_username(data['name']):
return {'message': 'User {} already exists'.format(data['name'])}
new_user = UserModel(
name=data['name'],
password=data['password'],
email=data['email']
)
try:
new_user.save_to_db()
return {
'status': 'User {} was created'.format(data['username'])}
except:
return {'message': 'Something went wrong'}, 500
When I run app.py, I get the following error:
Traceback (most recent call last):
File "G:\python\PycharmProjects\vumonic\app.py", line 19, in <module>
import resources, models
File "G:\python\PycharmProjects\vumonic\resources.py", line 2, in <module>
from models import UserModel
File "G:\python\PycharmProjects\vumonic\models.py", line 1, in <module>
from app import db
File "G:\python\PycharmProjects\vumonic\app.py", line 21, in <module>
api.add_resource(resources.UserRegistration, '/registration')
AttributeError: module 'resources' has no attribute 'UserRegistration'
This error dissapears when I remove from models import UserModel from resources.py.
I cannot figure out the reason for the error.
I am using Flask==1.1.2, Flask-SQLAlchemy==2.4.4 and Flask-RESTful==0.3.8
This is the first time Iam developing an API so any help would be appreciated.
you are facing circular import issue.
When Python imports a module, it checks the module registry to see if the module was already imported. If the module was already registered, Python uses that existing object from cache. The module registry is a table of modules that have been initialized and indexed by module name. This table can be accessed through sys.modules.
If it was not registered, Python finds the module, initializes it if necessary, and executes it in the new module's namespace.
to know more about circular import you can read the article:
https://stackabuse.com/python-circular-imports/
https://www.stefaanlippens.net/circular-imports-type-hints-python.html
this tutorial of Miguel Grinberg is a life savior
https://www.youtube.com/watch?v=NH-8oLHUyDc&t=3205s

How can i both register blueprint and add that app to flask-admin

my Code:
__init__.py
from flask import Flask
from flask_admin import Admin
from flask_admin.contrib.sqla import ModelView
from flask.ext.sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config.from_object('config')
db = SQLAlchemy(app)
from user.user import mod as user
from user.models import User as userModel
app.register_blueprint(user, url_prefix='/user')
admin = Admin(app, name='My app')
admin.add_view(ModelView(userModel, db.session, name='userAdmin'))
user.py:
from flask import Blueprint, json
from flask.views import MethodView
mod = Blueprint('user', __name__)
class UserAPI(MethodView):
def get(self):
users = [
{'nickname': 'Chan'},
{'nickname': 'Hzz'},
]
return json.dumps(users)
mod.add_url_rule('/users/', view_func=UserAPI.as_view('users'))
models.py:
from app import db
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True)
email = db.Column(db.String(120), unique=True)
def __init__(self, username, email):
self.username = username
self.email = email
def __repr__(self):
return "<User %s>" % self.username
i have a blueprint in my user app, and i've registered it, but when i want to add this to my admin to manage the user data, it throws the below exception:
Traceback (most recent call last):
File "run.py", line 2, in <module>
from app import app
File "/home/chenhj/flask/multiapp/app/__init__.py", line 21, in <module>
admin.add_view(ModelView(userModel, db.session, name='chj'))
File "/home/chenhj/.virtualenvs/multiapp/local/lib/python2.7/site-packages/flask_admin/base.py", line 526, in add_view
self.app.register_blueprint(view.create_blueprint(self))
File "/home/chenhj/.virtualenvs/multiapp/local/lib/python2.7/site-packages/flask/app.py", line 62, in wrapper_func
return f(self, *args, **kwargs)
File "/home/chenhj/.virtualenvs/multiapp/local/lib/python2.7/site-packages/flask/app.py", line 885, in register_blueprint
(blueprint, self.blueprints[blueprint.name], blueprint.name)
AssertionError: A blueprint's name collision occurred between <flask.blueprints.Blueprint object at 0x25e5d90> and <flask.blueprints.Blueprint object at 0x21b89d0>. Both share the same name "user". Blueprints that are created on the fly need unique names.
i am crazy about that
If you have a blueprint that has a name of users already then your 'admin' blueprint for your admin users model view needs to be called something different.
You can achieve this with the endpoint var in ModelView
Flask-Admin - ModelView
admin.add_view(ModelView(Users, db.session, endpoint="users_"))
The collision is because you have a module name user and a blueprint called user. Rename the blueprint to user_blueprint. From the code it seems you have a folder called user, a module called user and a blueprint called user. You can avoid problems later on with some descriptive names. Otherwise it is just plain confusing.
You can also override the admin blueprint names in a ModelView subclass:
from flask_admin.contrib.sqla import ModelView
class AppModelView(ModelView):
def create_blueprint(self, admin):
blueprint = super(AppModelView, self).create_blueprint(admin)
blueprint.name = '{}_admin'.format(blueprint.name)
return blueprint
def get_url(self, endpoint, **kwargs):
if not (endpoint.startswith('.') or endpoint.startswith('admin.')):
endpoint = endpoint.replace('.', '_admin.')
return super(AppModelView, self).get_url(endpoint, **kwargs)

Categories

Resources