Запрос нескольких связанных таблиц с помощью join для создания одной таблицы с использованием sqlalchemy - PullRequest
0 голосов
/ 15 мая 2019

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

class Book(ResourceMixin, db.Model):

    __tablename__ = 'book'

    id = db.Column(db.Integer, primary_key=True)

    title = db.Column(db.String(85))
    stock_amount = db.Column(db.Integer, nullable=False, server_default='0')

    #Foreign Key
    category_id = db.Column(db.Integer, db.ForeignKey('category.id',
                                                    onupdate='CASCADE',
                                                    ondelete='CASCADE'),
                        index=True, nullable=False)
  • Таблица категорий
class Category(ResourceMixin, db.Model):

    __tablename__ = 'category'

    id = db.Column(db.Integer, primary_key=True)
    category_name = db.Column(db.String(85))
    isbn1 = db.Column(db.String(13))
    isbn2 = db.Column(db.String(13))
    total_stock_amount = db.Column(db.Integer)
    unit_price = db.Column(db.Float)
    selling_price = db.Column(db.Float)
    bank_transfer_price = db.Column(db.Float)
    unit_cost = db.Column(db.Float)
    author = db.Column(db.String(100))


    ordered = db.Column('is_ordered', db.Boolean(), nullable=False, server_default='0')

    #Association Proxies

    orders = association_proxy('book_orders', 'order')
    stores = association_proxy('book_store', 'store')

    supplier_id = db.Column(db.Integer, db.ForeignKey('suppliers.id',
                                                    onupdate='CASCADE',
                                                    ondelete='CASCADE'),
                        index=True, nullable=False)

    #Relationship with Books

    books = db.relationship(Book, backref=db.backref('book_category'), innerjoin=True)
  • BookStore таблица, которая наследуется от Category таблицы

class BookStore(ResourceMixin, db.Model):

    __tablename__ = 'book_store'

    id = db.Column(db.Integer, primary_key=True)
    category_id = db.Column(db.Integer, db.ForeignKey('category.id'))
    store_id = db.Column(db.Integer, db.ForeignKey('store.id'))
    isbn1 = db.Column(db.String)
    isbn2 = db.Column(db.String)
    book_amount = db.Column(db.Integer)



    #Bidirectional attribute/collection of 'category'/'book_store'

    category = db.relationship('Category', backref = db.backref('book_store', cascade='all, delete-orphan'),
                            lazy='joined', innerjoin=True,
                            order_by='Category.category_name')


    bookstore_cart = db.relationship('StoreCart', backref='book_store_cart', passive_deletes=True)

    book_purchases = association_proxy('book_orders', 'customer_purchases')

    #Reference to the 'Store' object

    store = db.relationship('Store')
  • CustomerPurchase таблица, которая наследуется от BookStore
class CustomerPurchase(ResourceMixin, db.Model):

    __tablename__ = 'customer_purchase'

    id = db.Column(db.Integer, primary_key=True)

    book_store_category_id = db.Column(db.Integer, db.ForeignKey('book_store.id'))
    customer_order_id = db.Column(db.Integer, db.ForeignKey('customer_orders.id'))

    book_title = db.Column(db.Text)
    unit_price = db.Column(db.Float)
    quantity = db.Column(db.Float) 
    total_price = db.Column(db.Float)

    store_id = db.Column(db.Integer, db.ForeignKey('store.id',
                                                    onupdate='CASCADE',
                                                    ondelete='CASCADE'),
                        index=True)

    #Bidirectional attribute/collection of 'bookstore'/'customer purchase'

    book_purchase = db.relationship('BookStore', backref = db.backref('customer_purchases', cascade='all, delete-orphan'),
                            lazy='joined', innerjoin=True,
                            order_by='BookStore.isbn1')

    #Bidirectional attribute/collection of 'store'/'purchase'

    customer_order = db.relationship('CustomerOrders')

Позвольте мне объяснить вам принцип работы.Таким образом, чтобы продать книги, пользователь должен перевести Category на BookStore, а затем он / она может продать его.Продажи хранятся в таблице CustomerPurchase.Если книги в инвентаре закончены, то Пользователь должен заказать книги у поставщика и поместить их в инвентаре, дата ввода в инвентаре фиксируется для создания отчета в будущем.

Моя таблица отчета должна содержать эти столбцы

   book_title | unit_cost | amount_in_stock | revenue | amount_ordered | total_price_of_ordered_books | amount_sold | revenue | amount_left | total_price_of_amount_left | 

Мой запрос:

bp = db.session.query(CustomerPurchase.book_store_category_id, BookStore.category, func.sum(CustomerPurchase.quantity).label('quantity'))\
     .filter(CustomerPurchase.created_on >= start_date)\
     .filter(CustomerPurchase.created_on <= end_date)\
     .group_by(CustomerPurchase.book_store_category_id, BookStore.id, Category.id)\
     .subquery()


cp = db.session.query(BookStore, bp.c.quantity)\
                     .join(bp, BookStore.category_id == bp.c.book_store_category_id)\
                     .distinct(bp.c.book_store_category_id)\
                     .order_by(bp.c.book_store_category_id)\
                     .all()

Он выводит таблицу CustomerPurchase и BookStore, но не 'Например, я не могу выйти за пределы CustomerPurchase.book_purchase.category.books.stock_amount или BookStore.category.books.stock_amount

Когда я хочу получить доступ к CustomerPurchase.book_purchase, возникает ошибка UndefinedError: 'sqlalchemy.util._collections.result object' has no attribute 'book_purchase'

Любая помощь очень ценится!Заранее спасибо!

1 Ответ

0 голосов
/ 20 мая 2019

После 2 недель исследований и совместной работы мне удалось решить проблему:

Теперь он выводит все нужные столбцы и возвращает, даже если столбец имеет значение NULL:

my_query = db.session.query(CustomerPurchase.book_title, Category.unit_cost, Category.total_stock_amount, BookStore.book_amount,
                    func.sum(CustomerPurchase.quantity).label('quantity'),
                    func.sum(Book.stock_amount).label('book_stock_amount'))\
                    .join(BookStore)\
                    .join(Category)\
                    .outerjoin(Book)\
                    .filter(CustomerPurchase.created_on >= report.start_date.date())\
                    .filter(CustomerPurchase.created_on <= report.end_date.date())\
                    .group_by(CustomerPurchase.book_title,
                            Category.unit_cost, Category.total_stock_amount,
                            BookStore.book_amount).all()

Как простокак!По сути, мне нужно выбрать каждую колонку, которую я хочу отобразить.Также меня беспокоило NULL возвращаемое значение Book.stock_amount, но после того, как я использовал outerjoin в таблице Book, мне удалось извлечь все данные, необходимые для моего отчета.

Я надеюсь, что это поможет некоторым людям там!:)

...