SQLAlchemy many-many assoc table not populating - python

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?

Related

SQLALchemy, Flask, Python, code adds model object only once to database (PostgreSQL)

My database looks like this:
CREATE TYPE APP_ROLE AS ENUM ('admin', 'user');
CREATE TABLE IF NOT EXISTS users (
user_id SERIAL PRIMARY KEY,
login VARCHAR ( 50 ) UNIQUE NOT NULL,
password_hash TEXT NOT NULL,
role APP_ROLE NOT NULL
);
I wrote a simple Flask/SQLAlchemy/Python code to test inserting to db. However, it seems that my object is added only once, because no matter how many time I run the script (python3 testdb.py) it shows that there's only one user in db. What Im doing wrong?
#!/usr/bin/env python3
import os
from flask import Flask, render_template, request, url_for, redirect
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy import inspect
from sqlalchemy import create_engine
from sqlalchemy import Enum
from werkzeug.security import generate_password_hash
basedir = os.path.abspath(os.path.dirname(__file__))
class Config(object):
DEBUG = False
TESTING = False
CSRF_ENABLED = True
SQLALCHEMY_TRACK_MODIFICATIONS = False
SQLALCHEMY_DATABASE_URI = "postgresql://brian:1234#127.0.0.1:5432/example_db"
app = Flask(__name__)
app.config.from_object(Config)
db = SQLAlchemy(app)
class Users(db.Model):
__tablename__ = 'users'
user_id = db.Column(db.Integer, primary_key=True)
login = db.Column(db.String(50), unique=True)
password_hash = db.Column(db.String(128))
role = db.Column(Enum("admin", "user", name="app_role", create_type=False))
def __init__(self, login, password_hash, role):
self.login = login
self.password_hash = password_hash
self.role = role
#property
def password(self):
raise AttributeError('Password is not a readable attribute')
#password.setter
def password(self, password):
self.password_hash = generate_password_hash(password)
def to_json(self):
pass
def is_administrator(self):
pass
if __name__ == '__main__':
u1 = Users('brian', '2345643245', 'admin')
db.create_all()
db.session.add(u1)
db.session.add(u1)
db.session.add(u1)
db.session.flush()
users1 = Users.query.all()
for user in users1:
print(user.login, user.password_hash, user.role)
You are entering 3 times a record that has the exact same value for a field defined as UNIQUE. This is not allowed to do it at the database level, try to enter 3 different users with 3 different values ​​for the login field.

Flask relationships with sql alschemy - no such table error

