Итак, я работаю над проектом, который будет собирать данные из инвентаря нескольких веб-сайтов. С этих сайтов я соскребаю количество их инвентаря и цены, указанные для каждого размера каждого предмета. Я собираю данные каждый день, чтобы отслеживать цены с течением времени. Мои модели выглядят так:
class Shoe(Base):
__tablename__ = "shoes"
id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(String)
style = Column(String)
image = Column(String)
release_date = Column(String)
colorway = Column(String)
price_history = relationship('PriceHistory', back_populates='shoe')
sale_history = relationship('SaleHistory', back_populates='shoe')
web_pages = relationship('ShoePages', back_populates='shoe')
class ShoePages(Base):
__tablename__ = "shoespages"
id = Column(Integer, primary_key=True)
url = Column(String)
site = Column(String)
shoe_id = Column(Integer, ForeignKey('shoes.id'))
shoe = relationship('Shoe', back_populates='web_pages')
class PriceHistory(Base):
__tablename__ = "pricehistory"
id = Column(Integer, primary_key=True)
size = Column(String)
date = Column(Date)
site = Column(String)
price = Column(Float)
stock = Column(Integer)
in_stock = Column(Boolean)
shoe_id = Column(Integer, ForeignKey('shoes.id'))
shoe = relationship('Shoe', back_populates='price_history')
Я хочу построить запрос, который позволит мне посмотреть цены товаров, которые доступны на нескольких сайтах.
Таким образом, я хочу присоединить таблицу обуви к таблице обуви и таблице цен по истории один раз для каждого сайта, который присутствует в базе данных. Поскольку цены очищаются каждый день, мне нужно объединить запросы как по идентификаторам обуви, так и по датам истории цен. Я написал функцию, чтобы попытаться сгенерировать требуемый запрос. Но все это стало настолько запутанным, что я думаю, что есть или более простой способ сделать это в SQLAlchemy, которого я пропускаю, или я плохо спроектировал свои таблицы, делая это более трудным, чем это должно быть.
Ниже приведена функция, которую я написал для создания запроса к этим данным, я считаю, что сейчас он возвращает больший результат, чем должен, поскольку он содержит дубликаты. В настоящее время я пытаюсь
def prices_across_sites_v1(session, real_q=False):
sites = session.query(
PriceHistory.site
).distinct()
sites = [site[0] for site in sites.all()]
print(f'sites: {sites}')
price_queries = []
page_queries = []
for site in sites:
price_queries.append(
session.query(
PriceHistory.shoe_id,
PriceHistory.size,
PriceHistory.date,
PriceHistory.price.label(f'{site}_price'),
PriceHistory.stock.label(f'{site}_stock'),
PriceHistory.in_stock.label(f'{site}_in_stock'),
).filter(
and_(
PriceHistory.site == site
)
)
)
page_queries.append(
session.query(
ShoePages.shoe_id,
ShoePages.url.label(f'{site}_url')
).filter(
ShoePages.site == site
)
)
skips = ('date', 'size', 'shoe_id')
site_sepcific = lambda q: [col for col in dir(q.c) if '__' not in col and col not in skips]
price_queries = [q.subquery() for q in price_queries]
page_queries = [q.subquery() for q in page_queries]
query = session.query(
*[Shoe.name, Shoe.style, Shoe.image, Shoe.colorway, Shoe.release_date] +
[getattr(q.c, col) for q in price_queries for col in site_sepcific(q)] +
page_queries,
func.coalesce(*[q.c.size for q in price_queries]).label('size'),
func.coalesce(*[q.c.date for q in price_queries]).label('date')
).outerjoin(
*[(price_query, price_query.c.shoe_id == Shoe.id) for price_query in price_queries]
).outerjoin(
*[(page_query, page_query.c.shoe_id == Shoe.id) for page_query in page_queries]
).filter(
or_(
*[and_(
qa.c.shoe_id == qb.c.shoe_id,
qa.c.date == qb.c.date,
qa.c.size == qb.c.size
) for qa, qb in combinations(price_queries, 2)]
)
)
if real_q:
return query
else:
return str(query.statement.compile(
dialect=postgresql.dialect(),
compile_kwargs={"literal_binds": True}
))
В конечном итоге Мне нужен запрос, который будет возвращать таблицу, в которой в каждой строке указан конкретный c размер элемента и цена элемента на каждом сайте в конкретную c дату. Если кто-то здесь с большим опытом работы SQL или SQLAlchemy мог бы посоветовать, он был бы признателен.