flask sqlalchemy and update cascade - python

Im writing an inventory app with flask+sqlalchemy, long history made short i have a table called Bill with id, bill_id and bill_date, and the inventory table with id, bill_number, loctation. Then using a queryselectfield the user select the bill_number, fill the others fields and store information in the DB.
but if i update the bill_number in the bill table, need that also the bill_number in the inventory table update all those entries.
I have tried with foreignkey, creating a for statement to update all the entries and nothing works. Also the update method but only works with 'static_values' but with variables got me a literal error.
class Bill(db.Model):
id = db.Column(db.Integer, primary_key=True)
bill_number = db.Column(db.String(64), index=True, unique=True)
bill_date = db.Column(db.Date, index=False, unique=False)
class Location(db.Model):
id = db.Column(db.Integer, primary_key=True)
location_name = db.Column(db.String(64), index=True, unique=True)
class Inventory(db.Model):
id = db.Column(db.Integer, primary_key=True)
serial_number = db.Column(db.String(64), index=True, unique=True)
bill_number = db.Column(db.String(64), db.ForeignKey('bill.bill_number'))
location = db.Column(db.String(64), db.ForeignKey('location.location_name'))
update = Inventory.query.filter(Inventory.bill_number==old_bill).update({ Inventory.bill_number : new_bill})
where old_bill and new_bill comes from a form, if a try with:
Inventory.query.filter(Inventory.bill_number=='666').update({ Inventory.bill_number : '999'})
works like a charm, but i need to use the values from the form, not those static values. Foreignkeys are used but dont know if they really works how in the way that i implemented.
Even tried with:
old = form.old.data
new = form.new.data
all = Inventory.query.filter_by(bill_number=old).all()
for i in all:
i.bill_numer = new
db.session.commit()
but no, cant update the entire inventory table.

Related

'List object has no attribute' when querying 3 tables in database

I'm running a query and filtering results on 3 tables.
I wrote the function below to perform this query, it looked like this:
def bookshelf():
your_user = db.session.query(User).filter_by(email=session['email']).first().uid
your_books = db.session.query(user_book).filter_by(uid=your_user).all()
name_books = db.session.query(Book).filter_by(bid=your_books.bid).all()
return name_books
The variable your_user gets from the table user the id of the user who is logged in;
The variable your_books gets from the table user_books all the books added by the logged in user;
The variable name_books should get from the table books all the data of the books filtered by the id of the books (bid).
The problem occurs when I try to filter using your_books.bid, the console returns:
AttributeError: 'list' object has no attribute 'bid'
These are the tables cited above:
user_book = db.Table('user_book',
db.Column('uid', db.Integer, db.ForeignKey('user.uid'), primary_key=True),
db.Column('bid', db.Text, db.ForeignKey('book.bid'), primary_key=True),
db.Column('date_added', db.DateTime(timezone=True), server_default=db.func.now())
)
class User(db.Model):
__tablename__ = 'user'
uid = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String(25), nullable=False)
hash = db.Column(db.String(), nullable=False)
first_name = db.Column(db.String(30), nullable=True)
last_name = db.Column(db.String(80), nullable=True)
books = db.relationship('Book', secondary=user_book)
class Book(db.Model):
__tablename__ = 'book'
bid = db.Column(db.Text, primary_key=True)
title = db.Column(db.Text, nullable=False)
authors = db.Column(db.Text, nullable=False)
thumbnail = db.Column(db.Text, nullable=True)
users = db.relationship('User', secondary=user_book)
I also tried to do something like your_books = db.session.query(user_book.bid) but I got the same error message.
I also found this answer: Sqlalchemy single query for multiple rows from one column in one table, but I couldn't apply it.
What am I missing?
As I understand it, and following some of the logic, you want to show the books, right? So instead of query(User), use query(Book). Then you can do the .join()as instructed in the comments.
def bookshelf():
your_user = db.session.query(User).filter_by(email=session['email']).first().uid
your_books = db.session.query(Book).join(user_book).filter_by(uid=your_user).all()
return your_books
If you have any questions, let me know and I'll clarify.

