I spent all afternoon trying to figure this out. I've checked the flask documentation, mostly flask-marshmallow documentation most notably the sqlalchemy integration part and some other stackoverflow questions.
Is this something to do with serialization? I thought it was taken care of by using the flask-sqlalchemy package?
When I run this with a postman request, I get:
{
"name": [
"Unknown field."
]
}
My code:
Schema
from ma import ma
from models.form import FormModel
class FormSchema(ma.SQLAlchemySchema):
class Meta:
model = FormModel
Model
from db import db
class FormModel(db.Model):
__tablename__ = "forms"
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(255))
Resource
from flask_restful import Resource
from flask import request
from models.form import FormModel
from schemas.form import FormSchema
from db import db
form_schema = FormSchema()
class NewForm(Resource):
#classmethod
def post(cls):
print("Request:")
print(request.get_json())
print("Form schema load:")
#print(form_schema.load(request.get_json()))
form = form_schema.load(request.get_json())
print("Form")
#print(form)
db.session.add(form)
db.session.commit()
#form_schema.dump(form)
app.py
from flask import Flask, jsonify
from flask_restful import Api
from marshmallow import ValidationError
from db import db
from ma import ma
from models.form import FormModel
from schemas.form import FormSchema
from resources.form import NewForm
app = Flask(__name__)
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///test.db"
api = Api(app)
#app.before_first_request
def create_tables():
db.create_all()
#app.errorhandler(ValidationError)
def handle_marshmallow_validation(err):
return jsonify(err.messages), 400
api.add_resource(NewForm, "/form")
if __name__ == "__main__":
db.init_app(app)
ma.init_app(app)
app.run(port=5000, debug=True)
db.py
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
ma.py
from flask_marshmallow import Marshmallow
ma = Marshmallow()
Figured it out!
The schema isn't correct. It should be:
class FormSchema(ma.SQLAlchemyAutoSchema):
class Meta:
model = FormModel
load_instance = True
I changed ma.SQLAlchemySchema to ma.SQLAlchemyAutoSchema
And added load_instance = True
Related
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
I've been building a Flask app with the help of this video:
https://www.youtube.com/watch?v=dam0GPOAvVI&t=3256s
Here is the file of my init so far :
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from os import path
DB_NAME = "database.db"
db = SQLAlchemy()
app = Flask(__name__)
app.config['SECRET_KEY'] = 'bindthemostselling'
app.config['SQLALCHEMY_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='/')
if __name__ == '__main__':
app.run(debug=True)
and here is the file of my models so far its just one class:
from flask_login import UserMixin
from . import db
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))
My problem is that the db.Column inside the User class is unrecognizable. I've tried to reinstall sqlalchemy and flask and i've looked at everything he did again and even copied the code from his github and it still wont recognize that function or even other functions that I have noticed so far from the video. This is the first time I try to make an actual python app so maybe there is something i'm missing in the syntax?
Thanks in advance.
EDIT:
So i have updated the init file to include everything so i can run and see what error i get here is what I have now:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from os import path
from models import User
from flask_login import LoginManager
DB_NAME = "database.db"
db = SQLAlchemy()
app = Flask(__name__)
app.config['SECRET_KEY'] = 'bindthemostselling'
app.config['SQLALCHEMY_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='/')
login_manager = LoginManager()
login_manager.login_view = 'auth.login'
login_manager.init_app(app)
#login_manager.user_loader
def load_user(id):
return User.query.get(int(id))
def create_database(app):
if not path.exists('.' + DB_NAME):
db.create_all(app=app)
print('Created Database!')
create_database(app)
if __name__ == '__main__':
app.run(debug=True)
Here is the traceback that I got (Sorry if the formatting is bad):
Traceback (most recent call last):
File "c:\Users\Ashraf\FlaskToDo_init_.py", line 4, in
from models import User
File "c:\Users\Ashraf\FlaskToDo\models.py", line 2, in
from . import db
ImportError: attempted relative import with no known parent package
so apparently the db is not imported correctly? This can't be true cause when I created the User class and passed the db.Model, it recognized it. What am I exactly missing here?
Try changing the import statement in the models file from
from . import db
to:
from init import db
This way you should get a circular import error, so move from models import User in your init after db is defined.
This is the complete setup:
init:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from os import path
from flask_login import LoginManager
DB_NAME = "database.db"
db = SQLAlchemy()
app = Flask(__name__)
app.config['SECRET_KEY'] = 'bindthemostselling'
app.config['SQLALCHEMY_DATABASE_URI'] = f'sqlite:///{DB_NAME}'
db.init_app(app)
login_manager = LoginManager()
login_manager.login_view = 'auth.login'
login_manager.init_app(app)
#login_manager.user_loader
def load_user(id):
return User.query.get(int(id))
def create_database(app):
if not path.exists('.' + DB_NAME):
db.create_all(app=app)
print('Created Database!')
create_database(app)
if __name__ == '__main__':
app.run(debug=True)
from models import User
models:
from flask_login import UserMixin
from init import db
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))
EDIT:
add a route to actually navigate in your app:
#app.route("/")
def home():
return "Hello World"
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
So Im trying to create a website using flask and SQLAlchemy for database storage but I keep getting the two aforementioned errors
Here is my app.py code
import os
from flask import Flask, session,render_template, request
from flask_session import Session
from sqlalchemy import create_engine,Column, Integer, String
from sqlalchemy.orm import scoped_session, sessionmaker
from flask_sqlalchemy import SQLAlchemy
from models import *
app = Flask(__name__)
#app.config["DATABASE_URL"] = "sqlite:////plz_work.db"
app.config["SQLALCHEMY_DATABASE_URI"] = os.getenv("DATABASE_URL")
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
db.init_app(app)
# Check for environment variable
#if not os.getenv("DATABASE_URL"):
# raise RuntimeError("DATABASE_URL is not set")
# Configure session to use filesystem
app.config["SESSION_PERMANENT"] = False
app.config["SESSION_TYPE"] = "filesystem"
Session(app)
# Set up database
engine = create_engine(os.getenv("DATABASE_URL"))
db = scoped_session(sessionmaker(bind=engine))
class User:
def __init__(self,username,password):
self.username = username
self.password = password
#app.route("/")
def index():
return render_template('index.html')
#app.route("/registration.html")
def registration():
return render_template('registration.html')
#app.route("/send", methods = ['GET','POST'])
def send():
username = request.form['username']
password = request.form['password']
users = User(username,password)
db.session.add(users)
db.session.commit()
return render_template('index.html')
if __name__ == "__main__":
app.run(debug = True)
db.create_all()
and here is my models.py file
import os
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
class USERS(db.Model):
__tablename__ = "Users"
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String)
password = db.Column(db.String)
def __repr__(self):
value = "USER:({}, {})".format(self.username, self.password)
return value
I have been looking online for a soloution for so long but I can not find anything that works for me, and I have spent 2 days just on this problem, any help will be appreciated.
Thank You !!
I guess you're overriding your database object within your models.py file.
I suggest you to use sqlalchemy itself or flask-sqlalchemy not using them together. In my opinion things get complicated if you use them together.
You can achive that like this:
in your app.py
...your_other_imports...
import sqlalchemy
from sqlalchemy import create_engine
from sqlalchemy.orm import scoped_session, sessionmaker
from sqlalchemy.ext.declarative import declarative_base
from .models import *
app = Flask(__name__)
...your_other_configs...
# Set up database
engine = create_engine(os.getenv("DATABASE_URL"))
db = scoped_session(sessionmaker(bind=engine))
#NOW db carries your database session
#Do not define your database models in app.py remove User class from here.
#You should define your database model and also your query method (not necessary)
#if you're used to query with flask-sqlalchemy. Would make queries look similar to you
dbModel = declarative_base()
dbModel.query = db.query_property()
# define the function which will create your tables
def init_db():
from .models import *
dbModel.metadata.create_all(bind=engine)
...your_routes...
if __name__ == "__main__":
app.run(debug = True)
# now call the function to create your tables
init_db()
in your models.py
from .app import dbModel
from sqlalchemy import Column, Integer, String
class User(dbModel):
__tablename__ = "users"
id = Columnn(Integer, primary_key=True)
username = Column(String)
password = Column(String)
def __repr__(self):
value = "USER:({}, {})".format(self.username, self.password)
return value
Using query_property you can now query your data from your database and use your session to put data in your database like this:
User.query.filter_by(username=...).first()
newUser = User(
username=...,
password=...
)
db.add(newUser)
db.commit()
I'm trying to split out my models into a separate file as it's getting too large to manage. I've followed this but I am getting a NameError despite having run db.create_all():
NameError: name 'importsTable' is not defined
# stack_app.py
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from stack_dbmodels import db
from stack_dbmodels import importsTable
from datetime import datetime
app = Flask(__name__)
app.secret_key = 'secretsquirrel'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///stack_newAppCsv.db'
db.init_app(app)
#app.route('/', methods=['GET'])
def stack():
username = "username"
new_user = importsTable(username)
db.session.add(new_user)
db.session.commit()
return "Done!"
if __name__ == "__main__":
app.run(debug = True, port=8080)
My models file:
# stack_dbmodels.py
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
class importsTable(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80))
def __init__(self, username):
self.username = username
def __repr__(self):
return '<Import {0}>'.format(self.username)
The problem was mainly with the context of the app but during my tests there were a couple of gotchas I found. Key to make the above work was:
When I reference importsTable it wasn't initially defined unless I did:
from stack_dbmodels import db
from stack_dbmodels import importsTable
And whilst the .db file was created, the context wasn't correct so it couldn't create the actual importsTable so I added the following and problem solved, the key bit was "with app.app_context()":
db.init_app(app)
with app.app_context():
db.create_all()
Final working code was:
# stack_app.py
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from stack_dbmodels import db
from stack_dbmodels import importsTable
from datetime import datetime
app = Flask(__name__)
app.secret_key = 'secretsquirrel'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///stack_newAppCsv.db'
db.init_app(app)
with app.app_context():
db.create_all()
#app.route('/', methods=['GET'])
def stack():
username = "username"
new_user = importsTable(username)
db.session.add(new_user)
db.session.commit()
return "Done!"
if __name__ == "__main__":
app.run(debug = True, port=8080)