Skip to content

Commit

Permalink
Merge pull request #7 from django-oscar/identifierstuff
Browse files Browse the repository at this point in the history
Identifierstuff
  • Loading branch information
viggo-devries authored Dec 20, 2023
2 parents dec2bc1 + 2c9e2a5 commit fc15664
Show file tree
Hide file tree
Showing 15 changed files with 879 additions and 163 deletions.
8 changes: 4 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,14 @@ lint: fail-if-no-virtualenv
pylint oscar_odin/

test: fail-if-no-virtualenv
python3 runtests.py makemigrations --check --dry-run
@python3 runtests.py test tests/
python3 runtests.py test tests.reverse.test_catalogue

black:
@black oscar_odin/**/*.py

@black oscar_odin/
@black tests/

ill:
rm db.sqlite3
cp klaas.sqlite3 db.sqlite3
python3 runtests.py migrate
python3 runtests.py test_illshit
2 changes: 2 additions & 0 deletions oscar_odin/exceptions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
class OscarOdinException(TypeError):
pass
60 changes: 60 additions & 0 deletions oscar_odin/fixtures/oscar_odin/csv/products.csv

Large diffs are not rendered by default.

72 changes: 47 additions & 25 deletions oscar_odin/management/commands/test_illshit.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,12 @@
Image as ImageResource,
ProductClass as ProductClassResource,
Category as CategoryResource,
ProductAttributeValue as ProductAttributeValueResource
ProductAttributeValue as ProductAttributeValueResource,
)

from oscar_odin.mappings.defaults import DEFAULT_UPDATE_FIELDS
from oscar_odin.mappings.constants import *

from oscar_odin.utils import querycounter

Product = get_model("catalogue", "Product")
Expand All @@ -32,54 +34,64 @@


class Command(BaseCommand):

def handle(self, *args, **options):
img = PIL.Image.new(mode="RGB", size=(200, 200))
output = io.BytesIO()
img.save(output, "jpeg")

product_class, _ = ProductClass.objects.get_or_create(
slug="klaas", defaults={"requires_shipping": True, "track_stock": True, "name": "Klaas"}
slug="klaas",
defaults={"requires_shipping": True, "track_stock": True, "name": "Klaas"},
)
text_codes = ["code%s" % i for i in range(0, 10)]
int_codes = ["code%s" % i for i in range(11, 20)]
option_codes = ["code%s" % i for i in range(21, 30)]

group, _ = AttributeOptionGroup.objects.get_or_create(name="gekke options")
option, _ = AttributeOption.objects.get_or_create(group=group, option="klaas")

for code in text_codes:
ProductAttribute.objects.get_or_create(
name=code, code=code, type=ProductAttribute.TEXT, product_class=product_class
name=code,
code=code,
type=ProductAttribute.TEXT,
product_class=product_class,
)
for code in int_codes:
ProductAttribute.objects.get_or_create(
name=code, code=code, type=ProductAttribute.INTEGER, product_class=product_class
name=code,
code=code,
type=ProductAttribute.INTEGER,
product_class=product_class,
)
for code in option_codes:
ProductAttribute.objects.get_or_create(
name=code, code=code, type=ProductAttribute.OPTION, product_class=product_class, option_group=group
name=code,
code=code,
type=ProductAttribute.OPTION,
product_class=product_class,
option_group=group,
)

product_class = ProductClassResource(
slug="klaas", name="Klaas"
)

product_class = ProductClassResource(slug="klaas", name="Klaas")

partner, _ = Partner.objects.get_or_create(name="klaas")

Category.add_root(name="Hatsie", slug="batsie", is_public=True)
Category.add_root(name="henk", slug="klaas", is_public=True)
Category.add_root(name="Knaken", slug="knaken", is_public=True)
batsie = Category.add_root(
name="Hatsie", slug="batsie", is_public=True, code="batsie"
)
henk = batsie.add_child(name="henk", slug="klaas", is_public=True, code="henk")
henk.add_child(name="Knaken", slug="knaken", is_public=True, code="knaken")

products = []

for i in range(0, 5000):
def create_product(i):
attributes = dict()
attributes.update({code: "%s-%s" % (code, i) for code in text_codes})
attributes.update({code: i for code in int_codes})
attributes.update({code: option for code in option_codes})