How to remove 1 record from a db.Table using Flask_SQLAlchemy?

I have a very simple many-to-many table structure and I'm having problems removing records from the table that makes the association between the other two:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
user_book = db.Table('user_book',
db.Column('uid', db.Integer, db.ForeignKey('user.uid'), primary_key=True),
db.Column('bid', db.Text, db.ForeignKey('book.bid'), primary_key=True),
db.Column('date_added', db.DateTime(timezone=True), server_default=db.func.now())
)
class User(db.Model):
__tablename__ = 'user'
uid = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String(25), nullable=False)
hash = db.Column(db.String(), nullable=False)
first_name = db.Column(db.String(30), nullable=True)
last_name = db.Column(db.String(80), nullable=True)
books = db.relationship('Book', secondary=user_book)
class Book(db.Model):
__tablename__ = 'book'
bid = db.Column(db.Text, primary_key=True)
title = db.Column(db.Text, nullable=False)
authors = db.Column(db.Text, nullable=False)
thumbnail = db.Column(db.Text, nullable=True)
users = db.relationship('User', secondary=user_book)
To make it even clearer, here is an excerpt from the table with some records:
In the function that removes a record I did it this way:
def remove(book_id):
# get the user id (uid)
user_id = db.session.query(User).filter_by(email=session['email']).first().uid
# match the user id with the book id on table 'user_book'
book_rm = db.session.query(user_book).filter_by(uid=user_id, bid=book_id).one()
db.session.delete(book_rm)
db.session.commit()
When I call this function I get the following error on the console:
Class 'sqlalchemy.engine.row.Row' is not mapped
So after some research on Stack and documentation, I tried to do it like this:
db.session.execute(user_book.delete(user_id).where(bid=book_id))
db.session.commit()
And in this case I have received the following:
SQL expression for WHERE/HAVING role expected, got 2.
I really don't know how to go about solving this. I would like to delete only 1 record from the user_book table. Does anyone know how to do this?
Given the a User instance and the Book instance to be deleted from the User's books, the Book can be removed like this:
user_instance.books.remove(book_instance)
db.session.commit()
So the remove function would look like this:
def remove(book_id):
# get the user
user = db.session.query(User).filter_by(email=session['email']).first()
# Find the book by its id
book_rm = Book.query.get(book_id)
user.books.remove(book_rm)
db.session.commit()
See the SQLAlchemy docs for more information.

Flask SQLAlchemy filter by ONE to MANY

