I am using flask and flask SQLAlchemy to create my sqllite database that has one table with several columns. I have created my model but once I run the app it only creates the first 03 columns ?!!!
...
db = SQLAlchemy()
def setup_db(app):
db.app = app
db.init_app(app)
def db_drop_and_create_all():
db.drop_all()
db.create_all()
...
#dataclass
class ChurnModel(inheritedModels):
id = int
customerID = String
gender = String
SeniorCitizen: int
Partner: String
...
__tablename__ = 'churn'
id = Column(Integer().with_variant(Integer, "sqlite"), primary_key=True)
customerID = Column(String(255), nullable=False)
gender = Column(String(255))
SeniorCitizen: Column(Integer())
Partner: Column(String(255))
...
def get_churn(self):
return {
"id": self.id,
"customerID": self.customerID,
"gender": self.gender,
"SeniorCitizen": self.SeniorCitizen,
"Partner": self.Partner,
...
}
...
This is what I have found in the database.db file surrounded by a lot of nulls:
TE TABLE churn (
id INTEGER NOT NULL,
"customerID" VARCHAR(255) NOT NULL,
gender VARCHAR(255),
PRIMARY KEY (id)
)
Any explanation?!
After looking at the code, I think this is an expected behaviour since the only columns you defined are id, customerID, and gender.
Maybe you just got confused on how to use type hints, or you didn't pay attention to that, that's all.
Try this instead :
#dataclass
class ChurnModel(inheritedModels):
id: int
customerID: str
gender: str
SeniorCitizen: int
Partner: str
...
__tablename__ = 'churn'
id = Column(Integer().with_variant(Integer, "sqlite"), primary_key=True)
customerID = Column(String(255), nullable=False)
gender = Column(String(255))
SeniorCitizen= Column(Integer())
Partner= Column(String(255))
...
Related
I have the following model:
from marshmallow import Schema, fields
from server import db, ma, app
from sqlalchemy.ext.hybrid import hybrid_property
from .analysis import AnalysisSchema
class Category(db.Model):
__tablename__ = 'Categories'
__table_args__ = {'extend_existing': True}
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(120), index=True, unique=True)
description = db.Column(db.Text, nullable=False)
img = db.Column(db.LargeBinary, nullable=False)
img_mimetype = db.Column(db.Text, nullable=False)
img_name = db.Column(db.Text, nullable=False)
analysis = db.relationship("Analysis", back_populates="category")
#property
def img_url(self):
return "/categories/" + str(self.id)
class CategorySchema(ma.SQLAlchemyAutoSchema):
class Meta:
# model = Category
fields = ("id", "name", "description", "img", "img_url", "analysis")
analysis = fields.Nested(AnalysisSchema, many=True)
class CreateCategorySchema(Schema):
name = fields.Str(required=True)
description = fields.Str(required=True)
class UpdateCategorySchema(Schema):
name = fields.Str(required=True)
description = fields.Str(required=False)
img_name = fields.Str(required=False)
img_mimetype = fields.Str(required=False)
I create a new category with the following code:
from flask import jsonify
from server import db, app
from ..models.category import (
Category,
CategorySchema,
CreateCategorySchema,
UpdateCategorySchema
)
def create_category(data):
app.logger.info('Create category invoked')
create_category_schema = CreateCategorySchema()
# errors = create_category_schema.validate(data)
errors = None
if errors:
app.logger.info('Found errors %s', errors)
return jsonify(errors), 400
name = Category.query.filter_by(name=data['name']).first()
app.logger.info('Name is %s', name)
if not name:
app.logger.info('Name not present')
category = Category(
name=data['name'],
description=data['description'],
img=data['img'],
img_name=data['img_name'],
img_mimetype=data['img_mimetype']
)
_save_category(category)
category_schema = CategorySchema()
response = category_schema.dump(category), 201
#response = jsonify('Category created'), 200
else:
response = jsonify('Category already exists'), 409
return response
def all_categories():
category_schema = CategorySchema(many=True, exclude=['img'])
categories = Category.query.all()
response = category_schema.dump(categories)
return jsonify(response), 20
def get_category(id):
return Category.query.filter_by(id=id).first()
def _save_category(category):
db.session.add(category)
db.session.commit()
If I try to invoke create_category I got the following error:
sqlalchemy.exc.DataError: (MySQLdb._exceptions.DataError) (1406, "Data too long for column 'img' at row 1")
[SQL: INSERT INTO `Categories` (name, description, img, img_mimetype, img_name) VALUES (%s, %s, %s, %s, %s)]
[parameters: ('test10', 'blah blah blah', b'\xff\xd8\xff\xe0\x00\x10JFIF\x00\x01\x01\x00\x00\x01\x00\x01\x00\x00\xff\xdb\x00\x84\x00\x06\x06\x06\x06\x07\x06\x07\x08\x08\x07\n\x0b\n\x0b\n\x0f\x ... (371140 characters truncated) ... xe4\xd3\xc0\xe3\xcag\xaf\x17\xff\x00\xcc?\xfdD\xfe\x85\xc3\x91\x06\x07\x017#3\x93:\x7fE\xfe\xb3\xff\x00\xe9_\xff\x00\x04r-i\x86\xb7\xd6|#\xbf\xff\xd9', 'image/jpeg', 'WhatsApp_Image_2021-06-04_at_11.14.49_AM.jpeg')]
(Background on this error at: http://sqlalche.me/e/14/9h9h)
I don't understand why is trying to insert an image as a String if it is explicitly defined as a LargeBinary.
The solution can be found in the question comments. I had to increase the size of the Blob using the length attribute of SQLAlchemy.
I'm trying to create a Schema using marshmallow_sqlalchemy. I want to create a list out of two entries of the Database, x_coordinate and y_coordinate, however, I'm not sure how to do that.
Here's the Schema
from marshmallow_sqlalchemy import SQLAlchemySchema, auto_field
class LocationSQLAlchemySchema(SQLAlchemySchema):
class Meta:
model = Location
load_instance = True
location_id = auto_field('id')
name = auto_field('name')
user_uid = auto_field('customer_id')
maps_url = auto_field('maps_url')
coordinates = fields.List(Meta.model.x_coordinate,Meta.model.y_coordinate) #This is what I don't know how to define.
Here's the Model I'm using for this Schema:
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy.dialects.mysql import INTEGER
db = SQLAlchemy()
class Location(db.Model):
__tablename__ = 'cleaning_locations'
id = db.Column(db.String(128), primary_key=True, unique = True)
name = db.Column(db.String(45), nullable = False)
customer_id = db.Column(db.String(45),nullable = False)
maps_url = db.Column(db.String(2048),nullable = False)
x_coordinate = db.Column(db.Numeric(precision = 8, scale=5), nullable = False)
y_coordinate = db.Column(db.Numeric(precision = 8, scale=5), nullable = False)
address = db.Column(db.String(255))
country = db.Column(db.String(45))
state = db.Column(db.String(45))
size = db.Column(INTEGER(unsigned=True), nullable = False )
rooms = db.Column(INTEGER(unsigned=True), nullable = False )
bathrooms = db.Column(INTEGER(unsigned=True), nullable = False )
kitchens = db.Column(INTEGER(unsigned=True), nullable = False )
How can I make the Schema to represent the coordinates as a list containing the x_coordinate and the y_coordinate?
(newbie extra question). Is it a bad practice to use diferent variable names in the db model and in the Schema?
Please try this (untested):
from marshmallow_sqlalchemy import field_for
[...]
coordinates = fields.Tuple(
(field_for(Location, "x_coordinate"), field_for(Location, "y_coordinate"))
)
Not sure it is the best idea here because then you can't just cram the data loaded from the schema into the object init. But nothing prevents you from having an API (schemas) that differs from the DB representation.
I have existing DB dataset that has these tables already:
owners table that has ownerid as primary_key
another table owndnis whose primary_key is the same ownerid
one other table whose primary_key is also the same ownerid as that of owners
I want to define a relation which looks like this
owners
having
{owndnis} and
{application_parameters}
My model and route file contents are given below
model.py
from marshmallow import fields
from flask import jsonify
class owners(db.Model):
__tablename__ = 'owners'
ownerid = db.Column('ownerid',db.String(60), nullable=False)
name = db.Column('ownerdomainname', db.String(60),primary_key=True, nullable=False)
spownerid = db.Column('spownerid', db.String(60))
ownerid = db.Column(db.String(), db.ForeignKey('owndnis.ownerid'))
dnis = db.relationship("owndnis", uselist=False, backref="owners")
# ownerid = db.Column(db.String(), db.ForeignKey('application_parameters.ownerid'))
# app_params = db.relationship("application_parameters", backref="owners")
class owndnis(db.Model):
__tablename__ = 'owndnis'
ownerid = db.Column('ownerid',db.String(60),primary_key=True)
dnisstart = db.Column('dnisstart', db.String(20), nullable=False)
dnisend = db.Column('dnisend', db.String(20))
class application_parameters(db.Model):
__tablename__ = 'application_parameters'
ownerid = db.Column('ownerid',db.String(60),primary_key=True)
applicationid = db.Column('applicationid', db.String(60), nullable=False)
key = db.Column('key', db.String(128), nullable=False)
value = db.Column('value', db.String(1024), nullable=False)
###### SCHEMAS #####
class owndnis_schema(ma.ModelSchema):
dnisstart = fields.String()
dnisend = fields.String()
class app_params_schema(ma.ModelSchema):
key = fields.String()
value = fields.String()
class owners_schema(ma.ModelSchema):
ownerid = fields.String()
ownerdomainname = fields.String()
spownerid = fields.String()
ownerdescription = fields.String()
dnis = fields.Nested(owndnis_schema)
app_params = fields.Nested(app_params_schema)
routes.py
---------
from model import owners, owndnis, application_parameters,owners_schema,owndnis_schema, app_params_schema
#mod.route('/api/sp/<spdomainname>', methods=['GET'])
def findSp(spdomainname):
ownerArr = []
owner = owners.query.get(spdomainname)
owner_schema = owners_schema()
if owner:
owners_sm_result = owner_schema.dump(owner).data
return jsonify({'owner': owners_sm_result})
I get the output like this
{
"owner": {
"spownerid": "SYSTEM",
"ownerid": "NEWSP~ZryOZB9BGb",
"dnis": {
"dnisend": "199999",
"dnisstart": "100000"
}
}
}
If I uncomment the commented lines in model.py(owners) to include another table that has foreign key same as owndnis table
but I get this run time error
File "/home/holly/python_ws/new_project_blue/blue/lib/python2.7/site-packages/sqlalchemy/orm/relationships.py", line 2383, in _determine_joins
"specify a 'primaryjoin' expression." % self.prop
sqlalchemy.exc.NoForeignKeysError: Could not determine join condition between parent/child tables on relationship owners.dnis - there are no foreign keys linking these tables. Ensure that referencing columns are associated with a ForeignKey or ForeignKeyConstraint, or specify a 'primaryjoin' expression.
[pid: 18308|app: 0|req: 1/1] 10.133.0.31 () {34 vars in 620 bytes} [Tue May 14 07:22:14 2019] GET /api/sp/NEW-SP => generated 0 bytes in 25 msecs (HTTP/1.1 500) 0 headers in 0 bytes (0 switches on core 0)
The requirement is to have the output like this
I get the output like this
{
"owner": {
"spownerid": "SYSTEM",
"ownerid": "NEWSP~ZryOZB9BGb",
"dnis": {
"dnisend": "199999",
"dnisstart": "100000"
},
"app_params": {
"key":"xxxxx",
"value":"yyyy"
}
}
}
I would closely follow the relationship patterns in the documentation:
https://docs.sqlalchemy.org/en/13/orm/basic_relationships.html
As an example assuming you wanted a one-to-one relationship between owners and owndnis...
One to One
class Parent(Base):
__tablename__ = 'parent'
id = Column(Integer, primary_key=True)
child = relationship("Child", uselist=False, back_populates="parent")
class Child(Base):
__tablename__ = 'child'
id = Column(Integer, primary_key=True)
parent_id = Column(Integer, ForeignKey('parent.id'))
parent = relationship("Parent", back_populates="child")
Untested but following this pattern and in your case treating owners as the parent:
# Treated as Parent of One to One
class owners(db.Model):
__tablename__ = 'owners'
ownerid = db.Column('ownerid', db.String(60), primary_key=True) <--- changed primary key
name = db.Column('ownerdomainname', db.String(60), nullable=False)
spownerid = db.Column('spownerid', db.String(60))
dnis = db.relationship("owndnis", uselist=False, back_populates="owners") <--- note change
# child = relationship("Child", uselist=False, back_populates="parent")
# Treated as Child of One to One
class owndnis(db.Model):
__tablename__ = 'owndnis'
ownerid = db.Column('ownerid', db.String(60),
primary_key=True, db.ForeignKey('owners.ownerid')) <-- both a PK and FK
dnisstart = db.Column('dnisstart', db.String(20), nullable=False)
dnisend = db.Column('dnisend', db.String(20))
owner = relationship("owners", back_populates="owndnis") <--- added
# parent = relationship("Parent", back_populates="child")
I've used back_populates but per the docs:
As always, the relationship.backref and backref() functions may be used in lieu of the relationship.back_populates approach; to specify uselist on a backref, use the backref() function:
class Parent(Base):
__tablename__ = 'parent'
id = Column(Integer, primary_key=True)
child_id = Column(Integer, ForeignKey('child.id'))
child = relationship("Child", backref=backref("parent", uselist=False))
How can I insert data with a python dict?
This doesn't work:
class Date(Base):
__tablename__ = 'dates'
__table_args__ = {'schema':'www'}
id = Column(Integer, primary_key=True)
salutation = Column(VARCHAR(1))
lastname = Column(VARCHAR(128))
firstname = Column(VARCHAR(50))
zipcode = Column(VARCHAR(255))
...
statement = dict({
'salutation': form.get('salutation'),
'lastname': form.get('lastname'),
'firstname': form.get('firstname'),
'zipcode': form.get('zipcode')
})
new_entry = Date(**statement)
session.add(new_entry)
session.commit()
This produces this error output
ProgrammingError: (psycopg2.ProgrammingError) can't adapt type 'dict'
[SQL: 'INSERT INTO ....
I've read through all of these (https://stackoverflow.com/search?q=sqlalchemy.exc.NoReferencedTableError%3A), the Flask-appbuilder docs, the sqlalchemy docs, and the Flask-sqlalchemy docs and more. Unfortunately, I can't find any full examples of a many-to-many sqlalchemy relationship.
I have a python Flask app using flask-appbuilder (which relies on flask-sqlalchemy). My app/model.py file has this:
field_feature_association = Table('field_feature_association',Base.metadata,
Column('field_id', Integer, ForeignKey('field.id')),
Column('feature_id',Integer, ForeignKey('feature.id')),
schema="main"
)
class field(Model):
__tablename__ = 'field'
id = Column(Integer, primary_key=True)
name = Column(String(70), nullable=False)
database_type = Column(String(70)) #varchar(255), text, int
joinable_to = Column(Text())
notes = Column(Text()) #don't use this for X
table_id = Column(Integer, ForeignKey('table.id'))
table = relationship("table")
features = relationship("feature",
secondary = field_feature_association,
backref = backref('fields'),
)
def __repr__(self):
return self.name
class feature(Model):
__tablename__ = 'feature'
id = Column(Integer, primary_key=True)
name = Column(String(70), unique = True, nullable=False)
field_id = Column(Integer, ForeignKey('field.id'))
#field = relationship("field")
def __repr__(self):
return self.name
It's generating this error:
sqlalchemy.exc.NoReferencedTableError: Foreign key associated with column 'field_feature_association.feature_id' could not find table 'feature' with which to generate a foreign key to target column 'id'
Thoughts on how to fix this error?
Here is a working sample of many-to-many in SQLAlchemy. Moreover I modified your model and it works fine:
field_feature_association = db.Table('field_feature_association', db.Model.metadata,
db.Column('field_id', db.Integer, db.ForeignKey('field.id')),
db.Column('feature_id', db.Integer, db.ForeignKey('feature.id')),
schema="main"
)
class Field(db.Model):
__tablename__ = 'field'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(70), nullable=False)
database_type = db.Column(db.String(70)) # varchar(255), text, int
joinable_to = db.Column(db.Text())
notes = db.Column(db.Text()) # don't use this for X
features = db.relationship("Feature",
secondary=field_feature_association,
backref=db.backref('fields'),
)
def __repr__(self):
return self.name
class Feature(db.Model):
__tablename__ = 'feature'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(70), unique=True, nullable=False)
field_id = db.Column(db.Integer, db.ForeignKey('field.id'))
# field = relationship("field")
def __repr__(self):
return self.name
and this is how to use it:
field = Field()
field.name="filed1"
feature = Feature()
feature.name = "feature1"
field.features.append(feature)
db.session.add(field)
db.session.commit()
My database object is imported as ’db’ and I have used it explicitely to refer to other types.