products.append(ProductResource(
return ProductResource(
upc="1234323-%s" % i,
title="asdf2 %s" % i,
slug="asdf-asdfasdf-%s" % i,
Expand All @@ -92,18 +104,28 @@ def handle(self, *args, **options):
partner=partner,
product_class=product_class,
images=[
ImageResource(caption="gekke caption", display_order=0, original=File(output, name="image%s.jpg")),
ImageResource(
caption="gekke caption",
display_order=0,
original=File(output, name="image%s.jpg"),
),
],
categories=[
CategoryResource(name="henk", slug="klaas"),
CategoryResource(name="Hatsie datsie", slug="batsie"),
CategoryResource(name="Knaken", slug="knaken")
CategoryResource(code="batsie"),
CategoryResource(code="henk"),
CategoryResource(code="knaken"),
],
attributes=attributes
attributes=attributes,
)
)


products = list(map(create_product, range(0, 5000)))

with querycounter("COMMANDO"):
products_to_db(products)
products_to_db(
products,
fields_to_update=ALL_PRODUCT_FIELDS
+ ALL_STOCKRECORD_FIELDS
+ ALL_PRODUCTIMAGE_FIELDS,
)

print("AANTAL PRODUCTEN AANGEMAAKT:", Product.objects.count())
47 changes: 22 additions & 25 deletions oscar_odin/mappings/catalogue.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
save_foreign_keys,
)
from .context import ModelMapperContext
from .defaults import DEFAULT_UPDATE_FIELDS
from .constants import ALL_CATALOGUE_FIELDS, MODEL_IDENTIFIERS_MAPPING

__all__ = (
"ProductImageToResource",
Expand Down Expand Up @@ -217,19 +217,6 @@ def attributes(self) -> Dict[str, Any]:
for item in self.source.get_attribute_values()
}

@odin.assign_field
def children(self) -> Tuple[Optional[List[resources.catalogue.Product]]]:
"""Children of parent products."""

if self.context.get("include_children", False) and self.source.is_parent:
# Return a tuple as an optional list causes problems.
return (
map_queryset(
ProductToResource, self.source.children, context=self.context
),
)
return (None,)

@odin.assign_field(to_field=("price", "currency", "availability"))
def map_stock_price(self) -> Tuple[Decimal, str, int]:
"""Resolve stock price using strategy and decompose into price/currency/availability."""
Expand Down Expand Up @@ -258,15 +245,17 @@ def images(self, values) -> List[ProductImageModel]:
"""Map related image. We save these later in bulk"""
return ProductImageToModel.apply(values)

@odin.map_field
def parent(self, parent):
if parent:
return ParentToModel.apply(parent)

return None

@odin.map_list_field
def categories(self, values) -> List[CategoryModel]:
return CategoryToModel.apply(values)

@odin.map_list_field
def children(self, values) -> List[ProductModel]:
"""Map related image."""
return []

