Kaynağa Gözat

Dealing with the problem of multiple read_dir calls on checkout page. Introduced products.yaml as a table of product_id to product_path for faster processing of orders.

main.py - removed extra read_dir calls and replaced them with new logic

db.py - added get/write methods for the products.yaml

template.py - added calls to get product paths

cart.py - updated several functions to use new logic.
slow_tiger 1 yıl önce
ebeveyn
işleme
e82ee349b5
4 değiştirilmiş dosya ile 64 ekleme ve 62 silme
  1. 15 16
      app/cart.py
  2. 36 19
      app/db.py
  3. 10 24
      app/main.py
  4. 3 3
      app/template.py

+ 15 - 16
app/cart.py

@@ -5,7 +5,8 @@ import shortuuid
 
 
 from app.schema import CartUpdate, DocumentProduct, CartSessionItem, Settings, ProductInfoCode
 from app.schema import CartUpdate, DocumentProduct, CartSessionItem, Settings, ProductInfoCode
 from app.template import make_product_info_code
 from app.template import make_product_info_code
-from app.db import get_product_by_product_id
+from app.db import get_product_by_product_id, get_products_id_db
+from app.parser import parse_file
 
 
 
 
 def product_exist_in_cart(
 def product_exist_in_cart(
@@ -45,7 +46,7 @@ def initialize_cart(session, currency: str) -> dict[int, str] | NoReturn:
         }
         }
 
 
 
 
-def get_inventory_amount(session_item, products) -> int | None:
+def get_inventory_amount(session_item, products, settings) -> int | None:
     """Returns the inventory amount value for any product by matching it
     """Returns the inventory amount value for any product by matching it
     against the list of selected products in the cart. We need to make
     against the list of selected products in the cart. We need to make
     use of the selected product's style and size options in order to
     use of the selected product's style and size options in order to
@@ -53,23 +54,18 @@ def get_inventory_amount(session_item, products) -> int | None:
     """
     """
     inventory_amount = None
     inventory_amount = None
 
 
-    for product in products:
-        if product.meta.product_id == session_item["product_id"]:
-            for inventory in product.meta.inventory:
-                if (
-                    inventory.size == session_item["options"]["size"]
-                    and inventory.style == session_item["options"]["style"]
-                ):
-                    inventory_amount = inventory.amount
 
 
-    if inventory_amount:
-        return inventory_amount
+    product = parse_file(settings.git_repo, Path(products["products"][session_item["product_id"]]), settings.block_types)
+
+    for variation in product.meta.inventory:
+        if variation.product_variation_id == session_item["options"]["product_variation_id"]:
+            return variation.amount
 
 
 
 
 def update_cart_meta(
 def update_cart_meta(
         session,
         session,
         shipping_amount: int,
         shipping_amount: int,
-        products: list[DocumentProduct] | None = None
+        settings,
 ) -> NoReturn:
 ) -> NoReturn:
     """Update Meta key of Session Cart (subtotal, shipping, total).
     """Update Meta key of Session Cart (subtotal, shipping, total).
 
 
