improvements in product loader

This commit is contained in:
Sam
2021-02-26 13:59:30 +00:00
parent 25b8e561d3
commit 223b944199
5 changed files with 164 additions and 63 deletions

View File

@@ -1,11 +1,16 @@
import logging
import datetime
from django.db.models import Q
from django.contrib.postgres.search import SearchQuery, SearchRank, SearchVector, TrigramSimilarity
from django.db.models import Max, Min
from django.conf import settings
import requests
from products.models import Product
from companies.models import Company
from history.models import HistorySync
def extract_search_filters(result_set):
@@ -210,3 +215,76 @@ def find_related_products_v4(keyword):
).order_by('-similarity')
return set(products_qs)
def product_loader(csv_reader, user):
"""
Parse csv data and extract:
- product data
Return counts
"""
counter = 0
# create historysync instance
history = HistorySync.objects.create(company=user.company, sync_date=datetime.datetime.now())
for row in csv_reader:
# trim strings
for key in row:
if row[key]: row[key] = row[key].strip().lower()
# check required data
if '' in (row['nombre-producto'], row['descripcion'], row['precio'], row['categoria']):
logging.error(f"Required data missing: {row}")
continue
try:
# TODO: if tags is empty, auto-generate tags
# assemble instance data
product_data = {
'company': user.company,
'name': row['nombre-producto'].strip(),
'description': row['descripcion'].strip(),
#'url': row['url'].strip(),
#'price': row['precio'].strip(),
#'shipping_cost': row['gastos-envio'].strip(),
#'shipping_terms': row['cond-envio'].strip(),
#'discount': row['descuento'].strip(),
#'stock': row['stock'].strip(),
#'tags': row['tags'].strip(),
#'category': row['categoria'].strip(),
#'identifiers': row['identificadores'].strip(),
#'history': history,
'creator': user,
}
product = Product.objects.create(**product_data)
# image logo data
if row['imagen'] is not None:
try:
# get image
headers={"User-Agent" : "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36"}
response = requests.get(row['imagen'], stream=True, headers=headers)
assert(response.status_code==200)
response.raw.decode_content = True
image = Image.open(response.raw)
# save using File object
img_io = BytesIO()
image.save(img_io, format=image.format)
product.image.save(f"{product.company.company_name}{product.name}.{image.format.lower()}", File(img_io), save=False)
product.save()
except AssertionError as e:
logging.error(f"Source image [{row['imagen']}] not reachable: {response.status_code}")
except Exception as e:
logging.error(f"Could not add image to product from [{row['imagen']}]: {str(e)}")
logging.info(f"Created Product {product.id}")
counter += 1
except Exception as e:
import ipdb; ipdb.set_trace()
logging.error(f"Could not parse {row}")
history.quantity = counter
history.save()
return counter

View File

@@ -22,7 +22,7 @@ from companies.models import Company
from history.models import HistorySync
from back_latienda.permissions import IsCreator
from .utils import extract_search_filters, find_related_products_v3, find_related_products_v6
from .utils import extract_search_filters, find_related_products_v3, find_related_products_v6, product_loader
from utils.tag_serializers import TaggitSerializer
from utils.tag_filters import ProductTagFilter, ProductOrderFilter
@@ -64,8 +64,14 @@ def my_products(request):
def load_coop_products(request):
"""Read CSV file being received
Parse it to create products for related Company
Authenticated user must have a related company
"""
try:
# check company linked to user
if request.user.company is None:
return Response({"errors":{"details": "Your user has no company to add products to"}})
csv_file = request.FILES['csv_file']
if csv_file.name.endswith('.csv') is not True:
logging.error(f"File {csv_file.name} is not a CSV file")
@@ -74,67 +80,9 @@ def load_coop_products(request):
logging.info(f"Reading contents of {csv_file.name}")
decoded_file = csv_file.read().decode('utf-8').splitlines()
csv_reader = csv.DictReader(decoded_file, delimiter=',')
counter = 0
# get company linked to user
company_qs = Company.objects.filter(creator=request.user)
count = product_loader(csv_reader, request.user)
if company_qs:
company = company_qs.first()
else:
return Response({"errors":{"details": "Your user has no company to add products to"}})
# create historysync instance
history = HistorySync.objects.create(company=company, sync_date=datetime.datetime.now(), quantity=len(decoded_file))
for row in csv_reader:
if '' in (row['nombre-producto'], row['descripcion'], row['precio'], row['categoria']):
logging.error(f"Required data missing: {row}")
continue
try:
# download image references in csv
if row['imagen'].strip() != '':
image_url = row['imagen'].strip()
response = requests.get(image_url, stream=True)
if response.status_code == 200:
path = f"{setting.BASE_DIR}media/{row['nombre-producto'].strip()}.{image.url.split('/')[-1]}"
logging.info(f"Saving product image to: {path}")
new_image = open(path, 'wb')
for chunk in response:
new_image.write(chunk)
new_image.close()
else:
logging.warning(f"Image URL did not work: {image_url}")
new_image = None
else:
new_image = None
# TODO: if tags is empty, auto-generate tags
# assemble instance data
product_data = {
'id': None if row['id'].strip()=='' else row['id'].strip(),
'company': Company.objects.filter(creator=request.user).first(),
'name': row['nombre-producto'].strip(),
'description': row['descripcion'].strip(),
'image': new_image,
'url': row['url'].strip(),
'price': row['precio'].strip(),
'shipping_cost': row['gastos-envio'].strip(),
'shipping_terms': row['cond-envio'].strip(),
'discount': row['descuento'].strip(),
'stock': row['stock'].strip(),
'tags': row['tags'].strip(),
'category': row['categoria'].strip(),
'identifiers': row['identificadores'].strip(),
'history': history,
'creator': request.user,
}
Product.objects.create(**product_data)
logging.info(f"Created Product: {product_data}")
counter += 1
except Exception as e:
logging.error(f"Could not parse {row}")
return Response()
return Response(f"{count} products registered for {request.user.company_name}")
except Exception as e:
return Response({"errors": {"details": str(type(e))}}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)