Плохая схема или запрос? - PullRequest
0 голосов
/ 20 февраля 2020

Итак, я работаю над проектом, который будет собирать данные из инвентаря нескольких веб-сайтов. С этих сайтов я соскребаю количество их инвентаря и цены, указанные для каждого размера каждого предмета. Я собираю данные каждый день, чтобы отслеживать цены с течением времени. Мои модели выглядят так:

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 мог бы посоветовать, он был бы признателен.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...