I'm currently trying my hand at Flask-SQLAlchemy and I'm running into the following problem when it comes to running the commit() method:
First, here is my User class:
from flask_login import LoginManager, UserMixin
from flask_sqlalchemy import Model, SQLAlchemy
from app import db
class User(db.Model, UserMixin):
def __init__(self, id, name, password, active):
self.id = id
self.name = name
self.password = password
self.active = active
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String, nullable=False, unique=True)
password = db.Column(db.String, nullable=False)
active = db.Column(db.Boolean, nullable=False, default=True)
#property
def is_active(self):
return self.active
Now my main app:
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///database.sqlite'
app.secret_key = b'test'
db = SQLAlchemy(app)
from user import User
db.create_all()
db.session.commit() # This commit works fine!
admin = User(1, 'admin', 'admin', True)
db.session.add(admin)
db.session.commit() # <------ Value Error at this position
print(User.query.all())
And I get the following Error message when I try to run my code:
in flask_sqlalchemy\__init__.py
before_models_committed.send(session.main, changes=list(d.values()))
AttributeError: 'SignallingSession' object has no attribute 'main'
I am using Pycharm and the version of flask_sqlalchemy is 2.5.1
Am I using the module wrong?
Thank you for every helpfull comment!
Kind regards,
Bagheera
Now I don't know if this really counts as a solution, but I tried lowering the version of the flask_sqlalchemy module.
After this didn't work either, because now other error messages appeared, I set the version back to the highest.
After that it worked in a mysterious way. But maybe someone has an explanation for this or experienced something similar.
Related
I have installed python 3.9.7 64-bit in Windows 10 - I am using VSCode editor- installed flask, flask-login, flask-sqlalchemy using pip install command line. I created models.py with below commands
from .import db
from flask_login import UserMixin
from sqlalchemy.sql import func
# Defined Class note#
class Note(db.Model):
id = db.Column(db.Integer, primary_key=True)
data = db.Column(db.String(10000))
date = db.Column(db.DateTime(timezone=True), default=func.now())
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
#defined class User#
class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String(150), unique=True)
password = db.Column(db.String(150))
first_name = db.Column(db.String(150))
notes = db.relationship('Note')
Then created Python file init.py to get the data values. but due to the pylance notification, unable to create the database.db file after running the below command.
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from os import path
db = SQLAlchemy()
DB_NAME = "database.db"
def create_app():
app = Flask(__name__)
app.config['SECRET_KEY'] = 'gjkagfkag khsgfafhl'
app.config['SQLQLCHEMY_DATABASE_URI'] = f'sqlite:///{DB_NAME}'
db.init_app(app)
from.views import views
from.auth import auth
app.register_blueprint(views, url_prefix='/')
app.register_blueprint(auth, url_prefix='/')
from.models import User,Note (**# this line is Getting notification highlighter** -(class)user and (class) Note is not accessed Pylance)
create_database(app)
return app
def create_database(app):
if not path.exists('website/' + DB_NAME):
db.create_all(app = app)
print('Created Database!')
Screen shot:
Notification from pylance
There is absolutely no problem with this message. In fact, is not an Error message, it's more like a Info message.
Pylance is telling you that you have imported the User class, but you're not using it. Therefore, User is not accessed. If you hover your cursor over the Note import, the same message will appear and for all variables and imports that you are not using it.
Bonus: Your app config is wrong at the "SQLQLCHEMY_DATABASE_URI". I believe that is "SQLALCHEMY_DATABASE_URI".
This question already has answers here:
AttributeError: can't set attribute when connecting to sqlite database with flask-sqlalchemy
(6 answers)
Closed 1 year ago.
I try to create a database and put an article table in routes.py's /articles/<article_name> route but it gives me AttributeError: can't set attribute. I looked up other sources for a solution but they seemed irrelevant. Error occurs when create_all(), add(), commit() are used.
models.py
from files import db
from datetime import datetime
class Article(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(100), nullable=False,unique=True)
article_content = db.Column(db.Text)
date = db.Column(db.DateTime,default=datetime.utcnow)
abstract = db.Column(db.String(150))
comments = db.relationship("Comment", backref="article", lazy = True)
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
user_name = db.Column(db.String(30), unique=True, nullable=False)
password = db.Column(db.String(30), nullable=False)
comments = db.relationship("Comment", backref="user", lazy = True)
class Comment(db.Model):
id = db.Column(db.Integer, primary_key=True)
user_comment = db.Column(db.String(200), nullable=False)
user_id = db.Column(db.Integer, db.ForeignKey("user.id"))
article_id = db.Column(db.Integer, db.ForeignKey("article.id"))
init.py
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SECRET_KEY'] = ''
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///site.db'
db = SQLAlchemy(app)
from files import routes
routes.py
from files import app, db
from flask import render_template
from files.models import Article
from files.forms import RegisterForm, LoginForm
#app.route('/')
#app.route('/main')
#app.route('/home')
def home():
return render_template("home.html")
#app.route('/articles/<article_name>') # dynamic route
def article(article_name):
db.create_all()
article_ = Article(title = article_name, article_content = "article", abstract = "ndng")
db.session.add(article_)
db.session.commit()
return render_template("article.html", article_name=article_name)
#app.route('/articles')
def articles():
return render_template("articles.html")
#app.route('/register')
def register():
form = RegisterForm()
return render_template("register.html", form = form)
#app.route('/login')
def login():
form = LoginForm()
return render_template("login.html", form = form)
I recently delt with that same error message. It is actually due to an upgrade in SQLAlchemy, which gets installed as a dependency of flask-sqlalchemy.
You can find the question I posted on stackoverflow for the issue here:
The problem gets solved by uninstalling SQLAlchemy==1.4.0 and installing the previous version SQLAlchemy==1.3.23.
Try doing that and see if it helps.
Just Downgrade the SQLAlchemy .
For some reason the latest version is not working
pip install 'SQLAlchemy<1.4.0'
Downgrading SQLAlchemy to anything lower than 1.4.0 (1.3.8 in my case) solves the problem.
I'm trying to create a function that can be scheduled to delete all rows within an SQLAlchemy model.
I'm trying to use apscheduler to accomplish this task. But I keep getting an error that says:
sqlalchemy.orm.exc.UnmappedInstanceError: Class 'flask_sqlalchemy.model.DefaultMeta' is
not mapped; was a class (app.models.User) supplied where an instance was required?
Am I missing something?
Here is my app/__init__.py:
from flask import Flask
from flask_login import LoginManager
from flask_sqlalchemy import SQLAlchemy
from config import Config
app = Flask(__name__)
db = SQLAlchemy()
login = LoginManager()
app.config.from_object(Config)
db.init_app(app)
login.init_app(app)
login.login_view = 'login'
from app import routes, models
and here is my manage.py:
from apscheduler.schedulers.background import BackgroundScheduler
from app import app, db
from flask_migrate import Migrate
from flask_script import Manager
from app.models import User
manager = Manager(app)
migrate = Migrate(app, db)
def clear_data():
db.session.delete(User)
print("Deleted User table!")
#manager.command
def run():
scheduler = BackgroundScheduler()
scheduler.add_job(clear_data, trigger='interval', seconds=5)
scheduler.start()
app.run(debug=True)
if __name__ == '__main__':
manager.run()
Also, here's my model:
from app import db, login
from datetime import datetime
from flask_login import UserMixin
from werkzeug.security import generate_password_hash, check_password_hash
class User(UserMixin, db.Model):
id = db.Column(db.Integer, primary_key=True, unique=True)
api_token = db.Column(db.String(50), unique=True)
username = db.Column(db.String(64), index=True, unique=True)
email = db.Column(db.String(120), index=True, unique=True)
password_hash = db.Column(db.String(128))
todos = db.relationship('Todo', backref='owner', lazy='dynamic')
def __repr__(self):
return '<models.py {}>'.format(self.username)
def set_password(self, password):
self.password_hash = generate_password_hash(password)
def check_password(self, password):
return check_password_hash(self.password_hash, password)
#login.user_loader
def load_user(id):
return User.query.get(int(id))
class Todo(db.Model):
id = db.Column(db.Integer, primary_key=True)
body = db.Column(db.String(140))
timestamp = db.Column(db.DateTime, index=True, default=datetime.utcnow)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
def __repr__(self):
return '<Todo {}>'.format(self.body)
As your error indicated, it is expecting an instances of an object, and you instead passed it a class. I think the issue is the first line in the clear_data function:
db.session.delete(User)
It was expecting an instances of a User record to delete, and doesn't know how to delete the whole table using just the model.
Check out this answer on how to delete all rows in a table. There are a few ways to do this, but this may be the least change for you:
db.session.query(User).delete()
In this case you are adding the step of SELECTing all the records in the table User maps to, then deleting them.
P.S.: as mentioned in the linked answer, you need to .commit() your session, otherwise it won't stick, and will rollback after you close the connection.
db.session.commit()
Code snippet:
db.session.query(model_name).delete()
db.session.commit()
I have read quite a bit of documentation and I can't see what is wrong with these lines
update_this = User.query.filter_by(email=email).first()
update_this.emailconfirmed = True
db.session.commit()
...and yet when I deploy the boolean column 'emailconfirmed' never is update to True. I have confirmed with print statements that update_this.emailconfirmed is False at the exact point in the code shown above... I just can't seem to update that value. Does anybody know what tests I can do, what imports I should check etc. etc.
Right now this is the top of my main .py file where the above code appears
from flask import Flask, render_template, request, session, redirect, url_for, make_response
# the following line imports from models.py
from models import db, User
# the following line imports SignupForm from forms.py
from forms import SignupForm, LoginForm
from flask_mail import Mail, Message
from itsdangerous import URLSafeTimedSerializer
# Production (causes Heroku to redirect to SSL)
from flask_sslify import SSLify
from flask_sqlalchemy import SQLAlchemy
import os
app = Flask(__name__)
sslify = SSLify(app)
sslify = SSLify(app, subdomains=True)
app.config.from_pyfile('config_file.cfg')
app.config['SQLALCHEMY_DATABASE_URI'] = os.environ['DATABASE_URL']
db = SQLAlchemy(app)
mail = Mail(app)
ts = URLSafeTimedSerializer(app.config['SECRET_KEY'], salt=app.config['SALT'])
and this is my models.py file
from flask_sqlalchemy import SQLAlchemy
from werkzeug import generate_password_hash, check_password_hash
db = SQLAlchemy()
class User(db.Model):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
firstname = db.Column(db.String(100))
lastname = db.Column(db.String(100))
role = db.Column(db.String(20))
roleapproved = db.Column(db.Boolean)
school = db.Column(db.String(100))
email = db.Column(db.String(120), unique=True)
emailconfirmed = db.Column(db.Boolean)
pwdhash = db.Column(db.String(100))
def __init__(self, firstname, lastname, role, school, email, password):
self.firstname = firstname.title()
self.lastname = lastname.title()
self.role = role.lower()
if role.lower() == 'student':
self.roleapproved = True
if role.lower() == 'teacher':
self.roleapproved = False
self.school = school.title()
self.email = email.lower()
self.set_password(password)
self.emailconfirmed = False
def set_password(self, password):
self.pwdhash = generate_password_hash(password)
def check_password(self, password):
return check_password_hash(self.pwdhash, password)
def __repr__(self):
return '<User {0}>'.format(self.email)
Any help on doing the update I mentioned above would be greatly appreciated!!
Ideally you want to maintain a single session throughout your application lifecycle. This way it makes it easy to reason about and you avoid binding sessions to individual models.
Thanks #Ilja Everila
In main.py instead of initializing SQLAlchemy
you should write,
db.init_app(app)
Define a save instance method for your User model.
def save(self):
"""Saves model object instance
"""
db.session.add(self)
db.session.commit()
You can call this method to save the instance as
update_this.save()
Another way to update the entity is to get the specific object session before committing
from sqlachemy.orm import session
...
session = session.object_session(update_this)
session.commit()
i use pycharm 5.0 and python3.5.And i download all the liarbry by the build-in function of pycharm(setting-project-project interpreter-"+").other libraries appear well,but some problems happens to flask-SQLAlchemy.
i import flask-SQLAlchemy successfully.however,pycharm remind me that "unresolved attribute reference 'Column' in class'SQLAlchemy'"."unresolved attribute reference 'relationship' in class 'SQLAlchemy'" and so on.
I have try some ways ,but they didn't work.for example:1.restart 2.remove and redownload 3.refresh the cache.which mention in PyCharm shows unresolved references error for valid code
code:
from flask import Flask, redirect, render_template, session, url_for, flash
from flask_sqlalchemy import SQLAlchemy
from flask_bootstrap import Bootstrap
from flask_wtf import Form
from wtforms import StringField, SubmitField
import os
from wtforms.validators import data_required
basedir = os.path.abspath(os.path.dirname(__file__))
app = Flask(__name__)
app.config['SECRET_KEY'] = 'hard to guess string'
app.config['SQLALCHEMY_DATABASE_URI'] =\
'sqlite:///' + os.path.join(basedir, 'data.sqlite')
app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True
bootstrap = Bootstrap(app)
db = SQLAlchemy(app)
class Role(db.Model):
__tablename__ = 'roles'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(64), unique=True)
users = db.relationship('User', backref='role', lazy='dynamic')
def __repr__(self):
return '<Role %r>' % self.name
class User(db.Model):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(64), unique=True, index=True)
role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))
def __repr__(self):
return '<User %r>' % self.username
how can i solve this problem?
The constructor of the flask_sqlalchemy.SQLAlchemy class calls _include_sqlalchemy, which attaches all attributes from sqlalchemy and sqlalchemy.orm to its instances.
This is only done at runtime and not detected by PyCharm's code inspection.
It would require flask_sqlalchemy to use a more standard way of importing those attributes, like from sqlalchemy import *. But this would import the attributes into the flask_sqlalchemy module instead of each instance of SQLAlchemy and thus change the way they're accessed.
I'm not a Python or SQLAlchemy expert and won't judge whether this is good design or not but you could open an issue on https://github.com/pallets/flask-sqlalchemy and discuss it there.
here is what I do.
from flask_sqlalchemy import SQLAlchemy
from typing import Callable
class MySQLAlchemy(SQLAlchemy): # Or you can add the below code on the SQLAlchemy directly if you think to modify the package code is acceptable.
Column: Callable # Use the typing to tell the IDE what the type is.
String: Callable
Integer: Callable
db = MySQLAlchemy(app)
class User(db.Model, UserMixin):
__tablename__ = "users"
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(20)) # The message will not show: Unresolved attribute reference 'Column' for class 'SQLAlchemy'
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
def create_test_data():
db.create_all()
test_user = User(name='Frank') # I add __init__, so it will not show you ``Unexpected argument``
db.session.add(test_user)
db.session.commit()
I've ran into the same problem just now.
In short if I just hit Run the code runs with exit code 0 even is PyCharm shows Unresolved attribute reference
but for anyone who might make the same mistake as I did before simply hitting Run:
This is the code that I was writing and it showed 'Unresolved attribute reference 'Column' for class 'SQLAlchemy'' also for eg. 'Unresolved attribute reference 'Integer' for class 'SQLAlchemy' '.
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///new-books-collection.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] =
False
db = SQLAlchemy(app)
class Books(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(250), unique=True, nullable=False)
author = db.Column(db.String(250), unique=True, nullable=False)
rating = db.Column(db.Float, nullable=False)
db.create_all()
My problem was that I hovered over Column and Integer and clicked Add method Column() to class SQLAlchemy. Also the same with Integer.
From that moment TypeErrors came up for me because it created these empty methods in __init__.py of SQLAlchemy.
To solve this I used pip install flask_sqlalchemy --upgrade and pip install flask_sqlalchemy. And did not Add methods again. It still showed Unresolved attribute reference, but the code ran with exit code 0 and the database was created, with the right data inside.
Hope that helps!
Check the version of flask_sqlalchemy in your pycharm or environment.
i had same problem ,the easiest solution
pip install flask_sqlalchemy --upgrade
100% its gone work.