store Json field in an external file (.json) by python - postgresql

my table in postgresql v11 contains a json field, i would to store this data in an external file JSON using python (lib: SQLALSHEMY). i try to do it but i have a difficulty:
import psycopg2
from app import db
from models import Geotab
from sqlalchemy.dialects.postgresql import JSON
from sqlalchemy.sql import select
try:
connection = psycopg2.connect(user = "postgres",
password = "admin",
host = "127.0.0.1",
port = "5432",
database = "catalogue")
cursor = connection.cursor()
# Print PostgreSQL Connection properties
print ( connection.get_dsn_parameters(),"\n")
# Print PostgreSQL version
cursor.execute("SELECT version();")
record = cursor.fetchone()
print("You are connected to - ", record,"\n")
except (Exception, psycopg2.Error) as error :
print ("Error while connecting to PostgreSQL", error)
data=db.session.query(Geotab).\
filter(Geotab.dataJson['']) #.astext.cast(JSON))
print (data)
after executing code:
user=postgres password=admin host=127.0.0.1 port=5432 dbname=catalogue
{'user': 'postgres', 'dbname': 'catalogue', 'host': '127.0.0.1', 'port': '5432', 'tty': '', 'options': '', 'sslmode': 'prefer', 'sslcompression': '0', 'krbsrvname': 'postgres', 'target_session_attrs': 'any'}
You are connected to - ('PostgreSQL 11.4, compiled by Visual C++ build 1914,
64-bit',)
SELECT geocat.id AS geocat_id, geocat.url AS geocat_url, geocat.date AS
geocat_date, geocat."dataJson" AS "geocat_dataJson"
FROM geocat
WHERE geocat."dataJson" -> %(dataJson_1)s
geotab : class in models.py
dataJson : column type json
table name: geocat
help me please

i find the solution, thank you:
from sqlalchemy import create_engine
from app import db
from models import Geotab
from sqlalchemy import Integer
import json
from sqlalchemy.dialects.postgresql import JSON
engine = create_engine('postgresql://postgres:admin#127.0.0.1:5432/catalogue', echo =
True)
conn = engine.connect()
data=db.session.query(Geotab).\
filter(Geotab.id==1)
print (data)
result = db.session.query(Geotab).all()
metadata={}
for row in result:
print ("dataJson:",row.dataJson)
metadata=row.dataJson
with open('metadata.json', 'w') as outfile:
json.dump(metadata, outfile)

Related

sqlalchemy connect to databasename with whitespace

I'm trying to connect to a postgres-DB, which unfortunately has a name with a whitespace in it:
%load_ext sql
from sqlalchemy import create_engine
%sql postgresql://postgres:dbpass#localhost/Test DB
(psycopg2.OperationalError) FATAL: database "Test DB" does not exist
I've tried to follow some tipps on the internet and used:
import urllib.parse
urllib.parse.quote_plus("Test DB")
which simply results in a string "Test+DB" (this does not work).
How can I adress the database, without changing its name?
Best regards!
I was able to solve it by using sqlalchemy's create_engine(), therefore being able to simply save the string (with its whitespace) as a variable (eg database_name):
import sqlalchemy as db
database_name = 'Test DB'
engine = db.create_engine('postgresql://' + 'user_name' + ':' + 'password' + '#localhost/' + database_name)
connection = engine.connect()
s = 'SELECT id FROM user'
df = pd.read_sql_query(s, engine)
df.head()
Hope it helps, best regards.

Inserting JSON into postgresql from Flask-Sql Alchemy

I want to insert JSON type of data in PostgreSQL Database from flask
eg: {"a":[1,2,3] , "b":[1,2,3]}
One example for such data is Phone.no and Childrens, One person can have multiple ph.no and Childrens
In flask View
#app.route('/add', methods=['POST'])
def addRex():
Name = request.form[‘name’]
data = request.get_json(force=False, silent=False, cache=True)
p = Projects(name=name,data = data)
db.session.add(p)
db.session.commit()
In HTTP post method
def addData():
name = input ('Enter Name :')
data = input('Enter Data :')
headers = {'Content-type': 'application/json', 'Accept': 'text/plain'}
r = requests.post(localhost:5000/add,
data ={'name':name}, json={'data':data})
if (r.status_code == 200):print(' Added Successfully!!') else:print('Already exists!')
How can I insert such kind of data from flask into postgresql.
if Anyone can help me with my problem.
Thanks in advance
From sqlalchemy dialect, you can select JSON for Postgres. Here is an example,
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy.dialects.postgresql import JSON
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgres://username:password#localhost:5432/db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
db = SQLAlchemy(app)
class Person(db.Model):
person_name = db.Column(db.Text, primary_key=True)
details = db.Column(JSON)
# db.create_all() ==> for creating the db
per_1 = Person(person_name='Batman', details={"phone_no": [5, 6, 7, 8, 9], "children": {"son": [
"Dick Grayson", "Jason Todd", "Damian Wayne", "Tim Drake"], "daughter": ['Helena Wayne']}})
db.session.add(per_1)
db.session.commit()

Generate SQLite database in Flask REST API code

I am new to REST API and starting building first REST API app using Flask, SQLAlchemy & Marshmallow. This is my app.py file:
from flask import Flask, request, jsonify
from flask_sqlalchemy import SQLAlchemy
from flask_marshmallow import Marshmallow
import os
# Initialize App
app = Flask(__name__)
basedir = os.path.abspath(os.path.dirname(__file__))
# Database Setup
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + os.path.join(basedir, 'db.sqlite')
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
# Init db
db = SQLAlchemy(app)
# Init marshmallow
ma = Marshmallow(app)
# Product Class/Model
class Product(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(100), unique=True)
description = db.Column(db.String(200))
price = db.Column(db.Float)
qty = db.Column(db.Integer)
def __init__(self, name, description, price, qty):
self.name = name
self.description = description
self.price = price
self.qty = qty
# Product Schema
class ProductSchema(ma.Schema):
class Meta:
fields = ('id', 'name', 'description', 'price', 'qty')
# Init Schema
product_schema = ProductSchema()
products_schema = ProductSchema(many=True)
# Create Product
#app.route('/product', methods=['POST'])
def add_product():
name = request.json['name']
description = request.json['description']
price = request.json['price']
qty = request.json['qty']
new_product = Product(name, description, price, qty)
db.session.add(new_product)
db.session.commit()
return product_schema.jsonify(new_product)
# Get All Products
#app.route('/receive', methods=['GET'])
def get_products():
all_products = Product.query.all()
result = products_schema.dump(all_products)
return jsonify(result)
# Run the Server
if __name__ == '__main__':
app.run(debug=True)
For generating SQLite database, I have to open python interactive shell and then there I have to do this:
from app import db
db.create_all()
But I have to genreate database from app.py itself so I am inserting the same commands inside app.py, but it's giving me error:
OperationalError: (sqlite3.OperationalError) no such table: product
How do I generate a database from app.py?
Where are you placing your db.create_all()? The error may simply be a result of placement. When I copy and paste your code into PyCharm (running Python 3.7) it creates the DB fine when I place
db.create_all()
immediately before
# Run the Server
if __name__ == '__main__':
app.run(debug=True)
If you try to run db.create_all() before you instantiate the db object it will throw an error because db does not exist yet.
You should not need to use "from app import db" at all because the db object is declared up top.

flask-sqlalchemy-postgres db insert failing

I am using Flask with SQLAlchemy and PostGresDB and getting this error on an insert;
sqlalchemy.exc.ProgrammingError: (psycopg2.ProgrammingError) can't adapt type 'dict'
[SQL: 'SELECT results.id AS results_id,......]
models.py is as follows (just the ORM)
class Result(db.Model):
__tablename__ = 'results'
id = db.Column(db.Integer, primary_key=True)
url = db.Column(db.String())
cities = db.Column(JSON)
states = db.Column(JSON)
app.py for the insert part is;
import os
from flask import Flask, render_template, request, jsonify
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config.from_object(os.environ['APP_SETTINGS'])
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
db = SQLAlchemy(app)
frequency_cities = Counter(city_pop) # dict object
frequency_states = Counter(state_pop) # dict object
try:
from models import Result
result = Result(
url= url,
cities=frequency_cities,
states=frequency_states
)
db.session.add(result)
db.session.commit()
return result.id
except:
errors.append("Unable to add item to database.")
return {"error": errors}
I am at a loss.

Alembic autogenerate does not generate upgrade script

I am using sqlalchemy and postgressql in Flask application. The migration tool that I am using is alembic=0.6.3.
if I type alembic current it shows me:
Current revision for postgres://localhost/myDb: None
which is correct database connection. But when I run alembic revision --autogenerate -m 'Add user table' it generates the default alembic template without any sql commands in it. Like:
"""Add user table
Revision ID: 59b6d3503442
Revises: None
Create Date: 2015-04-06 13:42:24.540005
"""
# revision identifiers, used by Alembic.
revision = '59b6d3503442'
down_revision = None
from alembic import op
import sqlalchemy as sa
def upgrade():
### commands auto generated by Alembic - please adjust! ###
pass
### end Alembic commands ###
def downgrade():
### commands auto generated by Alembic - please adjust! ###
pass
### end Alembic commands ###
I couldn't find any proper solution in SO.
Here is my env.py:
from __future__ import with_statement
from logging.config import fileConfig
import os
import sys
import warnings
from alembic import context
from sqlalchemy import create_engine, pool
from sqlalchemy.exc import SAWarning
ROOT = os.path.abspath(
os.path.join(os.path.dirname(__file__), os.pardir, os.pardir)
)
sys.path.append(ROOT)
from myApp import Application
from myApp.extensions import db
# Don't raise exception on `SAWarning`s. For example, if Alembic does
# not recognize some column types when autogenerating migrations,
# Alembic would otherwise crash with SAWarning.
warnings.simplefilter('ignore', SAWarning)
app = Application()
# this is the Alembic Config object, which provides
# access to the values within the .ini file in use.
config = context.config
# Interpret the config file for Python logging.
# This line sets up loggers basically.
fileConfig(config.config_file_name)
target_metadata = db.metadata
def run_migrations_offline():
"""Run migrations in 'offline' mode.
This configures the context with just a URL
and not an Engine, though an Engine is acceptable
here as well. By skipping the Engine creation
we don't even need a DBAPI to be available.
Calls to context.execute() here emit the given string to the
script output.
"""
url = app.config['SQLALCHEMY_DATABASE_URI']
context.configure(url=url)
with context.begin_transaction():
context.run_migrations()
def run_migrations_online():
"""Run migrations in 'online' mode.
In this scenario we need to create an Engine
and associate a connection with the context.
"""
url = app.config['SQLALCHEMY_DATABASE_URI']
engine = create_engine(url, poolclass=pool.NullPool)
connection = engine.connect()
context.configure(
connection=connection,
target_metadata=target_metadata
)
try:
with context.begin_transaction():
context.run_migrations()
finally:
connection.close()
if context.is_offline_mode():
run_migrations_offline()
else:
run_migrations_online()
and this is my alembic.ini:
# A generic, single database configuration.
[alembic]
# path to migration scripts
script_location = myApp/migrations
# template used to generate migration files
# file_template = %%(rev)s_%%(slug)s
# Logging configuration
[loggers]
keys = root,sqlalchemy,alembic
[handlers]
keys = console
[formatters]
keys = generic
[logger_root]
level = WARN
handlers = console
qualname =
[logger_sqlalchemy]
level = WARN
handlers =
qualname = sqlalchemy.engine
[logger_alembic]
level = INFO
handlers =
qualname = alembic
[handler_console]
class = StreamHandler
args = (sys.stderr,)
level = NOTSET
formatter = generic
[formatter_generic]
format = %(levelname)-5.5s [%(name)s] %(message)s
datefmt = %H:%M:%S
Addition files for more information
This is the extensions.py file from where I import db for metadata:
from flask.ext.sqlalchemy import SQLAlchemy
from raven.contrib.flask import Sentry
from sqlalchemy_utils import force_instant_defaults
db = SQLAlchemy()
sentry = Sentry()
force_instant_defaults()
and this the model user.py file:
#
-*- coding: utf-8 -*-
from datetime import datetime
from flask.ext.login import UserMixin
from sqlalchemy_utils.types.password import PasswordType
from ..extensions import db
class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(
db.Unicode(255),
nullable=False
)
surname = db.Column(
db.Unicode(255),
nullable=False
)
email = db.Column(
db.Unicode(255),
nullable=False,
unique=True
)
password = db.Column(
PasswordType(128, schemes=['sha512_crypt']),
nullable=False
)
created_at = db.Column(
db.DateTime,
nullable=False,
default=datetime.utcnow
)
def is_active(self):
return True
def __repr__(self):
return '<{cls} email={email!r}>'.format(
cls=self.__class__.__name__,
email=self.email,
)
def __str__(self):
return unicode(self).encode('utf8')
def __unicode__(self):
return self.email