@@ -81,6 +77,7 @@ def update_cart_meta(
     session_meta_item_amount = 0
     session_meta_item_amount = 0
     session_meta_subtotal = 0
     session_meta_subtotal = 0
     session_meta_weight = 0
     session_meta_weight = 0
+    products = get_products_id_db(settings)
 
 
     for item in session["items"].values():
     for item in session["items"].values():
         if products is not None:
         if products is not None:
@@ -90,7 +87,7 @@ def update_cart_meta(
             # - or adjust user's cart to the max available number of
             # - or adjust user's cart to the max available number of
             #   items set in the inventory of the given item
             #   items set in the inventory of the given item
 
 
-            inventory_amount = get_inventory_amount(item, products)
+            inventory_amount = get_inventory_amount(item, products, settings)
 
 
             if inventory_amount == 0:
             if inventory_amount == 0:
                 # if inventory amount for given item has meanwhile gone to 0,
                 # if inventory amount for given item has meanwhile gone to 0,
@@ -146,6 +143,7 @@ def update_cart(
     shipping_amount: int,
     shipping_amount: int,
     quantity: int,
     quantity: int,
     inventory_amount: int,
     inventory_amount: int,
+    settings,
 ) -> NoReturn:
 ) -> NoReturn:
     """Update (add / remove) Session Cart with given product_id + options
     """Update (add / remove) Session Cart with given product_id + options
     item: if Cart contains the product, increase / decrease product's
     item: if Cart contains the product, increase / decrease product's
@@ -212,7 +210,7 @@ def update_cart(
 
 
                 session["items"][product_id] = update_data
                 session["items"][product_id] = update_data
 
 
-    update_cart_meta(session, shipping_amount)
+    update_cart_meta(session, shipping_amount, settings)
 
 
 
 
 def clear_cart(session, currency: str) -> NoReturn:
 def clear_cart(session, currency: str) -> NoReturn:
@@ -263,9 +261,10 @@ def create_product_list(settings: Settings, cart_items: dict[CartSessionItem]) -
     """
     """
 
 
     product_list = []
     product_list = []
+    products = get_products_id_db()
     
     
     for item in cart_items.values():
     for item in cart_items.values():
-        product = get_product_by_product_id(settings, item.product_id)
+        product = get_product_by_product_id(settings, item.product_id, products)
 
 
         product_path = str(Path(product.meta.path).stem)
         product_path = str(Path(product.meta.path).stem)
         item = ProductInfoCode(path=product_path,
         item = ProductInfoCode(path=product_path,

+ 36 - 19
app/db.py

@@ -134,6 +134,36 @@ def create_variation_id(product: DocumentProduct):
     return None # returns None in case there are no variations of the product or single variant only
     return None # returns None in case there are no variations of the product or single variant only
 
 
 
 
+def get_products_id_db(settings) -> dict:
+    """Returns collection of product_ids and paths associated with it"""
+
+    product_data = {}
+
+    filepath = f'{Path(settings.git_repo)}/products.yaml'
+    p = Path(filepath)
+
+    if p.exists():
+        with open(p, 'r') as f:
+            product_data = yaml.safe_load(f)
+
+    return product_data
+
+
+def write_product_id_db(product:DocumentProduct, settings, products_data = {}):
+    """Adds product_id - path relation to the products.md in product folder"""
+
+    filepath = f'{Path(settings.git_repo)}/products.yaml'
+    product_file_path = f'{Path(settings.git_repo)}/{product.meta.path}/index.md'
+    p = Path(filepath)
+    products_data.setdefault("products", {})
+
+    if product.meta.product_id not in products_data["products"] or not p.exists():
+        products_data["products"][product.meta.product_id] = product_file_path
+
+        with open(p, "w") as f:
+            yaml.dump(products_data, f, default_flow_style = False)
+
+
 def write_variation_id(product:DocumentProduct, settings):
 def write_variation_id(product:DocumentProduct, settings):
     """ Generate and write IDs for variation of the product into file"""
     """ Generate and write IDs for variation of the product into file"""
 
 
@@ -197,27 +227,14 @@ def get_products_by_category(settings):
 def get_product_by_product_id(
 def get_product_by_product_id(
     settings: Settings, 
     settings: Settings, 
     product_id: str,
     product_id: str,
-    products = []
+    products: dict,
 ) -> DocumentProduct:
 ) -> DocumentProduct:
     """Fetch a product by its product-id."""
     """Fetch a product by its product-id."""
-    if not products:
-        products = read_dir(
-            settings.git_repo,
-            settings.document_match,
-            settings.document_exclude,
-            settings.block_types,
-            exclude_doc="products",
-            tree="products",
-    )
-
-    product = None
-
-    for p in products:
-        if p.meta.product_id == product_id:
-            return p
-
-    return product
-
+    if products:
+        product = parse_file(settings.git_repo, Path(products["products"][product_id]), settings.block_types)
+        return product
+    else:
+        return None
 
 
 def get_docs_by_category(category: str, settings):
 def get_docs_by_category(category: str, settings):
     """Read a directory of directories and return a sublist with only the
     """Read a directory of directories and return a sublist with only the

+ 10 - 24
app/main.py

@@ -42,6 +42,8 @@ from app.db import (
     update_status_order,
     update_status_order,
     write_variation_id,
     write_variation_id,
     get_variation_id,
     get_variation_id,
+    write_product_id_db,
+    get_products_id_db,
 )
 )
 from app.email import send_email
 from app.email import send_email
 from app.parser import md, read_dir, read_file
 from app.parser import md, read_dir, read_file
@@ -106,9 +108,11 @@ async def lifespan(app: FastAPI):
         tree="products",
         tree="products",
     )
     )
 
 
+    products_data = get_products_id_db(settings)
+
     for single_product in products_list:
     for single_product in products_list:
         write_variation_id(single_product, settings)
         write_variation_id(single_product, settings)
-
+        write_product_id_db(single_product, settings, products_data)
 
 
     yield
     yield
 
 
@@ -364,25 +368,16 @@ async def checkout(request: Request):
         settings.git_repo, filename, settings.document_match, settings.block_types
         settings.git_repo, filename, settings.document_match, settings.block_types
     )
     )
 
 