@odin.map_list_field(
from_field=["price", "availability", "currency", "upc", "partner"]
)
Expand All @@ -288,13 +277,19 @@ def stockrecords(

@odin.map_field
def product_class(self, value) -> ProductClassModel:
if not value and self.source.structure == ProductModel.CHILD:
return None

return ProductClassToModel.apply(value)
# if isinstance(value, self.to_obj):


# return value
#
# return ProductClassToModel.apply(value)
class ParentToModel(odin.Mapping):
from_obj = resources.catalogue.ParentProduct
to_obj = ProductModel

@odin.assign_field
def structure(self):
return ProductModel.PARENT


def product_to_resource_with_strategy(
Expand Down Expand Up @@ -392,7 +387,8 @@ def products_to_model(
def products_to_db(
products: List[resources.catalogue.Product],
rollback=True,
fields_to_update=DEFAULT_UPDATE_FIELDS,
fields_to_update=ALL_CATALOGUE_FIELDS,
identifier_mapping=MODEL_IDENTIFIERS_MAPPING,
) -> Tuple[List[ProductModel], Dict]:
"""Map mulitple products to a model and store them in the database.
Expand All @@ -401,7 +397,8 @@ def products_to_db(
At last all related models like images, stockrecords, and related_products can will be saved and set on the product.
"""
instances, context = products_to_model(products)
context.add_fields_to_update(fields_to_update)
context.fields_to_update = fields_to_update
context.identifier_mapping = identifier_mapping

errors = {}

Expand Down
98 changes: 98 additions & 0 deletions oscar_odin/mappings/constants.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
from oscar.core.loading import get_model

Product = get_model("catalogue", "Product")
Category = get_model("catalogue", "Category")
ProductClass = get_model("catalogue", "ProductClass")
ProductImage = get_model("catalogue", "ProductImage")
StockRecord = get_model("partner", "StockRecord")
Partner = get_model("partner", "Partner")

PRODUCT_STRUCTURE = "Product.structure"
PRODUCT_IS_PUBLIC = "Product.is_public"
PRODUCT_UPC = "Product.upc"
PRODUCT_PARENT = "Product.parent"
PRODUCT_TITLE = "Product.title"
PRODUCT_SLUG = "Product.slug"
PRODUCT_DESCRIPTION = "Product.description"
PRODUCT_META_TITLE = "Product.meta_title"
PRODUCT_META_DESCRIPTION = "Product.meta_description"
PRODUCT_PRODUCT_CLASS = "Product.product_class"
PRODUCT_PARENT = "Product.parent"
PRODUCT_IS_DISCOUNTABLE = "Product.is_discountable"

CATEGORY_NAME = "Category.name"
CATEGORY_CODE = "Category.code"
CATEGORY_DESCRIPTION = "Category.description"
CATEGORY_META_TITLE = "Category.meta_title"
CATEGORY_META_DESCRIPTION = "Category.meta_description"
CATEGORY_IMAGE = "Category.image"
CATEGORY_SLUG = "Category.slug"
CATEGORY_IS_PUBLIC = "Category.is_public"

PRODUCTIMAGE_CODE = "ProductImage.code"
PRODUCTIMAGE_ORIGINAL = "ProductImage.original"
PRODUCTIMAGE_CAPTION = "ProductImage.caption"
PRODUCTIMAGE_DISPLAY_ORDER = "ProductImage.display_order"

STOCKRECORD_PARTNER = "StockRecord.partner"
STOCKRECORD_PARTNER_SKU = "StockRecord.partner_sku"
STOCKRECORD_PRICE_CURRENCY = "StockRecord.price_currency"
STOCKRECORD_PRICE = "StockRecord.price"
STOCKRECORD_NUM_IN_STOCK = "StockRecord.num_in_stock"
STOCKRECORD_NUM_ALLOCATED = "StockRecord.num_allocated"

ALL_PRODUCT_FIELDS = [
PRODUCT_STRUCTURE,
PRODUCT_IS_PUBLIC,
PRODUCT_UPC,
PRODUCT_PARENT,
PRODUCT_TITLE,
PRODUCT_SLUG,
PRODUCT_DESCRIPTION,
PRODUCT_META_TITLE,
PRODUCT_META_DESCRIPTION,
PRODUCT_PRODUCT_CLASS,
PRODUCT_IS_DISCOUNTABLE,
PRODUCT_PARENT,
]

ALL_CATEGORY_FIELDS = [
CATEGORY_NAME,
CATEGORY_CODE,
CATEGORY_DESCRIPTION,
CATEGORY_META_TITLE,
CATEGORY_META_DESCRIPTION,
CATEGORY_IMAGE,
CATEGORY_IS_PUBLIC,
CATEGORY_SLUG,
]

ALL_PRODUCTIMAGE_FIELDS = [
PRODUCTIMAGE_CODE,
PRODUCTIMAGE_ORIGINAL,
PRODUCTIMAGE_CAPTION,
PRODUCTIMAGE_DISPLAY_ORDER,
]

ALL_STOCKRECORD_FIELDS = [
STOCKRECORD_PARTNER,
STOCKRECORD_PARTNER_SKU,
STOCKRECORD_PRICE_CURRENCY,
STOCKRECORD_PRICE,
STOCKRECORD_NUM_IN_STOCK,
STOCKRECORD_NUM_ALLOCATED,
]


ALL_CATALOGUE_FIELDS = (
ALL_PRODUCT_FIELDS + ALL_PRODUCTIMAGE_FIELDS + ALL_STOCKRECORD_FIELDS
)

MODEL_IDENTIFIERS_MAPPING = {
Category: ("code",),
Product: ("upc",),
StockRecord: ("product_id",),
ProductClass: ("slug",),
ProductImage: ("code",),
Partner: ("slug",),
}
Loading

0 comments on commit fc15664

Please sign in to comment.