My Flask application users enter some data into form which I receive on server:
t_date = request.form['t_date'] #convert to date
t_date = request.form['t_date'] #convert to date
certificate = request.form['certificate'] #name string
skill = request.form['skill'] #name string
...
Then I query needed data with flask-sqlalchemy from MainModel like this:
query = MainModel.query.filter(
((MainModel.from_date >= f_date) &
(MainModel.from_date <= t_date)).self_group() |
((MainModel.to_date >= f_date) &
(MainModel.to_date <= t_date)).self_group()).all()
1. MainModel has MANY to ONE Company(one company can have many)
2. ONE Company has MANY Certificates and MANY Skills
Problem: User wants to enter Certificate, Skill and Dates in the form and find all records under MainModel, but Company related to that record/model must contain Certificate and/or Skill requested.
I tried: to get all records from MainModel only by looping through the mentioned query:
#case where user entered only certificate, but not skill
for qry in query: #all records between selected dates from MainModel
company = Company.query.filter_by(id=qry.company).first() #Company related to MainModel
for item in company.certificates: #Certificates belonging to that company
if item.name == certificate: #comparing user input from form and if company has such
# if all true, put row from MainModel on dict to be returned
Desired: I am not sure if looping is causing any performance issues, but it is making the the complete code a bit messy. So how can I improve the initial query to avoid too many loops? Something like:
query I wrote above + all().filter_by(MainModel.company.certificates.contains(certificate) and .skills.contains(skill)
Update as per comment request:
Models sample:
class MainModel(db.Model):
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
name = db.Column(db.String(50), nullable=False)
company = db.Column(db.Integer, db.ForeignKey('company.id'), nullable=False)
class Company(db.Model):
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
name = db.Column(db.String(50), nullable=False)
certificates = db.relationship('Certificate',
secondary=certif_company,
backref=db.backref('company',
lazy='dynamic'))
class Certificate(db.Model):
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
name = db.Column(db.String(50), nullable=False)
certif_company = db.Table('certif_company',
db.Column('certificate_id', db.Integer, db.ForeignKey('certificate.id'), primary_key=True),
db.Column('company_id', db.Integer, db.ForeignKey('company.id'), primary_key=True)
)

Stuck with Flask-Sqlalchemy Relationship system

I want to create database, that consist user info(sqlite db)
class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
login = db.Column(db.String(10), unique = True)
email = db.Column(db.String(20), unique = True)
psw = db.Column(db.String(500), nullable=True)
def __repr__(self):
return f"<User {self.id}>"
This is what i already did.
I want to create fields upcoming_friends, incoming_friends, friends, i think that i need to create a new class that will extends user , but I did not find the documentation and don't understand how to do it.
The User table stores the information that you need about a particular user. If you want to find out what friends this user might have in your application, then you can create another table called Friends.
class Friend(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
upcoming_friends = db.Column(db.String(64), unique = True)
incoming_friends = db.Column(db.String(64), unique = True)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
def __repr__(self):
return f"<Friends: {self.id}>"
To create a relationship between these two database structures, we will do as follows:
class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
login = db.Column(db.String(10), unique = True)
email = db.Column(db.String(20), unique = True)
friends = db.relationship('Friend', backref='<give-a-reference>', lazy='dynamic')
def __repr__(self):
return f"<User {self.id}>"
The user_id field was initialized as a foreign key to user.id, which means that it references an id value from the user's table. In this reference the user part is the name of the database table for the model.
There is a bit of inconsistency when it comes to referring to the user table in db.ForeignKey. Here, you can see that the user table starts with a lower case, whereas when it comes to referencing Friend table in db.relationship we begin with an upper case.

SQLAlchemy multiple joins to single table

I am making a wishlist app and I want to have db schema like bellow, but I can't figure out how to make the joins in sqlalchemy (this is the first time I am using sqlalchemy).
DB schema
(user : wish = 1 : N)
When I select a user, I want to get a list of wishes and each wish may contain a different user (an arranger of the wish)
So I could do something like this
first_user = User.query.get(1)
user_wishes = first_user.wishes.all()
for wish in user_wishes:
if wish.arranger is not None:
print(wish.id, wish.owner.id, wish.arranger.id)
else:
print(wish.id, wish.owner.id)
I have looked up some tutorials, but I only found simple relations.
I need a relation from User to Wish and in the Wish, back to both the UserWishOwner (the user from which I got here) a UserWishArranger (if there is any).
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
wishes = db.Column(db.relationship('Wish', backref='owner', lazy='dynamic'))
class Wish(db.Model):
id = db.Column(db.Integer, primary_key=True)
owner_id = db.Column(db.Integer, db.ForeignKey('user.id'), index=True)
arranger_id = db.Column(db.Integer, db.ForeignKey('user.id'), index=True)
arranger = relationship("User", foreign_keys=[arranger_id])
I have come up with some code, but am a bit confused, because owner_id and arranger_id are the same...
What do I need to do, to make this work?
Just like this
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
wishes = db.relationship('Wish', backref='owner', lazy='dynamic', foreign_keys="[Wish.owner_id]")
class Wish(db.Model):
id = db.Column(db.Integer, primary_key=True)
owner_id = db.Column(db.Integer, db.ForeignKey('user.id'), index=True)
arranger_id = db.Column(db.Integer, db.ForeignKey('user.id'), index=True)
arranger = db.relationship("User", foreign_keys=[arranger_id])

Categories

Resources