-    products = read_dir(
-        settings.git_repo,
-        settings.document_match,
-        settings.document_exclude,
-        settings.block_types,
-        exclude_doc="products",
-        tree="products",
-    )
-
     session_data = request.session
     session_data = request.session
     initialize_cart(session_data, settings.currency.default)
     initialize_cart(session_data, settings.currency.default)
 
 
     update_cart_meta(
     update_cart_meta(
-        session_data["cart"], session_data["cart"]["meta"]["shipping"], products
+        session_data["cart"], session_data["cart"]["meta"]["shipping"], settings
     )
     )
 
 
     cart = CartSession(**request.session["cart"])
     cart = CartSession(**request.session["cart"])
     
     
-    checkout_data = prepare_checkout(cart, settings, doc, products)
+    checkout_data = prepare_checkout(cart, settings, doc)
 
 
     site = read_file(
     site = read_file(
         settings.git_repo,
         settings.git_repo,
@@ -484,6 +479,7 @@ async def checkout_update(
         shipping_amount,
         shipping_amount,
         quantity,
         quantity,
         inventory_amount,
         inventory_amount,
+        settings,
     )
     )
 
 
     cart = CartSession(**request.session["cart"])
     cart = CartSession(**request.session["cart"])
@@ -512,17 +508,8 @@ async def checkout_update(
                 settings.block_types,
                 settings.block_types,
             )
             )
 
 
-            products = read_dir(
-                settings.git_repo,
-                settings.document_match,
-                settings.document_exclude,
-                settings.block_types,
-                exclude_doc="products",
-                tree="products",
-            )
-
             checkout_data = prepare_checkout(
             checkout_data = prepare_checkout(
-                cart, settings, doc, products, js_update=False
+                cart, settings, doc,  js_update=False
             )
             )
 
 
             cart_items = [
             cart_items = [
@@ -580,7 +567,6 @@ async def checkout_shipping(request: Request,
     ):
     ):
         raise HTTPException(status_code=403, detail="Shipping info are incorrect.")
         raise HTTPException(status_code=403, detail="Shipping info are incorrect.")
 
 
-
     shipping_rate = calculate_shipping_cost(country, weight, settings.currency.default)
     shipping_rate = calculate_shipping_cost(country, weight, settings.currency.default)
 
 
     if shipping_rate:
     if shipping_rate:
@@ -589,7 +575,7 @@ async def checkout_shipping(request: Request,
         session_data = request.session
         session_data = request.session
         initialize_cart(session_data, settings.currency.default)
         initialize_cart(session_data, settings.currency.default)
 
 
-        update_cart_meta(session_data["cart"], shipping_rate.price)
+        update_cart_meta(session_data["cart"], shipping_rate.price, settings)
         cart = CartSession(**request.session['cart'])
         cart = CartSession(**request.session['cart'])
 
 
         if js:
         if js:

+ 3 - 3
app/template.py

@@ -1,7 +1,5 @@
-import os
 import random
 import random
 import hashlib
 import hashlib
-import time
 from pathlib import Path
 from pathlib import Path
 from typing import Literal
 from typing import Literal
 
 
@@ -12,6 +10,7 @@ from app.db import (
     check_product_availability,
     check_product_availability,
     get_docs_by_category,
     get_docs_by_category,
     get_product_by_product_id,
     get_product_by_product_id,
+    get_products_id_db,
 )
 )
 from app.parser import read_file
 from app.parser import read_file
 from app.schema import (
 from app.schema import (
@@ -94,7 +93,7 @@ def prepare_checkout(
     cart: CartSession,
     cart: CartSession,
     settings: Settings,
     settings: Settings,
     doc: DocumentCheckout,
     doc: DocumentCheckout,
-    products: list[DocumentProduct],
+    product_id: str = None,
     js_update: bool = False,
     js_update: bool = False,
 ) -> dict[str, list[str] | dict[str, str | int] | DocumentCheckout]:
 ) -> dict[str, list[str] | dict[str, str | int] | DocumentCheckout]:
     """Return dictionary with necessary data to display the Checkout view:
     """Return dictionary with necessary data to display the Checkout view:
@@ -114,6 +113,7 @@ def prepare_checkout(
     show_checkout = []
     show_checkout = []
 
 
     # map over each item in the cart and create a new item object
     # map over each item in the cart and create a new item object
+    products = get_products_id_db(settings)
     checkout_items = []
     checkout_items = []
     for item in cart.items.values():
     for item in cart.items.values():
         product = get_product_by_product_id(settings, item.product_id, products)
         product = get_product_by_product_id(settings, item.product_id, products)