How to get data from two tables using SQLALCHEMY - python

Let say I have a model
import os
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
class Students(db.Model):
__tablename__ = "students"
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String, nullable=False)
description = db.Column(db.String, nullable=False)
class Hobbies(db.Model):
__tablename__ = "hobbies"
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String, nullable=False)
description = db.Column(db.String)
student_id = db.Column(db.Integer, db.ForeignKey("students.id"), nullable=False)
Now in flask I have following code
import os
from flask import Flask, render_template, request
from models import *
app = Flask(__name__)
app.config["SQLALCHEMY_DATABASE_URI"] = "postgresql://junaid:junaid#localhost:5432/UOB"
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
db.init_app(app)
Now I get all the record in the table Hobbies
from sqlalchemy.sql import select
with app.app_context():
a = Hobbies.query.all()
I want to get the result like
Hobby.ID, Hobby.title, Hobby.description, Student.name (The filter is Hobby.student_id = Students.id)
I want to print all the record in the hobbies table with student name in short.

Here is the solution. Sharing if someone else can benefit from this.
hobbies_with_stud = db.session.query(Students, Hobbies).join(Hobbies, Hobbies.student_id == Students.id).all()
for record in hobbies_with_stud:
print(record.Hobbies.title + " is the hobby of "+ record.Students.name)

Related

Empty Json using Flask-Marshmallow and SQLAlchemy

I am trying to create a endpoint to return data from two tables indicator and metadata so I created the model below with indicator = db.relationship('Indicator', backref='metadatas') and indicator_id = db.Column(db.Integer, db.ForeignKey('indicator.id')) but when I call the api/indicators I get empty json as you can see at the end, why?
models.py
from datetime import datetime
from app import db, ma
class Indicator(db.Model):
id = db.Column(db.Integer, primary_key=True)
unique_key = db.Column(db.String(32))
name = db.Column(db.String(255))
short_name = db.Column(db.String(255))
valid = db.Column(db.Boolean)
created_at = db.Column(db.DateTime())
last_updated_at = db.Column(db.DateTime())
class Metadata(db.Model):
id = db.Column(db.Integer, primary_key=True)
indicator_id = db.Column(db.Integer, db.ForeignKey('indicator.id'))
indicator = db.relationship('Indicator', backref='metadatas')
type = db.Column(db.String(255))
inputs = db.Column(db.String(255))
options = db.Column(db.String(255))
outputs = db.Column(db.String(255))
class IndicatorSchema(ma.SQLAlchemySchema):
class Meta:
model = Indicator
id: ma.auto_field()
unique_key: ma.auto_field()
name: ma.auto_field()
short_name: ma.auto_field()
valid: ma.auto_field()
class MetadataSchema(ma.SQLAlchemyAutoSchema):
class Meta:
model = Metadata
include_fk = True
Below you can see the other files:
app.py
from flask_jwt_extended import JWTManager
from flask import Flask, jsonify, request
from flask_sqlalchemy import SQLAlchemy
from flask_marshmallow import Marshmallow
app = Flask(__name__)
app.config["JWT_SECRET_KEY"] = "fe7e8955db51c0ff78550419434128cb"
app.config["JWT_ACCESS_TOKEN_EXPIRES "] = 28800
app.config['SQLALCHEMY_DATABASE_URI'] = "sqlite:////tmp/test.db"
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
app.config['JSON_SORT_KEYS'] = False
db = SQLAlchemy(app)
ma = Marshmallow(app)
controller.py
from flask_jwt_extended import jwt_required, create_access_token, get_jwt_identity
from flask import Flask, request, jsonify
from models import Indicator, Metadata, IndicatorSchema, MetadataSchema
from config import conn_string
from app import app, db
import services
import hashlib
import json
#app.route('/api/indicators', methods=['GET'])
#jwt_required()
def indicators():
short_name = request.args.get('short_name',None)
if short_name is not None:
indicator = Indicator.query.filter_by(short_name = short_name).first()
indicator_schema = IndicatorSchema()
output = indicator_schema.dump(indicator)
else:
indicators = Indicator.query.all()
indicators_schema = IndicatorSchema(many=True)
output = indicators_schema.dump(indicators)
return jsonify(output), 200
When I call the /api/indicators I get response 200 but empty JSON:
$ http :5000/api/indicators
HTTP/1.0
Content-Type: application/json
Server: Werkzeug/2.0.0 Python/3.8.5
[
{},
{},
{},
{},
{},
{}
]
I think there are two issues:
You should be defining the relationship on the Indicator model (one indicator with many metadatas)
I believe you're looking for the meta attribute include_relationships, since you're looking to return more than just the foreign key ids
Your code with the adjustments:
from datetime import datetime
from app import db, ma
class Indicator(db.Model):
__tablename__ = "indicator"
id = db.Column(db.Integer, primary_key=True)
unique_key = db.Column(db.String(32))
name = db.Column(db.String(255))
short_name = db.Column(db.String(255))
valid = db.Column(db.Boolean)
created_at = db.Column(db.DateTime())
last_updated_at = db.Column(db.DateTime())
metadatas = db.relationship('Metadata', backref='indicator')
class Metadata(db.Model):
__tablename__ = "metadata"
id = db.Column(db.Integer, primary_key=True)
indicator_id = db.Column(db.Integer, db.ForeignKey('indicator.id'))
type = db.Column(db.String(255))
inputs = db.Column(db.String(255))
options = db.Column(db.String(255))
outputs = db.Column(db.String(255))
class IndicatorSchema(ma.SQLAlchemyAutoSchema):
class Meta:
model = Indicator
include_relationships = True
id: ma.auto_field()
unique_key: ma.auto_field()
name: ma.auto_field()
short_name: ma.auto_field()
valid: ma.auto_field()
class MetadataSchema(ma.SQLAlchemyAutoSchema):
class Meta:
model = Metadata