I'm working through a flask relationships tutorial. I'm trying to make a database that stores puppies, information about their toys, and information about their owners, showing in
basic.py:
# basic.py
import os
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
basedir = os.path.abspath(os.path.dirname(__file__))
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///'+os.path.join(basedir, 'data.sqlite')
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
Migrate(app, db)
class Puppy(db.Model):
__tablename__ = 'puppies'
id = db.Column(db.Integer, primary_key = True)
name = db.Column(db.Text)
toys = db.relationship('Toy', backref = 'puppy', lazy = 'dynamic')
owner = db.relationship('Owner', backref = 'puppy', uselist = False)
def __init__(self, name):
self.name = name
def __repr__(self):
if self.owner:
return "Puppy name is {self.name} and owner is {self.owner}"
else:
return "Puppy is {self.name} and has no owner yet"
def report_toys(self):
print("Here are my toys:")
for toy in self.toys:
print(toy.item_name)
class Toy(db.Model):
__tablename__ = 'toys'
id = db.Column(db.Integer, primary_key = True)
item_name = db.Column(db.Text)
puppy_id = db.Column(db.Integer, db.ForeignKey('puppies.id'))
def __init__(self, item_name, puppy_id):
self.item_name = item_name
self.puppy_id = puppy_id
class Owner(db.Model):
__tablename__ = 'owners'
id = db.Column(db.Integer, primary_key = True)
name = db.Column(db.Text)
puppy_id = db.Column(db.Integer, db.ForeignKey('puppies.id'))
def __init__(self, name, puppy_id):
self.name = name
self.puppy_id = puppy_id
I then set up a manual database in models.py:
# models.py
from basic import db, Puppy, Owner, Toy
rufus = Puppy('Rufus')
fido = Puppy('Fido')
db.session.add_all([rufus, fido])
db.session.commit
rufus = Puppy.query.filter_by(name = 'Rufus').first()
kate = Owner('Kate', rufus.id)
toy1 = Toy('Chew Toy', rufus.id)
toy2 = Toy('Ball', rufus.id)
db.session.add_all([kate, toy1, toy2])
db.session.commit()
But I'm getting an error:
cursor.execute(statement, parameters)
sqlalchemy.exc.OperationalError: (raised as a result of Query-invoked autoflush; consider using a session.no_autoflush block if this flush is occurring prematurely)
(sqlite3.OperationalError) no such table: puppies
[SQL: INSERT INTO puppies (name) VALUES (?)]
[parameters: ('Rufus',)]
(Background on this error at: http://sqlalche.me/e/13/e3q8)
I'm new to this, so any help would be appreciated.
did you create the database ?
you need to import your db object and models and then create the database like following:
(venv) $ flask shell
>>> from basic import db
>>> from basic import Puppy, Toy, Owner
>>> db.create_all()
let me know if this solves your problem
The error message shows no table of puppies in your database. To apply migrations to your database, you need some steps while using flask-migrate.
The link would be helpful https://flask-migrate.readthedocs.io/en/latest/
Because you are using flask_migrate you need to open a terminal, be sure to be in the same working directory of your project and run these commands:
This you need to run it before you run the actual Flask App
CMD with in the envirorments folder:
>>> set FLASK_APP= app.py (optional)
>>> flask db init
>>> flask db migrate -m 'Any name you want' ---> what's inside the '' is the name of migrati
>>> flask db upgrade (perform the actual migration)
Normally if you don't use flask_migrate but only flask_sqlalchemy or SQLAlchemy vanilla, this is what you should run.
CMD with in the envirorments folder:
>>> from app import db
>>> db.create_all()
>>> exit() #or ctrl + z then enter
EDIT
Everytime you are adding something (or removing) from the DB Tables of instance:
class Puppy(db.Model):
__tablename__ = 'puppies'
id = db.Column(db.Integer, primary_key = True)
name = db.Column(db.Text)
toys = db.relationship('Toy', backref = 'puppy', lazy = 'dynamic')
owner = db.relationship('Owner', backref = 'puppy', uselist = False)
Becomes --->
class Puppy(db.Model):
__tablename__ = 'puppies'
id = db.Column(db.Integer, primary_key = True)
name = db.Column(db.Text)
age = db.Column(db.Integer, nullable=False)#Added new item
toys = db.relationship('Toy', backref = 'puppy', lazy = 'dynamic')
owner = db.relationship('Owner', backref = 'puppy', uselist = False)
Then you should delete the database file, in your case 'data.sqlite' (within your working directory) and run the above mentioned code again,
In fact by running the above code, you create database table but also the actual sqlite file

No result using the .first() method

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)

get column names from variables sqlite python3 sqlalchemy

I want to store the details stored in x variable to the sqlite database using flask sqlalchemy. How to make it possible.
Here's the code i wrote:
from flask import Flask
from flask_httpauth import HTTPBasicAuth
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/u.db'
db = SQLAlchemy(app)
class User(db.Model) :
x = ['username = "sam"', 'password = "sam123"']
u1 = (x[0].split()[0])
p1 = (x[1].split()[0])
print(u1,p1)
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key = True)
u1 = db.Column(db.String(32), index = True)
p1 = db.Column(db.String(128))
if __name__ == '__main__':
db.create_all()
print("db created")
app.run(host='0.0.0.0', port=5001)
table created in sqlite:
id u1 p1
Required table to be created in sqlite and data to be loaded:
id username password
1 sam sam123
Your table needs to define the columns with the names that you want:
class User(db.Model) :
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key = True)
username = db.Column(db.String(32), index = True)
password = db.Column(db.String(128))
You can make function to extract the username and password from x:
def get_user_data(data):
user_data = []
for item in data:
part = item.partition(' = ')[2]
cleaned = part.replace('"', '')
user_data.append(cleaned)
return user_data
And create a User instance like this:
username, password = get_user_data(x)
user = User(username=username, password=password)

Update not commited on mysql server flask-sqlalchemy

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):
...

Categories