I have a one to many relationship that returns an error each time I try to call it.
USER Model:
from config import db
from models.mixins import *
from models.decorators import *
import uuid
from sqlalchemy import Column, String, ForeignKey
from sqlalchemy.orm import relationship
from sqlalchemy.sql import func
from sqlalchemy.dialects import mysql
class User(db.Base):
__tablename__ = 'user'
id = Column(GUID(), primary_key=True, default=uuid.uuid4, unique=True)
name = Column(String(255), nullable=True)
address_to = Column(GUID(), ForeignKey('addess.id'), nullable=True)
address_from = Column(GUID(), ForeignKey('address.id'), nullable=True)
u_address_from = relationship('Address', foreign_keys='address_from',
back_populates='user_address_from')
u_address_to = relationship('Address', foreign_keys='address_to',
back_populates='user_address_to')
Address Model:
from config import db
from models.decorators import *
import uuid
from sqlalchemy import Column, String, ForeignKey
from sqlalchemy.orm import relationship
from sqlalchemy.sql import func
from sqlalchemy.dialects import mysql
class Address(db.Base):
__tablename__ = 'address'
id = Column(GUID(), primary_key=True, default=uuid.uuid4, unique=True)
street = Column(String(64), nullable=False)
city = Column(String(64), nullable=False)
user_address_from = relationship('Address', foreign_keys='User.address_from',
back_populates='u_address_from')
address_to = relationship('Address', foreign_keys='User.address_to',
back_populates='u_address_to')
Function to get user
class GetUser:
def user(user_id: str):
with db.Session() as session:
user = session.query(User).where(
User.id == user_id,
User.deleted_at.is_(None)
).first()
return user
The error I get is:
[ERROR] InvalidRequestError: When initializing mapper mapped class User->user, expression 'address_from' failed to locate a name ("name 'address_from' is not defined"). If this is a class name, consider adding this relationship() to the <class 'user.User'> class after both dependent classes have been defined.
Related
I'm using SqlAlchemy 1.3.20 and python3.8
In below code i used class sessionmaker.than i created an object.
when i call object methods such as : add() , commit() , query() and etc
i see this error TypeError: "Session' object is not callable.
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String, ForeignKey
from sqlalchemy.orm import Sessionmaker,relationship
base = declarative_base()
engine = create_engine('sqlite:///c:\\users\\alierza\\desktop\\python\\instagram\\test.db',echo=True)
class Cars(base):
__tablename__ = 'cars'
id = Column(Integer, primary_key=True)
make = Column(String(50), nullable=False)
color = Column(String(50), nullable=False)
class carOweners(base):
__tablename__ = 'carowner'
id = Column(Integer, primary_key=True)
name = Column(String(50), nullable=False)
age = Column(Integer, nullable=False)
carid = Column(Integer, ForeignKey('cars.id'))
car = relationship('Cars')
Session=sessionmaker(bind=engine)
session=Session()
base.metadata.create_all(engine)
car1=Cars(make='Ford',color='siliver')
owenr1=carOweners(name='Joe',age=20,carid=(car1.id))
session().add(car1)
session().add(owenr1)
session().commit()
its seems that methods does not exist.
Any tips or help?
When trying to get a many to many relationship working I keep getting the following error:
sqlalchemy.exc.InvalidRequestError: One or more mappers failed to initialize - can't proceed with initialization of other mappers. Triggering mapper: 'Mapper|User|Users'. Original exception was: When initializing mapper Mapper|User|Users, expression 'Device' failed to locate a name ("name 'Device' is not defined"). If this is a class name, consider adding this relationship() to the class after both dependent classes have been defined.
I have looked over all the sqlalchemy documents and reviewed multiple links on many to many but no luck. I am sure its a naming or importing issue, but have not found a solution yet
I removed some of the code that I don't feel is related
Users.py
from random import SystemRandom
from backports.pbkdf2 import pbkdf2_hmac, compare_digest
from flask_login import UserMixin
from sqlalchemy.ext.hybrid import hybrid_property
from sqlalchemy.orm import relationship
from devices.models import Device
user_device = db.Table('UserDevice', db.Model.metadata,
db.Column('userID', db.Integer, db.ForeignKey('Users.userID')),
db.Column('deviceID', db.Integer, db.ForeignKey('Device.deviceID')))
class User(UserMixin, db.Model):
__tablename__ = 'Users'
__table_args__ = {'mysql_engine': 'InnoDB',
'extend_existing': True}
id = db.Column('userID', db.Integer, primary_key=True)
# Relationship to UserDevice association table
user_device = relationship('Device',
secondary=user_device,
backref=db.backref('users', lazy='dynamic'))
Device.py
class Device(db.Model):
__tablename__ = 'Device'
__table_args__ = {'mysql_engine': 'InnoDB',
'extend_existing': True}
id = db.Column('deviceID', db.Integer, primary_key=True)
date_created = db.Column('deviceDateCreated', db.DateTime, default=db.func.current_timestamp())
date_modified = db.Column('deviceDateModified', db.DateTime, default=db.func.current_timestamp(), onupdate=db.func.current_timestamp())
device_created_user = db.Column('deviceCreatedUser', db.String, default='App Server')
device_last_updated_user = db.Column('deviceLastUpdatedUser', db.String, default='App Server', onupdate=current_user)
#Serial Number
serial_number = db.Column('deviceSerialNumber', db.Integer, nullable=False, unique=True)
#Sampling Interval
sampling_interval = db.Column('deviceSamplingInterval', db.Integer, default=60, nullable=False)
# Relationship to Device Status Table
device_status_id = db.Column('deviceStatusID', db.Integer, db.ForeignKey('DeviceStatus.deviceStatusID'))
# New instance instantiation procedure
def __init__(self, serial_number):
self.serial_number = serial_number
self.device_status_id = 1
def __repr__(self):
return '<Device %r>' % self.serial_number
Image of Database Model:
Turns out I didn't provide enough information to solve this problem. The problem turned out to be using the db variable created by calling SQLAlchemy. I created a python file just for the database called database.py. The mistake I made was in User\models.py I called the following import from database import db and in Device\models.py I called from app import db. This caused the db.Model to not function properly and also wouldn't create the user tables when calling create_all(). Hope this helps someone in the future.
Database.py
from flask_influxdb import InfluxDB
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
influx_db = InfluxDB()
influx_db_client = None
def init_db():
# import all modules here that might define models so that
# they will be registered properly on the metadata. Otherwise
# you will have to import them first before calling init_db()
from users.models import User, UserStatus, UserDevice
from devices.models import Device, DeviceStatus
db.Model.metadata.drop_all(bind=db.engine)
db.Model.metadata.create_all(bind=db.engine)
Devices\models.py
from app import db
from flask_login import current_user
from sqlalchemy.orm import relationship
import enum
class DeviceStatusType(enum.Enum):
INACTIVE = "Inactive"
ACTIVE = "Active"
# Define a Device model
class Device(db.Model):
__tablename__ = 'Device'
__table_args__ = {'extend_existing': True}
id = db.Column('deviceID', db.Integer, primary_key=True)
date_created = db.Column('deviceDateCreated', db.DateTime, default=db.func.current_timestamp())
date_modified = db.Column('deviceDateModified', db.DateTime, default=db.func.current_timestamp(), onupdate=db.func.current_timestamp())
device_created_user = db.Column('deviceCreatedUser', db.String(128), default='App Server')
device_last_updated_user = db.Column('deviceLastUpdatedUser', db.String(128), default='App Server', onupdate=current_user)
#Serial Number
serial_number = db.Column('deviceSerialNumber', db.Integer, nullable=False, unique=True)
#Sampling Interval
sampling_interval = db.Column('deviceSamplingInterval', db.Integer, default=60, nullable=False)
# Relationship to Device Status Table
device_status_id = db.Column('deviceStatusID', db.Integer, db.ForeignKey('DeviceStatus.deviceStatusID'))
users = relationship("User", secondary="userDevice")
# New instance instantiation procedure
def __init__(self, serial_number):
self.serial_number = serial_number
self.device_status_id = 1
def __repr__(self):
return '<Device %r>' % self.serial_number
users\models.py
from random import SystemRandom
from backports.pbkdf2 import pbkdf2_hmac, compare_digest
from flask_login import UserMixin, current_user
from sqlalchemy.ext.hybrid import hybrid_property
from sqlalchemy.orm import relationship, backref
from devices.models import Device
import enum
# Import the database object (db) from the main application module
# We will define this inside /app/__init__.py in the next sections.
from app import db
class UserStatusType(enum.Enum):
INACTIVE = "Inactive"
ACTIVE = "Active"
# Define a User model
class User(UserMixin, db.Model):
__tablename__ = 'User'
__table_args__ = {'extend_existing': True}
id = db.Column('userID', db.Integer, primary_key=True)
date_created = db.Column('userDateCreated', db.DateTime, default=db.func.current_timestamp())
date_modified = db.Column('userDateModified', db.DateTime, default=db.func.current_timestamp(), onupdate=db.func.current_timestamp())
user_created_user = db.Column('userCreatedUser', db.String(128), default=current_user)
user_last_updated_user = db.Column('userLastUpdatedUser', db.String(128), default=current_user, onupdate=current_user)
# First Name
first_name = db.Column('userFirstName', db.String(128), nullable=False)
# Last Name
last_name = db.Column('userLastName', db.String(128), nullable=False)
# User Name
user_name = db.Column('userUserName', db.String(128), nullable=False, unique=True)
# Email
email = db.Column('userEmailAddress', db.String(128), nullable=False, unique=True)
# Password
_password = db.Column('userPassword', db.LargeBinary(128))
_salt = db.Column('userSalt', db.LargeBinary(128))
# Relationship to User Status table
user_status_id = db.Column('userStatusID', db.Integer, db.ForeignKey('UserStatus.userStatusID'))
# Relationship to UserDevice association table
devices = relationship("Device", secondary="userDevice")
#hybrid_property
def password(self):
return self._password
# In order to ensure that passwords are always stored
# hashed and salted in our database we use a descriptor
# here which will automatically hash our password
# when we provide it (i. e. user.password = "12345")
#password.setter
def password(self, value):
# When a user is first created, give them a salt
if self._salt is None:
self._salt = bytes(SystemRandom().getrandbits(8))
self._password = self._hash_password(value)
def is_valid_password(self, password):
"""Ensure that the provided password is valid.
We are using this instead of a ``sqlalchemy.types.TypeDecorator``
(which would let us write ``User.password == password`` and have the incoming
``password`` be automatically hashed in a SQLAlchemy query)
because ``compare_digest`` properly compares **all***
the characters of the hash even when they do not match in order to
avoid timing oracle side-channel attacks."""
new_hash = self._hash_password(password)
return compare_digest(new_hash, self._password)
def _hash_password(self, password):
pwd = password.encode("utf-8")
salt = bytes(self._salt)
buff = pbkdf2_hmac("sha512", pwd, salt, iterations=100000)
return bytes(buff)
# New instance instantiation procedure
def __init__(self, first_name, last_name, user_name, email, password):
self.first_name = first_name
self.last_name = last_name
self.user_name = user_name
self.email = email
self.password = password
self.user_status_id = 2
def __repr__(self):
return "<User #{:d}>".format(self.id)
The model.py looks like this:
import datetime
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String, Numeric, ForeignKey, DateTime, Boolean
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker, relationship
from configs import config_base as config
Base = declarative_base()
class User(Base):
__tablename__ = 'user'
id = Column(String, unique=True, primary_key=True)
name = Column(String(100), nullable=False)
team_id = Column(String, ForeignKey('team.id'))
last_modified_on = Column(DateTime, default=datetime.datetime.utcnow())
team = relationship('Team', back_populates='members')
class Team(Base):
__tablename__ = 'team'
id = Column(String, unique=True, primary_key=True)
name = Column(String, nullable=False)
bot_access_token = Column(String(100), nullable=False)
bot_user_id = Column(String(100), nullable=False)
last_modified_on = Column(DateTime, default=datetime.datetime.utcnow())
is_active = Column(Boolean, default=True)
members = relationship('User', back_populates='team')
is_first_time_news = Column(Boolean, default=True)
engine = create_engine(config.SQLALCHEMY_DATABASE_URI)
Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)
I just added is_first_time_news via this alembic migration:
revision = '6f9e2d360276'
down_revision = None
branch_labels = None
depends_on = None
from alembic import op
import sqlalchemy as sa
def upgrade():
op.add_column('team', sa.Column('is_first_time_news', sa.Boolean, default=False))
def downgrade():
op.drop_column('team', sa.Column('is_first_time_news', sa.Boolean))
alembic upgrade head works great.
But when I do a alembic downgrade -1 I get a strange exception:
AttributeError: Neither 'Column' object nor 'Comparator' object has an
attribute '_columns'
Are you using sqlite? Sqlite does not allow you to drop a column from the
scheme. I had a similar problem when I tried to downgrade a local sqlite database I was testing.
SQLite supports a limited subset of ALTER TABLE. The ALTER TABLE
command in SQLite allows the user to rename a table or to add a new
column to an existing table.
https://www.sqlite.org/lang_altertable.html
Try:
def downgrade():
op.drop_column('team', 'is_first_time_news')
I need to create ten sample users (User) and each of them must have fifty documents (Doc). How to do this in tests.py using factoryboy?
#factories.py
from app_name.models import *
import factory
from datetime import datetime, timedelta, time
from django.contrib.auth.models import User
class UserFactory(factory.Factory):
FACTORY_FOR = User
username = factory.Sequence(lambda n: 'User ' + n)
email = 'demo#mail.com'
password = '1234567'
class DocFactory(factory.Factory):
FACTORY_FOR = Doc
user = factory.SubFactory(UserFactory)
kategories = '1'
doc_number = '12345678'
date_join = factory.Sequence(lambda n:(datetime.now() + timedelta(days=n)).date(), int)
in my tests.py:
from django.test import TestCase
from django_dynamic_fixture import G
from factories import *
users = UserFactory.create_batch(10)
for user in users:
doc = DocFactory.create(user=user)
You can use a post_generation decorator:
class UserFactory(factory.Factory):
...
#factory.post_generation
def create_docs(self, create, extracted, **kwargs):
if not create:
return
for i in range(50):
doc = DocFactory.create(user=self)
For those of you working with SQLAlchemy, this can be done with the following recipe (notice that I'm using the Person/Address models instead of the User/Docs model example above).
from sqlalchemy import create_engine, Integer, Text, ForeignKey, Column
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship, scoped_session, sessionmaker
import factory
from factory.alchemy import SQLAlchemyModelFactory as sqla_factory
import random
engine = create_engine("sqlite:////tmp/factory_boy.sql")
session = scoped_session(sessionmaker(bind=engine))
Base = declarative_base()
class Person(Base):
id = Column(Integer, primary_key=True)
name = Column(Text)
addresses = relationship("Address", backref="person")
class Address(Base):
id = Column(Integer, primary_key=True)
city = Column(Text)
street = Column(Text)
street_number = Column(Integer)
person_id = Column(Integer, ForeignKey('person.id'))
class AddressFactory(sqla_factory):
class Meta:
model = Address
sqlalchemy_session = session
street_number = random.randint(0, 10000)
street = "Commonwealth Ave"
city = "Boston"
class PersonFactory(sqla_factory):
class Meta:
model = Person
sqlalchemy_session = session
name = "John Doe"
Base.metadata.create_all(engine)
for i in range(100):
person = PersonFactory(addresses=AddressFactory.create_batch(3))
This creates 3 workouts for each person created, where each workout references the person via the person_id FK.
You can simply do batch_create so that for each DocFactory object new UserFactory object will create
`DocFactory.create_batch(10)`
I have problem with separating tables with relationships in different files. I want the tables below to be in three separate files and to import TableA in third party page, but I can not manage the load order.
In most of the time I'm receiving the following error.
sqlalchemy.exc. InvalidRequestError: When initializing mapper Mapper|TableA|tablea, expression 'TableB' failed to locate a name ("name 'TableB' is not defined"). If this is a class
name, consider adding this relationship() to the class after both dependent classes have been defined.
class TableA(Base):
__tablename__ = "tablea"
id = Column(Integer, primary_key=True)
name = Column(String)
tableB = relationship("TableB", secondary = TableC.__table__)
class TableB(Base):
__tablename__ = "tableb"
id = Column(Integer, primary_key=True)
name = Column(String)
class TableC(Base):
__tablename__ = "tableab"
tableAId = Column("table_a_id", Integer, ForeignKey("TableA.id"), primary_key=True)
tableBId = Column("table_b_id", Integer, ForeignKey("TableB.id"), primary_key=True)
This should work (note that the TableC.table is replaced with the name of the table to avoid circular module loading):
### base.py
engine = create_engine('sqlite:///:memory:', echo=True)
Session = sessionmaker(bind=engine)
Base = declarative_base(bind=engine)
### classA.py
from base import Base
from classB import TableB
class TableA(Base):
__tablename__ = 'tablea'
id = Column(Integer, primary_key=True)
name = Column(String(50))
tableBs = relationship("TableB", secondary="tableab")
#tableBs = relationship("TableB", secondary=TableC.__table__)
### classB.py
from base import Base
class TableB(Base):
__tablename__ = 'tableb'
id = Column(Integer, primary_key=True)
name = Column(String(50))
### classC.py
from base import Base
from classA import TableA
from classB import TableB
class TableC(Base):
__tablename__ = 'tableac'
tableAId = Column(Integer, ForeignKey("tablea.id"), primary_key=True, )
tableBId = Column(Integer, ForeignKey("tableb.id"), primary_key=True, )
### main.py
from base import Base, Session, engine
from classA import TableA
from classB import TableB
from classC import TableC
Base.metadata.create_all(engine)
Also I believe that the ForeignKey parameter is case sensitive, so you code might not work because "TableA.id" doe snot match "tablea" name when case-sensitive.
from sqlalchemy import Column, String, Integer
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class Parent(Base):
__tablename__ = 'Parent'
ParentID = Column(Integer, primary_key=True)
Description = Column(String)
def __init__(self, ParentID, Description):
self.ParentID = ParentID
self.Description = Description
----------------------------------------------------------------------
from sqlalchemy import Column, String, Integer, ForeignKey
import Parent
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class Child(Base):
__tablename__ = "Child"
ChildID = Column(Integer, primary_key=True)
Description = Column(String)
ParentID = Column('CompanyID', Integer, ForeignKey(Parent.ParentID))
def __init__(self, ChildID, Description,ParentID):
self.ChildID = ChildID
self.Description = Description
self.ParentID=ParentID