How to use dataLoader in strawberry(Fast API, Sqlalchemy) - python

I have these three model. One user have multiple roles.I am stuck for get roles of user.
How can I get the user with roles using strawberry dataloader?
class UserRole(Base):
__tablename__ = "user_roles"
id = Column(Integer, primary_key=True, index=True)
user = Column(Integer, ForeignKey("users.id"))
role = Column(Integer, ForeignKey("roles.id"))
created_at = Column(DateTime(), server_default=func.now())
updated_at = Column(DateTime(), nullable=True)
class Role(Base):
__tablename__ = "roles"
id = Column(Integer, primary_key=True, index=True)
name = Column(String(255), unique=True, index=True, default="patient")
description = Column(String(255), nullable=True)
created_at = Column(DateTime(), server_default=func.now())
updated_at = Column(DateTime(), nullable=True)
def __repr__(self):
return f"{self.name}"
class User(Base):
__tablename__ = "users"
id = Column(Integer, primary_key=True, index=True)
first_name = Column(String(255), nullable=True)
last_name = Column(String(255), nullable=True)
email = Column(String(255), unique=True, index=True)
roles = relationship(
"Role",
secondary="user_roles",
backref=backref("users", lazy="dynamic"),
)
created_at = Column(DateTime(), server_default=func.now())
updated_at = Column(DateTime(), nullable=True)
def __repr__(self):
return f"{self.email}"
Now I am using this tutorial https://strawberry.rocks/docs/guides/dataloaders

Related

FlaskSqlAlchemy multi join on multi table. ambiguous column name

I'm about a month into learning and working with SQLAlchemy. I've been working on troubleshooting this for several hours using previous posts on StackOverflow and reading SQLAlchemy docs. Even watched videos on Youtube.
Can anybody help me with creating a proper query? I think I need to alias the column name, but I haven't got that to work yet.
Thank you in advance
cdm_mapping = db.Table('cdm_mapping',
db.Column('product_id', db.ForeignKey('product.id'), primary_key=True),
db.Column('cdm_id', db.ForeignKey('CDM.id'), primary_key=True)
)
user_products = db.Table('user_products',
db.Column('user_id', db.ForeignKey('user.id'), primary_key=True),
db.Column('product_id', db.ForeignKey('product.id'), primary_key=True)
)
class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
created_on = db.Column(db.DateTime, default=datetime.utcnow)
updated_on = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
username = db.Column(db.String(20), unique=True, nullable=False)
email = db.Column(db.String(120), unique=True, nullable=False)
website = db.Column(db.String(120), nullable=True)
company = db.Column(db.String(120), nullable=True)
title = db.Column(db.String(60), nullable=True)
image_file = db.Column(db.String(25), nullable=False, default='default.jpg')
password = db.Column(db.String(60), nullable=False)
role = db.Column(db.String(60), nullable=True)
permission = db.Column(db.String(60), nullable=True)
status = db.Column(db.String(60), nullable=True)
products = db.relationship("Product", secondary=user_products, back_populates="users")
class Product(db.Model):
id = db.Column(db.Integer, primary_key=True)
created_on = db.Column(db.DateTime, default=datetime.utcnow)
updated_on = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
product_name = db.Column(db.String(120), unique=True, nullable=False)
product_shortname = db.Column(db.String(25), nullable=True)
homepage = db.Column(db.String(200), nullable=True)
rating = db.Column(db.Float, nullable=True)
review_count = db.Column(db.Integer, nullable=True)
github = db.Column(db.String(120), nullable=True)
description = db.Column(db.String(15000), nullable=True)
logo_file = db.Column(db.String(120), nullable=False, default='default.jpg')
# Relationships
categories = db.relationship("Category", secondary=product_category, back_populates="products")
features = db.relationship("Feature", secondary=product_feature, back_populates="products")
cdm_elements = db.relationship("CDM", secondary=cdm_mapping, back_populates="products")
vendor_id = db.Column(db.Integer, db.ForeignKey('vendor.id'), nullable=True)
users = db.relationship("User", secondary=user_products, back_populates="products")
class CDM(db.Model):
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
name = db.Column(db.String(30), unique=True, nullable=False)
description = db.Column(db.String(15000), nullable=True)
# Relationship
products = db.relationship("Product", secondary=cdm_mapping, back_populates="cdm_elements")
This is the query I constructed dozens of different ways.
user_id = 1
def get_toolkit_in_cdm(user_id):
query = db.session.query(CDM.name, Product.product_name, User.username).join(CDM.products).join(User.products).filter(User.id == user_id).all()
for product, cdm, user in query:
print(product, cdm, user)
I get this error.
sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) ambiguous column name: product.product_name

Ploymorphic Association

Let's say I have these models:
class User(db.Model):
__tablename__ = 'Users'
__table_args__ = {'extend_existing': True}
id = db.Column(db.Integer, primary_key=True)
alias = db.Column(db.String(120), index=True, unique=True)
name = db.Column(db.String(120), index=True, unique=False)
lastname = db.Column(db.String(120), index=True, nullable=False)
email = db.Column(db.String(120), index=True, nullable=False)
password = db.Column(db.String(120), index=False, nullable=True)
created_on = db.Column(db.DateTime, default=datetime.now)
updated_on = db.Column(db.DateTime, default=datetime.now, onupdate=datetime.now)
class A(db.Model):
__tablename__ = 'A'
__table_args__ = {'extend_existing': True}
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(120), index=True, unique=True)
class B(db.Model):
__tablename__ = 'B'
__table_args__ = {'extend_existing': True}
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(120), index=True, unique=True)
I want to create another model called Audit that can referentiate A and B, so I was thinking about polymorphic associations, but I could not find a valid documentation to do that.
class Audit(db.Model):
__tablename__ = 'audit'
__table_args__ = {'extend_existing': True}
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(120), index=True, unique=True)
user_id = db.Column(db.Integer, db.ForeignKey('Users.id'), nullable=True)
object???
I want to have an object that can point to A or B.
I'm just going to guess that maybe you want something like below. I find that sometimes just columns that are conditionally set is more useful unless you really have an inheritance tree, ie. truly polymorphic models.
class Audit(db.Model):
__tablename__ = 'audit'
__table_args__ = {'extend_existing': True}
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(120), index=True, unique=True)
user_id = db.Column(db.Integer, db.ForeignKey('Users.id'), nullable=True)
dataset_id = db.Column(db.Integer, db.ForeignKey('dataset.id'), nullable=True)
dataset = db.relationship('Dataset', backref='audits')
class Dataset(Base):
__tablename__ = 'datasets'
id = Column(Integer, primary_key=True)
type = Column(String(20))
name = db.Column(db.String(120), index=True, unique=True)
__mapper_args__ = {
'polymorphic_on':type,
# You can probably use None here
# and set type to nullable= False
# if you don't want a base case
'polymorphic_identity': 'c'
}
class DatasetA(Dataset):
info = db.Column(db.String(120))
__mapper_args__ = {
'polymorphic_identity':'a'
}
class DatasetB(Dataset):
__mapper_args__ = {
'polymorphic_identity':'b'
}

How to attach User model with two different Models so that the properties of those models can be accessed via current_user

I am building a online quiz app where both teacher and students can login. Teachers can create quizzes and students can run those quizzes. How can I attach both Teacher and Student model with User model so that properties like Teacher_Name or Student_Class etc can be accessed via current_user?
This is not a problem regarding user role. Because using flask-security I can do that pretty easily but providing role means grouping users by their access level but not actually identifying them. I mean if a student logs in I need know who is this particular student represented by the current logged in user. Only then I can store his/her result with his/her record.
Followings are my sqlalchemy models...
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String(120), unique=True, nullable=False)
password = db.Column(db.String(60), nullable=False)
class Student(db.Model):
__tablename__ = 'student'
id = db.Column(db.Integer, primary_key=True)
cls = db.Column(db.String(4), nullable=False, default='V')
sec = db.Column(db.String(1), nullable=False, default='A')
roll = db.Column(db.Integer, nullable=False, default=1)
name = db.Column(db.String(24), nullable=False)
dob = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
sex = db.Column(db.Enum(Gender), nullable=False, default=Gender.male)
results = db.relationship('Result', backref='student', lazy=True)
__table_args__ = (db.UniqueConstraint("cls", "roll", name="cls_roll"),)
class Teacher(db.Model):
__tablename__ = 'teacher'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(24), nullable=False)
subject = db.Column(db.String(4), nullable=False)
quiz_ques = db.Table('quiz_ques', db.Column('quiz_id', db.Integer, db.ForeignKey('quiz.id'), nullable=False),
db.Column('mcq_id', db.Integer, db.ForeignKey('mcq.id'), nullable=False),
db.PrimaryKeyConstraint('quiz_id', 'mcq_id'))
class Quiz(db.Model):
__tablename__ = 'quiz'
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(50), nullable=False, unique=True)
subject = db.Column(db.String(4), nullable=False)
marks = db.Column(db.Integer, nullable=False, default=1)
time_limit = db.Column(db.Integer, nullable=False, default=20)
questions = db.relationship('MCQ', secondary=quiz_ques, lazy='subquery', backref=db.backref('quizzes', lazy=True))
results = db.relationship('Result', backref='quiz', lazy=True)
class MCQ(db.Model):
__tablename__ = 'mcq'
id = db.Column(db.Integer, primary_key=True)
subject = db.Column(db.String(4), nullable=False)
topic = db.Column(db.String(150), nullable=False)
question = db.Column(db.String(255), nullable=False)
answers = db.Column(db.Text(), nullable=False)
class Result(db.Model):
__tablename__ = 'result'
id = db.Column(db.Integer, primary_key=True)
date_created = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
marks_obtained = db.Column(db.Integer, nullable=False, default=0)
response = db.Column(db.Text(), nullable=True)
stud_id = db.Column(db.Integer, db.ForeignKey('student.id'), nullable=False)
quiz_id = db.Column(db.Integer, db.ForeignKey('quiz.id'), nullable=False)
The code should allow me to do something like this -
current_user.student.name = 'John Doe'
or
current_user.teacher.subject = 'Math'

Order of declaring classes in SqlAlchemy