SQLAlchemy model how to simulate PostgreSQL "SERIAL" datatype

so as the problem says, I want to set up a SERIAL column's counterpart in my SQLAlchemy model. Can anyone help me?
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
class Review(db.Model):
__tablename__ = "reviews"
id = db.Column(db.INTEGER,(???), primary_key=True)
name = db.Column(db.VARCHAR, db.ForeignKey("users.username"))
bookisbn = db.Column(db.CHAR(10), db.ForeignKey("books.isbn"))
review = db.Column(db.VARCHAR, nullable=False)
rating = db.Column(db.INTEGER, nullable=False)

How to query with many tables

from flask import Flask, render_template
from flask_sqlalchemy import SQLAlchemy
#import sqlite3 as sql
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://ahmad:ahmad#192.168.3.103/utama'
db = SQLAlchemy(app)
class ak(db.Model):
__tablename__ = 'ak'
id = db.Column(db.Integer, primary_key=True)
nama = db.Column(db.String)
alamat = db.Column(db.String)
akreditasi = db.Column(db.String)
def __init__(self, id, nama, alamat, akreditasi):
self.id = id
self.city = nama
self.alamat = alamat
self.akreditasi = akreditasi
class av(db.Model):
__tablename__ = 'av'
id = db.Column(db.Integer, primary_key=True)
nama = db.Column(db.String)
alamat = db.Column(db.String)
akreditasi = db.Column(db.String)
def __init__(self, id, nama, alamat, akreditasi):
self.id = id
self.city = nama
self.alamat = alamat
self.akreditasi = akreditasi
id_jurusan = db.Table('id_jurusan',
db.Column('id', db.Integer, db.ForeignKey('ak.id')),
db.Column('id', db.Integer, db.ForeignKey('av.id'))
)
#app.route('/ak')
def jurusan(jurusan):
return render_template('index.html', rows=ak.query.all() )
#app.route('/av')
def Akuntansi():
return render_template('index.html', rows=av.query.all() )
if __name__ == '__main__':
app.run(debug=True, host='1.1.1.1', port=80)
I am a new to learn python, in this case I studied the framework flask and I had trouble on the declaration SQLAlchemy, precisely displays the contents of the table but with the same structure,when executed will be like this.....
[
which one success
You are using the decorator
#app.route('/av')
The method which succeeds Akuntansi() does not require a parameter. So this works. The method which fails expects a parameter jurusan(jurusan) but your decorator #app.route('/ak') does not consider this.
To pass a parameter you need to use the decorator like this:
#app.route("/ak/<jurusan>") and then also pass the parameter in the request.

How to query multiple items using Flask SQLAlchemy

After importing the modules:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
and declaring app and db objects:
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///test.db'
db = SQLAlchemy(app)
I go ahead and create two tables: User and Email:
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(50))
addresses = db.relationship('Email', backref='person', lazy='dynamic')
class Email(db.Model):
id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String(50))
person_id = db.Column(db.Integer, db.ForeignKey('user.id'))
With db.relationship in place I can now link some multiple emails to the same user. First I create two email addresses:
first_email = Email(email='first#email.com')
second_email = Email(email='second#email.com')
Then I am passing these two emails to User class at the time it is being created:
user = User(name='User Name', addresses = [first_email, second_email])
To see which user is linked to which email I can simply use:
print first_email.person
print user.addresses.all()
Now I want to add another third email to the same user. How do I append a new email to the list of the emails that have been already linked to the user?
new_email = Email(email='new_email#example.com')
user.addresses.append(new_email)
db.session.commit()
This will append the email address to the relationship.
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///inquestion.db'
db = SQLAlchemy(app)
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(50))
addresses = db.relationship('Email', backref='person', lazy='dynamic')
def add_email(self, new_email):
linked_emails = [email.email for email in self.addresses.all()]
if not new_email in linked_emails:
linked_emails.append(new_email)
self.addresses = [Email.find_or_create(email) for email in linked_emails]
class Email(db.Model):
id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String(50))
person_id = db.Column(db.Integer, db.ForeignKey('user.id'))
#staticmethod
def find_or_create(email):
try:
return Email.query.filter_by(email=email).one()
except:
new_email = Email(email=email)
db.session.add(new_email)
db.session.commit()
return new_email
first_email = Email(email='first#email.com')
second_email = Email(email='second#email.com')
user = User(name='User Name', addresses = [first_email, second_email])
db.drop_all()
db.create_all()
db.session.add(first_email)
db.session.add(second_email)
db.session.add(user)
db.session.commit()
# some extra queries
user.add_email('third#email.com')
print user.addresses.all()
print Email.find_or_create('fourth#email.com')
print Email.query.filter_by(email='fourth#email.com').one().email
print first_email.query.filter_by(email='second#email.com').one()

