Last active
March 25, 2021 05:56
-
-
Save jerinisready/416fd959007d9a7342c9823585637121 to your computer and use it in GitHub Desktop.
Django Oscar Product fetching (my personal) recommendation for API. This follows assumption that, Main screen Displays Parent / Standalone Products. Parent Products will have a dropdown from where, the card item can replace parent product with details of child product. This also devices into a logic that, Area of delivery is divided into differe…
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from typing import Any, Union | |
from django.db.models import Q, QuerySet | |
from django.http import HttpRequest | |
from apps.api_set_v2.serializers.catalogue import ProductSimpleListSerializer | |
from apps.catalogue.models import Product | |
from apps.partner.models import StockRecord | |
def get_optimized_product_dict( | |
request: HttpRequest, | |
qs_filter: Q = None, | |
qs: Union[QuerySet, list] = None, | |
offset: int = None, | |
limit: int = None, | |
needs_stock: bool = True, | |
product_serializer_class: type = ProductSimpleListSerializer) -> dict: | |
assert qs is not None or qs_filter is not None, "Either one is required!" | |
""" | |
Zone can be explained as a model with a pointer to partner who delivers to a geographical region. | |
zone: = None | |
class Zone(models.Model): | |
name = models.CharField(max_length=128) | |
zone = models.PolygonField() | |
partner = models.ForeignKey('partner.Partner', related_name='zone', on_delete=models.CASCADE) | |
stock record -> partner -> zone | |
""" | |
zone: int = request.session.get('zone') # zone => Zone.pk | |
if qs is not None: | |
if not qs: return {} | |
product_set = qs | |
else: | |
product_set = Product.objects.filter( | |
qs_filter, is_public=True, | |
stockrecords__isnull=False | |
) | |
if offset and limit: | |
product_set = product_set[offset:limit] | |
elif limit: | |
product_set = product_set[:limit] | |
elif offset: | |
product_set = product_set[offset:] | |
sr_set = StockRecord.objects.filter( | |
product__parent__in=product_set, | |
product__structure__in=[Product.CHILD, Product.STANDALONE], | |
num_in_stock__gt=0 if needs_stock else -1, | |
).select_related( | |
'product', 'product__product_class', 'product__parent', 'product__parent__product_class' | |
).prefetch_related('product__images', 'product__parent__images') | |
if zone: | |
sr_set = sr_set.filter(partner__zone__id=zone) | |
product_data = {} | |
for sr in sr_set: | |
sr.product.selected_stock_record = sr | |
if sr.product.is_child: | |
if sr.product.parent not in product_data.keys(): | |
product_data[sr.product.parent] = product_serializer_class(instance=sr.product.parent, | |
context={'request': request}).data | |
product_data[sr.product.parent]['variants'] = [] | |
product_data[sr.product.parent]['variants'].append( | |
product_serializer_class(instance=sr.product, context={'request': request}).data) | |
elif sr.product.is_standalone: # parent or standalone | |
product_data[sr.product] = product_serializer_class(instance=sr.product, | |
context={'request': request}).data | |
product_data[sr.product]['variants'] = [] | |
return product_data | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from apps.api_set_v2.serializers.mixins import ProductPrimaryImageFieldMixin, ProductPriceFieldMixinLite | |
class ProductSimpleListSerializer(ProductPrimaryImageFieldMixin, ProductPriceFieldMixinLite, | |
serializers.ModelSerializer): | |
primary_image = serializers.SerializerMethodField() | |
price = serializers.SerializerMethodField() | |
class Meta: | |
model = Product | |
fields = ('id', 'title', 'primary_image', 'price') | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from apps.utils import cache_key | |
class empty: | |
""" faking request object just for the purpose of generating complete url """ | |
def __init__(self, **kwargs): | |
for key in kwargs: | |
setattr(self, key, kwargs[key]) | |
def build_absolute_uri(self, path): | |
return path | |
class ProductPrimaryImageFieldMixin(object): | |
""" Serializer mixin to facilitate fetching primary image for Product Serializers """ | |
def get_primary_image(self, instance): | |
if instance.is_child: | |
return None # planning to deliver images only to parent image. | |
request = (self.context or {}).get('request', empty()) # noqa: mixin assured | |
req = request.build_absolute_uri | |
img = instance.primary_image() | |
img_mob = img['original'] if type(img) is dict else img.thumbnail_mobile_listing | |
return { | |
# 'web': req.build_absolute_uri(img_web), | |
'mobile': req(img_mob or image_not_found()), | |
} | |
class ProductAttributeFieldMixin(object): | |
attribute_values_filter = {} | |
def get_attributes(self, instance): | |
def _inner(): | |
""" | |
Executing 5 Queries! | |
""" | |
attrs_value = instance.attribute_values.filter( | |
**self.attribute_values_filter | |
).annotate( | |
att_name=F('attribute__name'), | |
att_code=F('attribute__code'), | |
) | |
return [{ # saves model mapping and another 5 queries | |
'name': attr.att_name, | |
'value': attr.value_as_text, | |
'code': attr.att_code, | |
} for attr in attrs_value] | |
# cache.delete(cache_key.product_attribute__key(instance.id)) | |
return cache_library(cache_key.product_attribute__key(instance.id), cb=_inner) | |
class SibblingProductAttributeFieldMixin(ProductAttributeFieldMixin): | |
# attribute_values_filter = {'attribute__is_varying': True} | |
pass | |
class ProductPriceFieldMixin(object): | |
def get_price(self, product): | |
if product.is_parent: | |
return | |
request = (self.context or {}).get('request') | |
purchase_info = get_purchase_info(product, request) # noqa | |
if purchase_info: | |
from oscarapi.serializers.product import AvailabilitySerializer | |
availability = AvailabilitySerializer(purchase_info.availability).data | |
else: | |
availability = { | |
"is_available_to_buy": False, | |
"message": "Unavailable" | |
} | |
return purchase_info_as_dict(purchase_info, **availability) | |
# cache.delete(cache_key.product_price_data__key(product.id)) | |
# return cache_library( | |
# cache_key.product_price_data__key(product.id), | |
# cb=product._recalculate_price_cache | |
# ) | |
class ProductPriceFieldMixinLite(object): | |
def get_price(self, product): | |
key = 'ProductPriceFieldMixinLite__{0}__{1}' | |
def _inner(): | |
if product.is_parent: | |
return dummy_purchase_info_lite_as_dict(availability=True, availability_message='') | |
purchase_info = get_purchase_info( | |
product, | |
request=self.context['request'] # noqa: mixin ensures | |
) | |
addittional_informations = { | |
"availability": bool(purchase_info.availability.is_available_to_buy), | |
"availability_message": purchase_info.availability.short_message, | |
} | |
return purchase_info_lite_as_dict(purchase_info, **addittional_informations) | |
return _inner() | |
# cache.delete(cache_key.product_price_data__key(product.id)) | |
# return cache_library( | |
# cache_key.product_price_data_lite__key(product.id), | |
# cb=product._recalculate_price_cache | |
# ) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
product_price_data__key = "product_price_data_key__{}".format | |
product_attribute__key = "product_attribute__key__{}".format | |
product_price_data_lite__key = "product_price_data_lite__key__{}".format |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
THUMBNAIL_KVSTORE = 'sorl.thumbnail.kvstores.redis_kvstore.KVStore' |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment