I am defining a table in Flask like
groups = db.Table(
"types",
db.Column("one_id", db.Integer, db.ForeignKey("one.id")),
db.Column("two_id", db.Integer, db.ForeignKey("two.id")),
UniqueConstraint('one_id', 'two_id', name='uix_1') #Unique constraint given for unique-together.
)
But this is not working.
I think you can refer to an old topic https://stackoverflow.com/a/10061143/18269348
Here is the code :
# version1: table definition
mytable = Table('mytable', meta,
# ...
Column('customer_id', Integer, ForeignKey('customers.customer_id')),
Column('location_code', Unicode(10)),
UniqueConstraint('customer_id', 'location_code', name='uix_1')
)
# or the index, which will ensure uniqueness as well
Index('myindex', mytable.c.customer_id, mytable.c.location_code, unique=True)
# version2: declarative
class Location(Base):
__tablename__ = 'locations'
id = Column(Integer, primary_key = True)
customer_id = Column(Integer, ForeignKey('customers.customer_id'),
nullable=False)
location_code = Column(Unicode(10), nullable=False)
__table_args__ = (UniqueConstraint('customer_id', 'location_code',
name='_customer_location_uc'),
)
You have a little explanation on the post and a link to the official documentation of sqlalchemy.
Thanks to Van who posted that.
Related
My models look like this:
class Company(DB_BASE):
__tablename__ = 'Company'
id = Column(Integer, primary_key=True, index=True)
...
products = relationship('Product', secondary=Company_Products, backref='Company')
class Product(DB_BASE):
__tablename__ = 'Product'
id = Column(Integer, primary_key=True, index=True)
...
companies = relationship('Company', secondary=Company_Products, backref='Product')
This is my association table
Company_Products = Table(
'Company_Products',
DB_BASE.metadata,
Column('id', Integer, primary_key=True),
Column('company_id', Integer, ForeignKey('Company.id')),
Column('product_id', Integer, ForeignKey('Product.id')),
Column('quantity', Integer, default=0),
Column('price_per_unit', Integer, default=0),
)
And this is how I'm querying the association table.
company_product = db.query(Company_Products).filter_by(product_id=id, company_id=user.company_id).first()
company_product.quantity = data.data['quantity']
company_product.price = data.data['price']
After creating the many-to-many relationship between a Company and a Product, I would like to modify the relationship extra data, quantity and price_per_unit in this instance. After querying the association object, modifying any attribute yields:
AttributeError: can't set attribute 'quantity'
Follow up on my question, the solution which ended up working for me is making a new model and using it to somewhat simulate an association table.
class Company_Products(DB_BASE):
__tablename__ = 'Company_Products'
id = Column(Integer, primary_key=True, index=True)
...
quantity = Column(String) # 1 - client, 2 - furnizor
price_per_unit = Column(String)
company_id = Column(Integer, ForeignKey('Company.id'))
company = relationship('Company', back_populates='products', lazy='select')
product_id = Column(Integer, ForeignKey('Product.id'))
product = relationship('Product', back_populates='companies', lazy='select')
This is definitely not the best solution, if I come up with something else or come across something which might work out, I will edit this.
There are tables for my question.
class TemplateExtra(ExtraBase, InsertMixin, TimestampMixin):
__tablename__ = 'template_extra'
id = Column(Integer, primary_key=True, autoincrement=False)
name = Column(Text, nullable=False)
roles = relationship(
'RecipientRoleExtra',
secondary='template_to_role',
)
class RecipientRoleExtra(
ExtraBase, InsertMixin, TimestampMixin,
SelectMixin, UpdateMixin,
):
__tablename__ = 'recipient_role'
id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(Text, nullable=False)
description = Column(Text, nullable=False)
class TemplateToRecipientRoleExtra(ExtraBase, InsertMixin, TimestampMixin):
__tablename__ = 'template_to_role'
id = Column(Integer, primary_key=True, autoincrement=True)
template_id = Column(Integer, ForeignKey('template_extra.id'))
role_id = Column(Integer, ForeignKey('recipient_role.id'))
I want to select all templates with prefetched roles in two sql-queries like Django ORM does with prefetch_related. Can I do it?
This is my current attempt.
def test_custom():
# creating engine with echo=True
s = DBSession()
for t in s.query(TemplateExtra).join(RecipientRoleExtra, TemplateExtra.roles).all():
print(f'id = {t.id}')
for r in t.roles:
print(f'-- {r.name}')
But..
it generates select query for every template to select its roles. Can I make sqlalchemy to do only one query?
generated queries for roles are without join, just FROM recipient_role, template_to_role with WHERE %(param_1)s = template_to_role.template_id AND recipient_role.id = template_to_role.role_id. Is it correct?
Can u help me?
Based on this answer:
flask many to many join as done by prefetch_related from django
Maybe somthing like this:
roles = TemplateExtra.query.options(db.joinedload(TemplateExtra.roles)).all
Let me know if it worked.
I am a newbie in SQL Alchemy and I need a help to implement the following relationship :
I have two tables Trends and ClosestTrends and I want to declare two one-to-many relationships :
Tables relationship
In SQL, it would be :
ALTER TABLE "closest_trends" ADD FOREIGN KEY ("id_trend_ref") REFERENCES "trends" ("id") ON DELETE CASCADE;
ALTER TABLE "closest_trends" ADD FOREIGN KEY ("id_trend_close") REFERENCES "trends" ("id") ON DELETE CASCADE;
I tried the following implementation :
class Trends(Base):
__tablename__ = "trends"
__table_args__ = (
UniqueConstraint(
"name", "id_region", "language_iso", name="name_id_region_language"
),
)
id = Column(Integer, primary_key=True, index=True, unique=True)
.
.
.
closest_trends = relationship("ClosestTrends", backref="Trends")
def __str__(self):
return "Trends"
class ClosestTrends(Base):
__tablename__ = "closest_trends"
__table_args__ = (
UniqueConstraint(
"id_trend_ref", "id_trend_close", name="id_trend_ref_id_trend_close"
),
)
id = Column(Integer, primary_key=True, index=True, unique=True)
.
.
.
id_trend_ref = Column(
Integer, ForeignKey("trends.id", ondelete="CASCADE"), nullable=False
)
id_trend_close = Column(
Integer, ForeignKey("trends.id", ondelete="CASCADE"), nullable=False
)
def __str__(self):
return "ClosestTrends"
I does not work and I am receiving the following error:
sqlalchemy.exc.AmbiguousForeignKeysError: Could not determine join
condition between parent/child tables on relationship
Trends.closest_trends - 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.
Does anyone have an idea how to fix this ?
Many thanks
your solution is written in official site.
https://docs.sqlalchemy.org/en/13/orm/join_conditions.html#handling-multiple-join-paths
according to official site, I implement like this.
class Trends(Base):
__tablename__ = "trends"
__table_args__ = (
UniqueConstraint(
"name", "id_region", "language_iso", name="name_id_region_language"
),
)
id = Column(Integer, primary_key=True, index=True, unique=True)
.
.
.
# closest_trends = relationship("ClosestTrends", backref="Trends")
def __str__(self):
return "Trends"
class ClosestTrends(Base):
__tablename__ = "closest_trends"
__table_args__ = (
UniqueConstraint(
"id_trend_ref", "id_trend_close", name="id_trend_ref_id_trend_close"
),
)
id = Column(Integer, primary_key=True, index=True, unique=True)
.
.
.
id_trend_ref = Column(
Integer, ForeignKey("trends.id", ondelete="CASCADE"), nullable=False
)
id_trend_close = Column(
Integer, ForeignKey("trends.id", ondelete="CASCADE"), nullable=False
)
trend_ref = relationship("Trends", foreign_keys=[id_trend_ref])
trend_close = relationship("Trends", foreign_keys=[id_trend_close])
def __str__(self):
I am using sqlachemy with MySQL backend. Actually having problems optimizing a query.
I have the following set of models:
class Book(Base):
__tablename__ = 'books'
name = Column(String(32), primary_key=True)
sku = Column(Integer, nullable=False)
class Author(Base):
__tablename__ = 'authors'
name = Column(String(64), primary_key=True)
# book
books = relationship(Book, secondary=Table(
'author_books', Base.metadata,
Column('author', String(32),
ForeignKey(Author.name), primary_key=True),
Column('book', String(64), ForeignKey("book.title"),
primary_key=True)
), backref=backref('book_authors', cascade="save-update"))
And was doing a query:
authors_with_books = [(autor.name, [book.name for book in books]) for author in session.query(Authors)]
Which is actually very very slow :(
Your query is slow because you are joining data on python.
Do it on database.
try something like that:
authors_with_books = session.query(Author.name, Book.name)
It'll create a join on SQL
authors_with_books = session.query(Author).join(Author.books)
or
Use 'lazyload' param.
Try rewrite many_to_many table in models. It's work for me:
class Author(Base):
__tablename__ = 'authors'
name = Column(String(64), primary_key=True)
books = relationship('Book', secondary='author_books')
author_book = Table(
'author_books', Base.metadata,
Column('author', String(32), ForeignKey("author.name", match=u'FULL'), primary_key=True),
Column('book', String(64), ForeignKey("book.title", match=u'FULL'), primary_key=True)
)
And I think ForeignKey(Author.name) - Incorrect code, fix it.
I created a many to many relationship with sqlalchemy like this:
subject_books = Table('subject_books', Base.metadata,
Column('subject_id', Integer, ForeignKey('subjects.id')),
Column('book_id', Integer, ForeignKey('books.id')),
Column('group', Integer)
)
class Subject(Base):
__tablename__ = 'subjects'
id = Column(Integer, primary_key=True)
value = Column(Unicode(255), unique=True)
class Book(Base):
__tablename__ = 'books'
id = Column(Integer, primary_key=True)
title = Column(Unicode(255))
isbn = Column(Unicode(24))
subjects = relationship('Subject', secondary=subject_books, collection_class=attribute_mapped_collection('group'), backref='books')
after that I created a test like following:
book = Book(title='first book',isbn='test')
book.subjects[0] = Subject(value='first subject')
book.subjects[1] = Subject(value='second subject')
session.add(book)
transaction.commit()
and it works fine. But what I really want is to store more than one subject with the same group value, so I tried the following test:
book = Book(title='first book',isbn='test')
book.subjects[0] = [Subject(value='first subject'),Subject(value='second subject')]
book.subjects[1] = [Subject(value='third subject'),Subject(value='forth subject')]
session.add(book)
transaction.commit()
but it does not work.
Can this be done using sqlalchemy?
Thanks in Advance
Razi
I think you are constructing wrong relation ship.
Your relation ship must be
book M2M subject
subject M2M group
So you have to create one more model for group and that must be assign as m2m in Subject
Your models will be like.
subject_books = Table('subject_books', Base.metadata,
Column('subject_id', Integer, ForeignKey('subjects.id')),
Column('book_id', Integer, ForeignKey('books.id')),
)
subject_group = Table('subject_groups', Base.metadata,
Column('group_id', Integer, ForeignKey('groups.id')),
Column('subject_id', Integer, ForeignKey('subjects.id')),
)
class Subject(Base):
__tablename__ = 'subjects'
id = Column(Integer, primary_key=True)
value = Column(Unicode(255), unique=True)
groups = relationship('Groups', secondary=subject_groups, backref='subjects')
class Groups(Base):
__tablename__ = 'groups'
id = Column(Integer, primary_key=True)
name = Column(Unicode(255), unique=True)
class Book(Base):
__tablename__ = 'books'
id = Column(Integer, primary_key=True)
title = Column(Unicode(255))
isbn = Column(Unicode(24))
subjects = relationship('Subject', secondary=subject_books, backref='books')
I also check the docs for attribute_mapped_collection. But each time I found that each key is associated with only one object not more then one. If you read anywhere then please provide the link so I can check that how it will be fit in your code.
I think this will be help you.