understanding marshmallow nested schema with list data

Am new to python and am usign marshmallow serialization. unable to use the nested scehma.
, my code
from sqlalchemy import Column, Float, Integer, String, Text, text,ForeignKey
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship
Base = declarative_base()
metadata = Base.metadata
class CompanyDemo(Base):
__tablename__ = 'company_demo'
company_id = Column(Integer, primary_key=True,
server_default=text("nextval('company_demo_company_id_seq'::regclass)"))
name = Column(Text, nullable=False)
address = Column(String(50))
location = Column(String(50))
class UsersDemo(Base):
__tablename__ = 'users_demo'
id = Column(Integer, primary_key=True,
server_default=text("nextval('users_demo_id_seq'::regclass)"))
company_id = Column(Integer,ForeignKey('company_demo.company_id'), nullable=False)
email = Column(String)
company = relationship('CompanyDemo')
schema
from marshmallow import Schema, fields, pprint
class CompanySchema(Schema):
company_id = fields.Int(dump_only=True)
name = fields.Str()
address = fields.Str()
location = fields.Str()
class UserSchema(Schema):
email = fields.Str()
company = fields.Nested(CompanySchema)
user = UserSchema()
user = UserSchema(many=True)
company = CompanySchema()
company = CompanySchema(many=True)
and my flask app
from flask import Flask, jsonify, url_for, render_template
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from flask_sqlalchemy import SQLAlchemy
from model import CompanyDemo, UsersDemo
from schemas.userschema import user, company
app = Flask(__name__)
app.secret_key = "shiva"
def db_connect():
engine = create_engine('postgresql://ss#127.0.0.1:5432/test')
Session = sessionmaker(autocommit=False, autoflush=False, bind=engine)
# create a Session
session = Session()
session._model_changes = {}
return session
#app.route('/company', methods=["GET", "POST"])
def get_all_company():
db = db_connect()
allcompany = db.query(CompanyDemo).join(UsersDemo).all()
return jsonify(company.dump(allcompany, many=True).data) # company is marshmallow schema
if __name__ == '__main__':
app.run(host='0.0.0.0', port=15418, debug=True)
anything wrong in my code? and am facing problem with nested schema and unable to get the nested data in output.
the output below
[ {
"address": "qqq ",
"company_id": 1,
"location": "www ",
"name": "eee" }, {
"address": "www ",
"company_id": 2,
"location": "qqq ",
"name": "aaa" } ]
Self contained example using in-memory SQLite:
from flask import Flask, jsonify
from flask_sqlalchemy import SQLAlchemy
from marshmallow import Schema, fields, pprint
app = Flask(__name__)
app.config['DEBUG'] = True
app.config['SECRET_KEY'] = 'super-secret'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///:memory:'
app.config['SQLALCHEMY_ECHO'] = True
db = SQLAlchemy(app)
class CompanyDemo(db.Model):
__tablename__ = 'company_demo'
company_id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.Text, nullable=False)
address = db.Column(db.String(50))
location = db.Column(db.String(50))
def __unicode__(self):
return u"{name} ({address})".format(name=self.name, address=self.address)
class UsersDemo(db.Model):
__tablename__ = 'users_demo'
id = db.Column(db.Integer, primary_key=True,)
company_id = db.Column(db.Integer, db.ForeignKey('company_demo.company_id'), nullable=False)
company = db.relationship('CompanyDemo')
email = db.Column(db.String)
def __unicode__(self):
return u"{email}".format(email=self.email)
class CompanySchema(Schema):
company_id = fields.Int(dump_only=True)
name = fields.Str()
address = fields.Str()
location = fields.Str()
class UserSchema(Schema):
email = fields.Str()
company = fields.Nested(CompanySchema)
user_schema = UserSchema()
company_schema = CompanySchema()
#app.route('/')
def index():
return "<a href='/dump_company'>Dump Company</a><br><a href='/dump_user'>Dump User</a>"
#app.route('/dump_user')
def dump_user():
user = UsersDemo.query.first()
return jsonify(user_schema.dump(user).data)
#app.route('/dump_company')
def dump_company():
company = CompanyDemo.query.first()
return jsonify(company_schema.dump(company).data)
def build_db():
db.drop_all()
db.create_all()
company = CompanyDemo(name='Test 1', address='10 Downing Street', location='wherever')
db.session.add(company)
user = UsersDemo(email='fred#example.com', company=company)
db.session.add(user)
db.session.commit()
#app.before_first_request
def first_request():
build_db()
if __name__ == '__main__':
app.run(debug=True, port=7777)

Categories