I'm sory for this newby question, but I can't figure it out for a couple days and it is driving me nuts.
I'm building a small project in order to learn flask, SqlAlchemy and Postrges.
I have major problems with declaring classes in SqlAlchemy. I have already simplified models by removing all many-to-many relationships. However, now I have new problems even with one-to many relationships, although I think I have tried all the possible options. Maybe there's a typo that I keep on overlooking, or I don't grasp something fundamental. Please let me know...
So, I have classes declared as follows in my models.py:
#login_manager.user_loader
def load_user(user_id):
return User.query.get(int(user_id))
class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key = True)
username = db.Column(db.String(20), unique=True, nullable=False)
email = db.Column(db.String(120), unique=True, nullable=False)
password = db.Column(db.String(60), nullable=False)
date_registered = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
role = db.Column(db.Integer, nullable=False)
role_exp_date = db.Column(db.DateTime)
#o2o
personal_datas = db.relationship('PersonalData', uselist=False, backref='user', lazy=True)
persons = db.relationship('Person', uselist=False, backref='user', lazy=True)
#o2m
posts = db.relationship('Post', backref='author', lazy=True)
comments = db.relationship('PostComment', backref='author', lazy=True)
projects_owned = db.relationship('ConstrProject', backref='owner', lazy=True)
attachments = db.relationship('Attachment', backref='author', lazy=True)
def __repr__(self):
return f"{self.username} ({self.email})"
class PersonalData(db.Model):
id = db.Column(db.Integer, primary_key = True)
date_birth = db.Column(db.DateTime)
image_file = db.Column(db.String(20), nullable=False, default='default.jpg')
interests = db.Column(db.Text)
experties = db.Column(db.Text) #Потом сделать отдельную таблицу...
#o2o
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
#o2m
class Person(db.Model):
id = db.Column(db.Integer, primary_key = True)
first_name = db.Column(db.String(30), nullable=False)
middle_name = db.Column(db.String(40), nullable=False)
last_name = db.Column(db.String(60), nullable=False)
email = db.Column(db.String(120))
license = db.Column(db.String(120))
address = db.Column(db.String(240))
telephone = db.Column(db.String(30))
#o2o
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
#o2m
signers = db.relationship('Signer', backref='person', lazy=True)
def __repr__(self):
return f"{self.last_name.Capitalize} {self.first_name[0].Upper}. {self.middle_name[0].Upper}."
class ConstrProject(db.Model):
__tablename__ = 'constrproject'
id = db.Column(db.Integer, primary_key = True)
name = db.Column(db.String(120), nullable=False, default='New Project')
full_title = db.Column(db.Text, default='New Project')
notes = db.Column(db.Text)
public = db.Column(db.Boolean, default=True) #? check expamples
date_created = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
date_last_edit = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
document_template = db.Column(db.Integer, nullable=False, default=1) #later to m2m
print_settings = db.Column(db.Integer, nullable=False, default=1) #later to m2m
address = db.Column(db.String(240))
#o2m
documents = db.relationship('Document', backref='project', lazy=True)
#m2o
owner_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False) #+ #default = CurrentUser
developer_id = db.Column(db.Integer, db.ForeignKey('company.id'))
main_contractor_id = db.Column(db.Integer, db.ForeignKey('company.id'))
architect_id = db.Column(db.Integer, db.ForeignKey('company.id'))
subcontractor_id = db.Column(db.Integer, db.ForeignKey('company.id'))
other_id = db.Column(db.Integer, db.ForeignKey('company.id'))
developer = db.relationship('Company', foreign_keys=[developer_id], back_populates='constr_projects_developed')
main_contractor = db.relationship('Company', foreign_keys=[main_contractor_id], back_populates='constr_projects_main_contracts')
architect = db.relationship('Company', foreign_keys=[architect_id], back_populates='constr_projects_architect')
subcontractor = db.relationship('Company', foreign_keys=[subcontractor_id], back_populates='constr_projects_subcontracts')
other = db.relationship('Company', foreign_keys=[other_id], back_populates='constr_projects_other')
tech_control_reps_id = db.Column(db.Integer, db.ForeignKey('signer.id'), nullable=False)
main_contractor_reps_id = db.Column(db.Integer, db.ForeignKey('signer.id'), nullable=False)
architect_reps_id = db.Column(db.Integer, db.ForeignKey('signer.id'), nullable=False)
subcontractor_reps_id = db.Column(db.Integer, db.ForeignKey('signer.id'), nullable=False)
other_reps_id = db.Column(db.Integer, db.ForeignKey('signer.id'), nullable=False)
tech_control_reps = db.relationship('Signer', foreign_keys=[tech_control_reps_id], back_populates='tech_control_projects')
main_contractor_reps = db.relationship('Signer', foreign_keys=[main_contractor_reps_id], back_populates='main_contractor_projects')
architect_reps = db.relationship('Signer', foreign_keys=[architect_reps_id], back_populates='architect_projects')
subcontractor_reps = db.relationship('Signer', foreign_keys=[subcontractor_reps_id], back_populates='subcontractor_projects')
other_reps = db.relationship('Signer', foreign_keys=[other_reps_id], back_populates='others_projects')
def __repr__(self):
return f"Site: {self.name}, (id{self.id})"
class Signer(db.Model):
id = db.Column(db.Integer, primary_key = True)
decree = db.Column(db.String(120))
job_title = db.Column(db.String(120))
date_duty_start = db.Column(db.DateTime)
date_duty_end = db.Column(db.DateTime)
#o2m
person_id = db.Column(db.Integer, db.ForeignKey('person.id'), nullable=False)
company_id = db.Column(db.Integer, db.ForeignKey('company.id'), nullable=False)
#m2o
tech_control_projects = db.relationship('ConstrProject', back_populates='tech_control_reps')
main_contractor_projects = db.relationship('ConstrProject', back_populates='main_contractor_reps')
architect_projects = db.relationship('ConstrProject', back_populates='architect_reps')
subcontractor_projects = db.relationship('ConstrProject', back_populates='subcontractor_reps')
others_projects = db.relationship('ConstrProject', back_populates='other_reps')
def __repr__(self):
return f"{self.job_title} as per {self.decree}." #название компании как подтянуть
class Company(db.Model):
id = db.Column(db.Integer, primary_key = True)
name = db.Column(db.String(60))
full_title = db.Column(db.String(240))
tin = db.Column(db.Integer)
kpp = db.Column(db.Integer)
ogrn = db.Column(db.Integer)
email = db.Column(db.String(120))
address = db.Column(db.String(240))
telephone = db.Column(db.String(30))
#o2m
license_number = db.Column(db.String(40), nullable = False)
license_date_issued = db.Column(db.DateTime)
license_category = db.Column(db.String(120), default = '2nd')
license_issued_by = db.Column(db.String(120))
license_issued_by_tin = db.Column(db.Integer)
license_issued_by_kpp = db.Column(db.Integer)
license_issued_by_ogrn = db.Column(db.Integer)
signers = db.relationship('Signer', backref='company', lazy=True)
constr_projects_developed = db.relationship('ConstrProject', back_populates='developer')
constr_projects_main_contracts = db.relationship('ConstrProject', back_populates='main_contractor')
constr_projects_architect = db.relationship('ConstrProject', back_populates='architect')
constr_projects_subcontracts = db.relationship('ConstrProject', back_populates='subcontractor')
constr_projects_other = db.relationship('ConstrProject', back_populates='other')
def __repr__(self):
return f"{self.name}"
class Post(db.Model):
id = db.Column(db.Integer, primary_key = True)
title = db.Column(db.String(100), nullable=False)
date_posted = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
content = db.Column(db.Text, nullable=False)
#o2m
comments = db.relationship('PostComment', backref='Post', lazy=True)
#m2o
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
def __repr__(self):
return f"Post('{self.title}', '{self.date_posted}')"
class PostComment(db.Model):
id = db.Column(db.Integer, primary_key = True)
date_posted = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
content = db.Column(db.Text, nullable=False)
#m2o
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
post_id = db.Column(db.Integer, db.ForeignKey('post.id'), nullable=False)
def __repr__(self):
return f"Comment('{self.id}', '{self.date_posted}')"
class Document(db.Model):
id = db.Column(db.Integer, primary_key = True)
type = db.Column(db.String(60), nullable=False, default='АОСР')
date_last_edit = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
notes = db.Column(db.Text)
public = db.Column(db.Boolean, default=True)
number = db.Column(db.String(20), nullable=False)
date = db.Column(db.DateTime, default=datetime.utcnow)
job_name = db.Column(db.Text) #? обязательный? на каком этапе делать проверку?
job_place = db.Column(db.String(200))
date_job_start = db.Column(db.DateTime, default=datetime.utcnow)
date_job_end = db.Column(db.DateTime, default=datetime.utcnow)
regulations = db.Column(db.Text)
next_job_allowed = db.Column(db.String(240))
attachments_user_defined = db.Column(db.Text)
#o2m
attachments = db.relationship('Attachment', backref='document', lazy=True)
#m2o
project_id = db.Column(db.Integer, db.ForeignKey('constrproject.id'), nullable=False)
author_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
#m2m
arch_docs = db.Column(db.Text)
building_materials = db.Column(db.Text)
work_drawings = db.Column(db.Text)
def __repr__(self):
return f"АОСР ('{self.number}', '{self.job_name} {self.job_place}', '{self.project}' )"
class Attachment(db.Model):
id = db.Column(db.Integer, primary_key = True)
type_of_document = db.Column(db.String(60), nullable=False, default="QAC")
number = db.Column(db.String(50), nullable=False)
date = db.Column(db.DateTime)
date_valid_start = db.Column(db.DateTime)
date_valid_end = db.Column(db.DateTime)
contents = db.Column(db.Text)
type_of_file = db.Column(db.String(10), nullable=False, default = 'jpg')
image_file = db.Column(db.String(20), nullable=False)
#m2o
author_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
document_id = db.Column(db.Integer, db.ForeignKey('document.id'), nullable=False)
def __repr__(self):
if self.text:
return f'{self.text}'
return f'+{self.type_of_document} id{self.id} ({self.type_of_file})'
I cannot understand why, when I try to create an instance of a "Document"
I get errors like this:
sqlalchemy.exc.AmbiguousForeignKeysError: Could not determine join
condition between parent/child tables on relationship
Signer.tech_control_projects - there are multiple foreign key paths
linking the tables. Specify the 'foreign_keys' argument, providing a
list of those columns which should be counted as containing a foreign
key reference to the parent table.
or
sqlalchemy.exc.InvalidRequestError: When initializing mapper
Mapper|ConstrProject|constrproject, expression 'tech_control_reps_id'
failed to locate a name ("name 'tech_control_reps_id' is not
defined"). If this is a class name, consider adding this
relationship() to the class
after both dependent classes have been defined.
I haven't even tried to create these classes. Adding "foreign_keys" doesn't seem to help either. all relationships declared as strings. I tried to use lambda's also without success.
Nevertheless moving the order of class declearations alters the error messages i get...
I cannot find any good examples (resources) of more complicated databases with multiple many-to-many and one-to-many relationships in Each class. Usually examples are very basic and obvious.
So I would really appreciate if you post links to such projects or tutorials.
I wanted to learn some of it myself so I created a working example with one-to-one and multiple one-to-many relationships based on your code (User, Person, Post and Comment classes). I hope it will be a good (simple but not trivial) example for you.
'''SQLAlchemy one-to-one and one-to-many SSCCE'''
import sqlalchemy
import sqlalchemy.ext.declarative
from passlib.hash import pbkdf2_sha256
Base = sqlalchemy.ext.declarative.declarative_base()
class User(Base):
__tablename__ = 'users'
user_id = sqlalchemy.Column(sqlalchemy.Integer, primary_key=True)
username = sqlalchemy.Column(sqlalchemy.String(20), unique=True, nullable=False)
email = sqlalchemy.Column(sqlalchemy.String(120), unique=True, nullable=False)
password = sqlalchemy.Column(sqlalchemy.String(100), nullable=False)
registered = sqlalchemy.Column(
sqlalchemy.DateTime(timezone=True),
nullable=False,
server_default=sqlalchemy.func.now()
)
#o2o
person = sqlalchemy.orm.relationship(
'Person',
uselist=False,
back_populates='user',
lazy='joined'
)
#o2m
posts = sqlalchemy.orm.relationship('Post', back_populates='user')
comments = sqlalchemy.orm.relationship('Comment', back_populates='user')
def __repr__(self):
return f'{self.username} ({self.email})'
class Person(Base):
__tablename__ = 'persons'
person_id = sqlalchemy.Column(
sqlalchemy.Integer,
sqlalchemy.ForeignKey('users.user_id'),
primary_key=True
)
first_name = sqlalchemy.Column(sqlalchemy.String(30), nullable=False)
middle_name = sqlalchemy.Column(sqlalchemy.String(40), nullable=False)
last_name = sqlalchemy.Column(sqlalchemy.String(60), nullable=False)
#o2o
user = sqlalchemy.orm.relationship('User', back_populates='person', lazy='joined')
def __repr__(self):
return (
f'{self.last_name.upper()}'
f' {self.first_name[:1].upper()}.'
f' {self.middle_name[:1].upper()}.'
)
class Post(Base):
__tablename__ = 'posts'
post_id = sqlalchemy.Column(sqlalchemy.Integer, primary_key=True)
title = sqlalchemy.Column(sqlalchemy.String(100), nullable=False)
posted = sqlalchemy.Column(
sqlalchemy.DateTime(timezone=True),
nullable=False,
server_default=sqlalchemy.func.now()
)
content = sqlalchemy.Column(sqlalchemy.Text, nullable=False)
#o2m
comments = sqlalchemy.orm.relationship('Comment', back_populates='post')
#m2o
user_id = sqlalchemy.Column(
sqlalchemy.Integer,
sqlalchemy.ForeignKey('users.user_id'),
nullable=False
)
user = sqlalchemy.orm.relationship('User', uselist=False, back_populates='posts', lazy='joined')
def __repr__(self):
return f'Post({self.title!r}, {self.posted!r})'
class Comment(Base):
__tablename__ = 'comments'
comment_id = sqlalchemy.Column(sqlalchemy.Integer, primary_key=True)
posted = sqlalchemy.Column(
sqlalchemy.DateTime(timezone=True),
nullable=False,
server_default=sqlalchemy.func.now()
)
content = sqlalchemy.Column(sqlalchemy.Text, nullable=False)
#m2o
user_id = sqlalchemy.Column(
sqlalchemy.Integer,
sqlalchemy.ForeignKey('users.user_id'),
nullable=False
)
user = sqlalchemy.orm.relationship(
'User',
uselist=False,
back_populates='comments',
lazy='joined'
)
post_id = sqlalchemy.Column(
sqlalchemy.Integer,
sqlalchemy.ForeignKey('posts.post_id'),
nullable=False
)
post = sqlalchemy.orm.relationship(
'Post',
uselist=False,
back_populates='comments',
lazy='joined'
)
def __repr__(self):
return f'Comment({self.comment_id!r}, {self.posted!r})'
def main():
engine = sqlalchemy.create_engine(
'postgresql+psycopg2:///stack',
echo=True,
server_side_cursors=True,
use_batch_mode=True
)
Base.metadata.create_all(engine)
Session = sqlalchemy.orm.sessionmaker(bind=engine)
session = Session()
session.commit()
try:
the_user = session.query(User).filter(User.username == 'example').one()
except sqlalchemy.orm.exc.NoResultFound:
the_user = User(
username='example',
email='example#example.com',
password=pbkdf2_sha256.hash('correct horse battery staple')
)
the_user.person = Person(first_name='Ex', middle_name='', last_name='Ample')
session.add(the_user)
print(the_user)
print(the_user.person)
if not the_user.posts:
the_user.posts.append(Post(title='First post', content='Lorem ipsum'))
session.commit()
print(the_user.posts[0])
if not the_user.posts[0].comments:
the_user.posts[0].comments.append(Comment(content='Me too', user=the_user))
session.commit()
print(the_user.posts[0].comments[0])
if __name__ == '__main__':
main()
Several comments:
I don't think it is easy to have foreign-keys both ways for a mandatory one-to-one relationship.
I made both User and Person use the same id numbers, as they are one-to-one.
I made the PostgreSQL now() as the default value for timestamps, instead of client-side utcnow.
I made the timestamps use "timestamp with timezone" type - the "timestamp" type (without timezone) is an abomination.
"user" is a bad name for a table, as this is also a keyword in PostgreSQL, so I changed it to "users". Other tables also changed to plural form for consistency.
A secure password storage is a must.
I used back_populates consistently, as it is more explicit and works better with static code analyzers than backref.

errorclass, errorvalue when I try to add new model/table to existing database

When I try to add new model to SQLAlchemy I get error ( I am using MySQL below)
raise errorclass, errorvalue
sqlalchemy.exc.OperationalError 1005 Can't create table
I have model/table PlayerModel/players since beginning of the time and I am trying now to add new table (Base has id column id)
class Base(object):
def __tablename__(self):
return self.__name__.lower()
id = Column(Integer, primary_key=True, nullable=False)
class PlayerModel(Base):
__tablename__ = 'players'
alliances_id = Column(Integer, ForeignKey('alliances.id'), nullable=True)
alliance = relationship('AllianceModel')
username = Column(String(90), nullable=True, default=None)
email = Column(String(75), nullable=True, default=None)
password = Column(String(128), nullable=True, default=None)
money = Column(Integer, nullable=False, default=INITIAL_MONEY)
# used for push notifications
push_token = Column(String(64), nullable=True)
registered_for_push = Column(Boolean, nullable=False, default=False)
device_id = Column(String(64), nullable=True)
device_type = Column(String(64), nullable=True)
device_os = Column(Integer, nullable=True)
notify = Column(Boolean, default=True)
def __repr__(self):
return "<Player('%s')>" % (self.type)
and here throw error
class ArmyModel(Base):
__tablename__ = 'army'
player_id = Column(Integer, ForeignKey('players.id', ondelete='CASCADE'), nullable=False, index=True)
speed = Column(Float, nullable=False, default=1)
# mode of army behavior ( always fight, ignore )
mode = Column(Integer, nullable=False)
x = Column(Float, nullable=False, default=0)
y = Column(Float, nullable=False, default=0)
z = Column(Float, nullable=False, default=0)
def __repr__(self):
return "<Army('%s')>" % (self.type)

Categories

Resources