I get an error while trying to process a Query result based on the .first() method, whereas the .all() method returns the intended values.
#app.route('/getAlphabet')
def getElement():
abc=["abc","def","ghi"]
newTest=Test(idU1=json.dumps(abc))
db.session.add(newTest)
db.session.commit()
entryString = testSchema.dumps(Test.query.with_entities(Test.idU1).filter_by(idm=1).first())
return entryString
The result viewed in the browser is[{}], while .all() produces the intended result [{"idU1": "[\"abc\", \"def\", \"ghi\"]"}].
Has anyone had the same problem?
My Code to set up the database:
app = Flask(__name__)
app.config["DEBUG"] = True
SQLALCHEMY_DATABASE_URI = "mysql+mysqlconnector://{username}:{password}#{hostname}/{databasename}".format(
username="Ehrismann",
password="abcdefgh",
hostname="Ehrismann.mysql.pythonanywhere-services.com",
databasename="Ehrismann$default",
)
app.config["SQLALCHEMY_DATABASE_URI"] = SQLALCHEMY_DATABASE_URI # connection specs
app.config["SQLALCHEMY_POOL_RECYCLE"] = 299 # don't care
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
db = SQLAlchemy(app) # actually make connection
ma = Marshmallow(app) # instantiate MarshmallowObject
class Test(db.Model): # new Table: comment
__tablename__ = "test"
idm = db.Column(db.Integer, primary_key=True) # new Column
idU1=db.Column(db.String(100), nullable=False)
class TestSchema(ma.ModelSchema):
class Meta:
model=Test
testSchema = TestSchema(many=True)
Related
I'm trying to make a pair of tables with a many-many relationship. Here's my code to set up the tables:
from flask import Flask, render_template
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy.exc import IntegrityError
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///db.sqlite'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
recipe_ingredient = db.Table('recipe_ingredient',
db.Column('recipe_name', db.String(64), db.ForeignKey('recipe.name')),
db.Column('ingredient_name', db.String(64), db.ForeignKey('ingredient.name'))
)
class Recipe(db.Model):
name = db.Column(db.String(64), primary_key = True)
ingredients_for = db.relationship('Ingredient', secondary='recipe_ingredient', backref='recipes_for')
def __repr__(self):
return f'<Recipe: {self.name}>'
class Ingredient(db.Model):
name = db.Column(db.String(64), primary_key = True)
def __repr__(self):
return f'<Ingredient: {self.name}>'
Now, here's some test code to try and add data to the tables:
db.create_all()
r0 = Recipe(name='eggsandwich')
db.session.merge(r0)
r1 = Recipe(name='tomatoegg')
db.session.merge(r1)
i0 = Ingredient(name='egg')
db.session.merge(i0)
i1 = Ingredient(name='bread')
db.session.merge(i1)
i2 = Ingredient(name='tomato')
db.session.merge(i2)
db.session.commit()
r0.ingredients_for.append(i0)
r0.ingredients_for.append(i1)
r1.ingredients_for.append(i0)
r1.ingredients_for.append(i2)
db.session.commit()
print([i.name for i in i.ingredients_for])
When I run this, it prints "['eggsandwich', 'tomatoegg']", as expected. However, in DB Browser, the recipe_ingredient table is empty:
Why isn't this table populating? How do I get the relationships to show up there?
I'm following a tutorial and using the below code. I'm also using Postman to view the status of the server for http://localhost:5000/planets , but I'm getting 500 INTERNAL SERVER ERROR, when I should see my JSON data of the planets I created.
In the command line I also see: AttributeError: 'list' object has no attribute 'data'
I feel it might have to do with the line that has: return jsonify(result.data) but I'm not sure.
from flask import Flask, jsonify, request
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy import Column, Integer, String, Float
import os
from flask_marshmallow import Marshmallow
from marshmallow import Schema
app = Flask(__name__)
basedir = os.path.abspath(os.path.dirname(__file__))
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///C:/Users/krist/Py3/flask2/planets.db'
db = SQLAlchemy(app)
ma = Marshmallow(app)
#app.cli.command('db_create')
def db_create():
db.create_all()
print("DB Created")
#app.cli.command('db_seed')
def deb_seed():
mercury = Planet(planet_name='Mercury',
planet_type='Class D',
home_star='Sol',
mass=3.25e23,
radius=1516,
distance=35.98e6)
venus = Planet(planet_name='Venus',
planet_type='Class K',
home_star='Sol',
mass=8.95e24,
radius=3516,
distance=67.98e6)
earth = Planet(planet_name='Earth',
planet_type='Class M',
home_star='Sol',
mass=5.97e24,
radius=3916,
distance=92.96e6)
db.session.add(mercury)
db.session.add(venus)
db.session.add(earth)
test_user = User(first_name='William',
last_name='Hershel',
email='test#test.com',
password='p#ssw0rd')
db.session.add(test_user)
db.session.commit()
print("DB Seeded")
#app.route('/planets', methods=['GET'])
def planets():
planets_list = Planet.query.all()
result = planets_schema.dump(planets_list)
return jsonify(result.data)
class User(db.Model):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
first_name = Column(String)
last_name = Column(String)
email = Column(String, unique=True)
password = Column(String)
class Planet(db.Model):
__tablename__ = 'planets'
planet_id = Column(Integer, primary_key=True)
planet_name = Column(String)
planet_type = Column(String)
home_star = Column(String)
mass = Column(Float)
radius = Column(Float)
distance = Column(Float)
class UserSchema(ma.Schema):
class Meta:
fields = ('id', 'first_name', 'last_name', 'email', 'password')
class PlanetSchema(ma.Schema):
class Meta:
fields = ('planet_id', 'planet_name', 'planet_type', 'home_star', 'mass', 'radius', 'distance')
user_schema = UserSchema()
users_schema = UserSchema(many=True)
planet_schema = PlanetSchema()
planets_schema = PlanetSchema(many=True)
if __name__ == '__main__':
app.run()
Instead of
result = planets_schema.dump(planets_list)
return jsonify(result.data)
Try
result = planets_schema.dump(planets_list)
return jsonify(result)
Why this works:
Here you are querying the Planet Mapper to return a list of Planet ORM objects
planets_list = Planet.query.all()
Then the Marshmallow schema is used to marshal, or transform the ORM object into a python dictionary object. This is the basic principle of marshaling - transforming data from one format into another when the data is about to be transmitted or stored. So in this case you transform you data from a list of SQLAlchemy ORM objects into a list of Python dictionary objects.
result = planets_schema.dump(planets_list)
Now you have result (which could more aptly be names results that contains a list of dictionary objects.
Then you are attempting to access the data variable on this list object. However Python lists have no data variable, so you get an error.
return jsonify(result.data)
The jsonify method from flask accepts a list of dictionaries as input, so simply modifying this line to the below should work:
return jsonify(result)
I am able to perform 'select' queries to my Mysql database.
However, the "insert" ones don't change the database, only the python objects. So when I restart the flask app, all the commited(?) editions are gone.
Views:
from flask import Flask, render_template, request, redirect, url_for, flash, Response
from sqlalchemy import exc
from models import *
app = Flask(__name__)
app.config['DEBUG'] = True
app.config['SECRET_KEY'] = 'kjhS7usfHGJHDez78'
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+mysqldb://admin:admin#127.0.0.1:3306/grenier'
app.config['SQLALCHEMY_ECHO'] = True
db = SQLAlchemy(app)
db.create_all()
#app.route('/ajax/submit_edition', methods=['POST'])
def submit_edition():
if request.method == 'POST':
given_id=1
show = Shows.query.filter_by(id=given_id).first()
show.short_description = "Hello"
try:
db.session.commit()
db.session.flush()
return "ok"
except exc.SQLAlchemyError:
return "Error in commiting the edition"
No particular exception is found. The route always returns "ok".
Models:
from sqlalchemy import Column, ForeignKey
from sqlalchemy.dialects.mysql import LONGTEXT, YEAR
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
class Shows(db.Model):
__tablename__ = "shows"
id = Column(db.Integer, ForeignKey("programmation.id"), primary_key=True)
date = Column(db.DATETIME)
title = Column(db.VARCHAR(50))
short_description = Column(db.VARCHAR(200))
type = Column(db.VARCHAR(20))
background_image = Column(db.VARCHAR(150))
content = Column(LONGTEXT)
def serialize(self, whatTo):
result = {}
if 'id' in whatTo:
result['id'] = self.id
if 'date' in whatTo:
result['date'] = str(self.date)
if 'title' in whatTo:
result['title'] = self.title
if 'short_description' in whatTo:
result['short_description'] = self.short_description
if 'type' in whatTo:
result['type'] = self.type
if 'background_image' in whatTo:
result['background_image'] = self.background_image
if 'content' in whatTo:
result['content'] = self.content
return result
class Programmation(db.Model):
__tablename__ = "programmation"
id = Column(db.Integer, primary_key=True)
semester = Column(db.Integer)
year = Column(YEAR)
When I look at the logs, the sql request is created for the select. But for the insert commit(), there is nothing.
Thank you !
The problem is usage of two different SQLAlchemy instance. When you call db.create_all() method it creates all tables which which inherited from db.Model but in your views you don't have any model inherited from db = SQLAlchemy(app). All your models inherited from other SQLAlchemy instance. To fix this import the db object from views to models module and use it as parent class for inheritance:
#models.py
from views import db
#db = SQLAlchemy() #remove this line
class Show(db.Model):
...
I need to create a dB for testing purposes and I would like initialize it with "some" users.
The "intended" code is:
import os
from flask import Flask
from flask.ext.script import Manager, Shell
from flask.ext.sqlalchemy import SQLAlchemy
app = Flask(__name__)
manager = Manager(app)
db = SQLAlchemy(app)
class User(db.Model):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key = True)
name = db.Column(db.String(64), unique = True)
email = db.Column(db.String(64), unique = True)
def __init__(self, user = None, email = None):
name = self.__tablename__
db.drop_all()
db.create_all()
for i in range(100):
user = User('user%d' % i, 'someone#example.com')
db.session.add(user)
db.session.commit()
def __repr__(self):
return '<User %r>' % self.name
The call usr_db = User() generates RuntimeError: maximum recursion depth exceeded.
The question is , when during construction the class is "ready" to be called recursively to avoid the error above.
I think creating test users inside the model class is the wrong way to do it. This is going to recursively call __init__() if you instantiate a User() instance inside __init__(). A better place would be inside a unittest setUp() method.
However, if you really want to do this, you could guard against instantiating the users more than once like this:
class User(db.Model):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key = True)
name = db.Column(db.String(64), unique = True)
email = db.Column(db.String(64), unique = True)
_test_users_initialised = False
def _initialise_test_users(self):
if self._test_users_initialised:
return
self.__class__._test_users_initialised = True
for i in range(100):
user = User('user%d' % i, 'someone#example.com')
db.session.add(user)
def __init__(self, user = None, email = None):
name = self.__tablename__
db.drop_all()
db.create_all()
self._initialise_test_users()
db.session.commit()
What i have: multiple identical databses and a SQL-Alchemy setup.
What I need to achieve: a single "Flask" function able to query all the databses. All other functions need to access only one of the databases.
The DB's already exist and I am loading data from them.
Initially I was only using the SQL-Alchemy abstraction layer, without any Flask model. This is how the code looked like:
app = Flask(__name__)
app.config.from_object('myflaskapp.config.settings')
metadata = None
def connect_db():
engine = create_engine(app.config['DATABASE_URI'])
global metadata
metadata = MetaData(bind=engine)
return engine.connect()
#app.before_request
def before_request():
g.db = connect_db()
#app.after_request
def after_request(response):
close_connection()
return response
being DATABASE_URI declared in settings.py. I guess doesn't matter, however the underlying DB is a Mysql server and DATABASE_URI looks like:
DATABASE_URI = 'mysql://' + dbuser + ':' + dbpass + '#' + dbhost + '/' +dbname
The above code allows me to write something like this:
myTable = Table('branch', metadata, autoload=True)
myBranch = select([myTable])
which is quite handy. This approach works just fine unless I have to deal with more than one DB. To be more precise I'd like to show (from within the same function) data belonging to multiple DB's that have exactly the same structure. Meaning that the same query can be succesfully run againsy any DB. In pseudo code:
#app.route('/summary')
def summary():
....
allData = []
for db in all_of_my_dbs:
allData.append(db.query())
....
sendToTemplate(allData)
Is it something doable? Is it feasable?
Thank you.
It's definitely possible.
Try adding something like this to your settings file
SQLALCHEMY_BINDS = {
'users': 'mysqldb://localhost/users',
'appmeta': 'sqlite:////path/to/appmeta.db'
}
Edit
So here is a working copy/paste example
from flask import Flask
from flask.ext.sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.debug = True
databases = {
'sqlite1': 'sqlite:///sqlite1.db',
'sqlite2': 'sqlite:///sqlite2.db'
}
app.config['SQLALCHEMY_BINDS'] = databases
db = SQLAlchemy(app)
class Thing(db.Model):
__tablename__ = "sqlite1"
thing_id = db.Column(db.Integer, primary_key=True)
thing_val = db.Column(db.String(40))
def __init__(self, thing_val):
self.thing_val = thing_val
class Thing2(db.Model):
__tablename__ = "sqlite2"
thing_id = db.Column(db.Integer, primary_key=True)
thing_val = db.Column(db.String(40))
def __init__(self, thing_val):
self.thing_val = thing_val
if __name__ == "__main__":
db.create_all()
t1 = Thing("test1")
t2 = Thing2("test2")
db.session.add(t1)
db.session.add(t2)
db.session.commit()
t1 = Thing.query.filter_by(thing_id=1).first()
t2 = Thing2.query.filter_by(thing_id=1).first()
print t1.thing_val
print t2.thing_val
First I would like to remark a couple of things regarding my very own situation. The two tables have the same name, same DDL but belong to different schema's/database's.
from flask import Flask
from flask.ext.sqlalchemy import SQLAlchemy
app = Flask(__name__)
databases = {
'sqlite1': 'sqlite:///sqlite1.db',
'sqlite2': 'sqlite:///sqlite2.db'
}
app.config['SQLALCHEMY_BINDS'] = databases
db = SQLAlchemy(app)
class Thing(db.Model):
__tablename__ = "mytable"
__bind_key__ = 'sqlite1'
thing_id = db.Column(db.Integer, primary_key=True)
thing_val = db.Column(db.String(40))
def __init__(self, thing_val):
self.thing_val = thing_val
if __name__ == "__main__":
t1 = Thing.query.filter_by(thing_id=1).first()
print t1.name
The moment I add a second Class named Thing2 just after the first class definition everything breakes. I.e.:
class Thing(db.Model):
__tablename__ = "mytable"
__bind_key__ = 'sqlite1'
thing_id = db.Column(db.Integer, primary_key=True)
thing_val = db.Column(db.String(40))
def __init__(self, thing_val):
self.thing_val = thing_val
class Thing2(db.Model):
__tablename__ = "mytable"
__bind_key__ = 'sqlite2'
thing_id = db.Column(db.Integer, primary_key=True)
thing_val = db.Column(db.String(40))
def __init__(self, thing_val):
self.thing_val = thing_val
The above code breaks with this error:
InvalidRequestError: Table 'mytable' is already defined for this MetaData instance. Specify 'extend_existing=True' to redefine options and columns on an existing Table object.
So the framework doesn't seem to be able to distinguish between the two of them.
apparently there is a bug on that issue -https://github.com/mitsuhiko/flask-sqlalchemy/pull/222 so the problem is that the bind key must be unique and can be used only for one class (at least for now),so you could still have multiple databases but each database can have only one table or a class but it does appear to have a huge overhead if you many tables still this is just a workaround at least for now...
here is the reference for "Binds" -http://flask-sqlalchemy.pocoo.org/2.0/binds/#binds
Below is the configuration:
SQLALCHEMY_DATABASE_URI = 'sqlite://///main.db'
SQLALCHEMY_BINDS= {
'table1':'sqlite://///DB1.db',
'table2':'sqlite://///DB2.db',
}
and below is the model:
class table1(db.Model):
__tablename__ = "table1"
__bind_key__='table1'
class table2(db.Model):
__tablename__ = "table2"
__bind_key__='table2'