merge resolution

This commit is contained in:
Sam
2021-02-25 11:21:30 +00:00
11 changed files with 93 additions and 76 deletions

View File

@@ -214,7 +214,7 @@ Endpoint: `/api/v1/product_search/`
Query parameters: Query parameters:
- `query_string`: text from the search input box - `q`: text from the search input box
Response format: Response format:

View File

@@ -3,7 +3,7 @@ import logging
from django.core.management.base import BaseCommand from django.core.management.base import BaseCommand
from django.conf import settings from django.conf import settings
from core.models import TreeTag from products.models import CategoryTag
from products.models import Product from products.models import Product
@@ -15,7 +15,7 @@ class Command(BaseCommand):
print(self.help) print(self.help)
print("Deleting existing instances") print("Deleting existing instances")
TreeTag.objects.all().delete() CategoryTag.objects.all().delete()
file_path = settings.BASE_DIR + '/../datasets/' + settings.TAXONOMY_FILE file_path = settings.BASE_DIR + '/../datasets/' + settings.TAXONOMY_FILE
counter = 0 counter = 0
@@ -23,11 +23,11 @@ class Command(BaseCommand):
print(f"Reading from {settings.TAXONOMY_FILE}") print(f"Reading from {settings.TAXONOMY_FILE}")
for line in data_file.readlines(): for line in data_file.readlines():
try: try:
tag = Product.tags.tag_model.objects.create(name=line) tag = Product.category.tag_model.objects.create(name=line)
counter += 1 counter += 1
print('.', end='') print('.', end='')
logging.debug(f"{tag} created from {line}") logging.debug(f"{tag} created from {line}")
except Exception as e: except Exception as e:
logging.error(f"{type(e)} while creating tags from {settings.TAXONOMY_FILE}") logging.error(f"{type(e)} while creating tags from {settings.TAXONOMY_FILE}")
print(f"\nAdded {counter} Tag objects to Product.tags") print(f"\nAdded {counter} Tag objects to Product.category")
print('Shutting down\n') print('Shutting down\n')

View File

@@ -3,19 +3,19 @@ import logging
from django.core.management.base import BaseCommand from django.core.management.base import BaseCommand
from django.conf import settings from django.conf import settings
from core.models import TreeTag from products.models import CategoryTag
class Command(BaseCommand): class Command(BaseCommand):
help = 'Extract top level tags' help = 'Extract top level catefory tags'
def handle(self, *args, **kwargs): def handle(self, *args, **kwargs):
# get all instances # get all instances
tags = TreeTag.objects.all() tags = CategoryTag.objects.all()
top_tags = [] top_tags = []
print("Extracting top-level tags from TreeTag instances") print("Extracting top-level tags from CategoryTag instances")
# extract tags with no ancestor # extract tags with no ancestor
for tag in tags: for tag in tags:
if not tag.get_ancestors(): if not tag.get_ancestors():

View File

@@ -73,10 +73,3 @@ class CustomUser(AbstractBaseUser, PermissionsMixin):
verbose_name = 'Usuario' verbose_name = 'Usuario'
verbose_name_plural = 'Usuarios' verbose_name_plural = 'Usuarios'
class TreeTag(TagTreeModel):
class TagMeta:
initial = ""
force_lowercase = True
max_count=20
# autocomplete_view = 'myapp.views.hobbies_autocomplete'

View File

@@ -9,9 +9,9 @@ class HistorySync(models.Model):
company = models.ForeignKey('companies.Company', on_delete=models.DO_NOTHING, null=True) company = models.ForeignKey('companies.Company', on_delete=models.DO_NOTHING, null=True)
rss_url = models.URLField('URL del feed', null=True, blank=True) rss_url = models.URLField('URL del feed', null=True, blank=True)
sync_date = models.DateTimeField('Fecha de lanzamiento', null=True) sync_date = models.DateTimeField('Fecha de lanzamiento', null=True, blank=True)
result = models.TextField('Resultado', null=True, blank=True) result = models.TextField('Resultado', null=True, blank=True)
quantity = models.PositiveIntegerField('Productos importados', null=True) quantity = models.PositiveIntegerField('Productos importados', null=True, blank=True)
# internal # internal
created = models.DateTimeField('date of creation', auto_now_add=True) created = models.DateTimeField('date of creation', auto_now_add=True)

View File

@@ -2,11 +2,34 @@ from django.contrib.gis.db import models
from tagulous.models import SingleTagField, TagField, TagTreeModel from tagulous.models import SingleTagField, TagField, TagTreeModel
from core.models import TreeTag
from companies.models import Company from companies.models import Company
# Create your models here. # Create your models here.
class TreeTag(TagTreeModel):
class TagMeta:
initial = ""
force_lowercase = True
max_count=20
# autocomplete_view = 'myapp.views.hobbies_autocomplete'
class CategoryTag(TagTreeModel):
class TagMeta:
initial = ""
force_lowercase = True
max_count=20
# autocomplete_view = 'myapp.views.hobbies_autocomplete'
class AttributeTag(TagTreeModel):
class TagMeta:
initial = ""
force_lowercase = True
max_count=20
# autocomplete_view = 'myapp.views.hobbies_autocomplete'
class Product(models.Model): class Product(models.Model):
@@ -33,10 +56,10 @@ class Product(models.Model):
sourcing_date = models.DateTimeField('Fecha de importación original de producto', null=True, blank=True) sourcing_date = models.DateTimeField('Fecha de importación original de producto', null=True, blank=True)
update_date = models.DateTimeField('Fecha de actualización de producto', null=True, blank=True) update_date = models.DateTimeField('Fecha de actualización de producto', null=True, blank=True)
discount = models.DecimalField('Descuento', max_digits=5, decimal_places=2, null=True, blank=True) discount = models.DecimalField('Descuento', max_digits=5, decimal_places=2, null=True, blank=True)
stock = models.PositiveIntegerField('Stock', null=True) stock = models.PositiveIntegerField('Stock', null=True, blank=True)
tags = TagField(to=TreeTag) tags = TagField(to=TreeTag)
category = SingleTagField(blank=True, null=True) # main tag category category = SingleTagField(to=CategoryTag, null=True, blank=True) # main tag category
attributes = TagField(to=TreeTag, related_name='product_attributes') attributes = TagField(to=AttributeTag, related_name='product_attributes')
identifiers = models.TextField('Identificador único de producto', null=True, blank=True) identifiers = models.TextField('Identificador único de producto', null=True, blank=True)
# internal # internal

View File

@@ -212,11 +212,11 @@ class ProductViewSetTest(APITestCase):
# Assert access is granted # Assert access is granted
self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.status_code, status.HTTP_200_OK)
# TODO: assert correct order # assert correct order
previous_date = datetime.datetime.now() dates = [d['created'][:-1] for d in payload]
for instance in payload: for i in range(len(dates)-1):
self.assertTrue(datetime.datetime.fromisoformat(instance['created'][:-1]) < previous_date) # first instance should be most recent
previous_date = datetime.datetime.fromisoformat(instance['created'][:-1]) self.assertTrue(datetime.datetime.fromisoformat(dates[i]) > datetime.datetime.fromisoformat(dates[i+1]))
# authenticated user # authenticated user
def test_auth_user_can_list_instances(self): def test_auth_user_can_list_instances(self):
@@ -321,7 +321,7 @@ class ProductViewSetTest(APITestCase):
'discount': '0.05', 'discount': '0.05',
'stock': 22, 'stock': 22,
'tags': ['tag1x, tag2x'], 'tags': ['tag1x, tag2x'],
'category': 'MayorTagCategory2', 'category': 'mayortagcategory2',
'attributes': ['color/blue', 'size/m'], 'attributes': ['color/blue', 'size/m'],
'identifiers': '34rf34f43c43', 'identifiers': '34rf34f43c43',
} }
@@ -531,9 +531,9 @@ class ProductSearchTest(TestCase):
self.factory(tags="azules"), self.factory(tags="azules"),
] ]
query_string = quote("zapatos rojos") q = quote("zapatos rojos")
url = f"{self.endpoint}?query_string={query_string}" url = f"{self.endpoint}?q={q}"
# send in request # send in request
response = self.client.get(url) response = self.client.get(url)
@@ -565,10 +565,10 @@ class ProductSearchTest(TestCase):
self.factory(tags="azules"), self.factory(tags="azules"),
] ]
query_string = quote("zapatos rojos") q = quote("zapatos rojos")
limit = 2 limit = 2
url = f"{self.endpoint}?query_string={query_string}&limit=2" url = f"{self.endpoint}?q={q}&limit=2"
# send in request # send in request
response = self.client.get(url) response = self.client.get(url)
@@ -592,9 +592,9 @@ class ProductSearchTest(TestCase):
self.factory(tags="lunares/rojos", description="zapatos", shipping_cost=0.00), self.factory(tags="lunares/rojos", description="zapatos", shipping_cost=0.00),
] ]
query_string = quote("zapatos rojos") q = quote("zapatos rojos")
# shipping_cost=true # shipping_cost=true
url = f"{self.endpoint}?query_string={query_string}&shipping_cost=true" url = f"{self.endpoint}?q={q}&shipping_cost=true"
# send in request # send in request
response = self.client.get(url) response = self.client.get(url)
# check response # check response
@@ -613,10 +613,10 @@ class ProductSearchTest(TestCase):
self.factory(tags="azules", shipping_cost=10.00), self.factory(tags="azules", shipping_cost=10.00),
] ]
query_string = quote("zapatos rojos") q = quote("zapatos rojos")
# shipping_cost=false # shipping_cost=false
url = f"{self.endpoint}?query_string={query_string}&shipping_cost=false" url = f"{self.endpoint}?q={q}&shipping_cost=false"
# send in request # send in request
response = self.client.get(url) response = self.client.get(url)
# check response # check response
@@ -636,9 +636,9 @@ class ProductSearchTest(TestCase):
self.factory(tags="lunares/rojos", category='zapatos', description="zapatos verdes", discount=None), self.factory(tags="lunares/rojos", category='zapatos', description="zapatos verdes", discount=None),
] ]
query_string = quote("zapatos rojos") q = quote("zapatos rojos")
# discount=true # discount=true
url = f"{self.endpoint}?query_string={query_string}&discount=true" url = f"{self.endpoint}?q={q}&discount=true"
# send in request # send in request
response = self.client.get(url) response = self.client.get(url)
# check response # check response
@@ -658,9 +658,9 @@ class ProductSearchTest(TestCase):
self.factory(tags="azules", discount=9.00), self.factory(tags="azules", discount=9.00),
] ]
query_string = quote("zapatos rojos") q = quote("zapatos rojos")
# discount=true # discount=true
url = f"{self.endpoint}?query_string={query_string}&discount=false" url = f"{self.endpoint}?q={q}&discount=false"
# send in request # send in request
response = self.client.get(url) response = self.client.get(url)
# check response # check response
@@ -680,9 +680,8 @@ class ProductSearchTest(TestCase):
self.factory(tags="azules"), self.factory(tags="azules"),
] ]
query_string = quote("zapatos rojos")
# discount=true # discount=true
url = f"{self.endpoint}?query_string=" url = f"{self.endpoint}?q="
# send in request # send in request
response = self.client.get(url) response = self.client.get(url)
# check response # check response
@@ -702,9 +701,9 @@ class ProductSearchTest(TestCase):
self.factory(tags="zapatos/azules", category="deporte", description='rojos', discount=12.00), self.factory(tags="zapatos/azules", category="deporte", description='rojos', discount=12.00),
] ]
query_string = quote("zapatos rojos") q = quote("zapatos rojos")
# discount=true # discount=true
url = f"{self.endpoint}?query_string={query_string}&category=ropa" url = f"{self.endpoint}?q={q}&category=ropa"
# send in request # send in request
response = self.client.get(url) response = self.client.get(url)
# check response # check response
@@ -724,9 +723,9 @@ class ProductSearchTest(TestCase):
self.factory(tags="zapatos/azules", category="deporte", description='rojos', discount=12.00), self.factory(tags="zapatos/azules", category="deporte", description='rojos', discount=12.00),
] ]
query_string = quote("zapatos rojos") q = quote("zapatos rojos")
# discount=true # discount=true
url = f"{self.endpoint}?query_string={query_string}&tags=deporte" url = f"{self.endpoint}?q={q}&tags=deporte"
# send in request # send in request
response = self.client.get(url) response = self.client.get(url)
# check response # check response
@@ -746,8 +745,8 @@ class ProductSearchTest(TestCase):
self.factory(tags="lunares/rojos", category='zapatos', description="zapatos verdes", price=None), self.factory(tags="lunares/rojos", category='zapatos', description="zapatos verdes", price=None),
] ]
price_min = 5.00 price_min = 5.00
query_string = quote("zapatos rojos") q = quote("zapatos rojos")
url = f"{self.endpoint}?query_string={query_string}&price_min={price_min}" url = f"{self.endpoint}?q={q}&price_min={price_min}"
# send in request # send in request
response = self.client.get(url) response = self.client.get(url)
@@ -770,8 +769,8 @@ class ProductSearchTest(TestCase):
self.factory(tags="lunares/rojos", category='zapatos', description="zapatos verdes", price=100.00), self.factory(tags="lunares/rojos", category='zapatos', description="zapatos verdes", price=100.00),
] ]
price_max = 50.00 price_max = 50.00
query_string = quote("zapatos rojos") q = quote("zapatos rojos")
url = f"{self.endpoint}?query_string={query_string}&price_max={price_max}" url = f"{self.endpoint}?q={q}&price_max={price_max}"
# send in request # send in request
response = self.client.get(url) response = self.client.get(url)

View File

@@ -28,7 +28,7 @@ from history.models import HistorySync
from back_latienda.permissions import IsCreator 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
from utils.tag_serializers import TaggitSerializer from utils.tag_serializers import TaggitSerializer
from utils.tag_filters import ProductTagFilter from utils.tag_filters import ProductTagFilter, ProductOrderFilter
logging.basicConfig( logging.basicConfig(
@@ -40,21 +40,11 @@ logging.basicConfig(
class ProductViewSet(viewsets.ModelViewSet): class ProductViewSet(viewsets.ModelViewSet):
# queryset = Product.objects.all() queryset = Product.objects.all().order_by('-created')
serializer_class = ProductSerializer serializer_class = ProductSerializer
permission_classes = [IsAuthenticatedOrReadOnly, IsCreator] permission_classes = [IsAuthenticatedOrReadOnly, IsCreator]
filter_backends = [DjangoFilterBackend, OrderingFilter] filter_backends = [DjangoFilterBackend, OrderingFilter]
filterset_class = ProductTagFilter filterset_class = ProductTagFilter
filterset_fields = ['name', 'tags', 'category', 'attributes', 'company', 'created']
# TODO: figure out why cant use filterset for company filter
def get_queryset(self):
try:
company_id = self.request.GET.get('company')
company_id = int(company_id)
queryset = Product.objects.filter(company__id=company_id)
except:
queryset = Product.objects.all()
return queryset
def perform_create(self, serializer): def perform_create(self, serializer):
serializer.save(creator=self.request.user) serializer.save(creator=self.request.user)
@@ -159,7 +149,7 @@ def product_search(request):
Takes a string of data, return relevant products Takes a string of data, return relevant products
Params: Params:
- query_string: used for search [MANDATORY] - q: used for search [MANDATORY]
- limit: max number of returned instances [OPTIONAL] - limit: max number of returned instances [OPTIONAL]
- offset: where to start counting results [OPTIONAL] - offset: where to start counting results [OPTIONAL]
- shipping_cost: true/false - shipping_cost: true/false
@@ -168,7 +158,7 @@ def product_search(request):
- tags: string - tags: string
""" """
# capture query params # capture query params
query_string = request.GET.get('query_string', None) q = request.GET.get('q', None)
limit = request.GET.get('limit', None) limit = request.GET.get('limit', None)
offset = request.GET.get('offset', None) offset = request.GET.get('offset', None)
shipping_cost = request.GET.get('shipping_cost', None) shipping_cost = request.GET.get('shipping_cost', None)
@@ -192,9 +182,9 @@ def product_search(request):
price_min = request.GET.get('price_min', None) price_min = request.GET.get('price_min', None)
price_max = request.GET.get('price_max', None) price_max = request.GET.get('price_max', None)
if query_string is None: if q is None:
return Response({"errors": {"details": "No query string to parse"}}) return Response({"errors": {"details": "No query string to parse"}})
elif query_string is '': elif q is '':
# return everything # return everything
serializer = ProductSerializer(Product.objects.all(), many=True) serializer = ProductSerializer(Product.objects.all(), many=True)
products = serializer.data products = serializer.data
@@ -205,7 +195,7 @@ def product_search(request):
result_set = set() result_set = set()
# split query string into single words # split query string into single words
chunks = query_string.split(' ') chunks = q.split(' ')
for chunk in chunks: for chunk in chunks:
product_set = find_related_products_v6(chunk, shipping_cost, discount, category, tags, price_min, price_max) product_set = find_related_products_v6(chunk, shipping_cost, discount, category, tags, price_min, price_max)
# add to result set # add to result set

View File

@@ -17,11 +17,11 @@ class StatsLog(models.Model):
action_object_object_id = models.CharField(max_length=255, blank=True, null=True) action_object_object_id = models.CharField(max_length=255, blank=True, null=True)
action_object = GenericForeignKey('action_object_content_type', 'action_object_object_id') action_object = GenericForeignKey('action_object_content_type', 'action_object_object_id')
user = models.ForeignKey(User, on_delete=models.DO_NOTHING, null=True) user = models.ForeignKey(User, on_delete=models.DO_NOTHING, null=True)
anonymous = models.BooleanField('Usuario no registrado', null=True) anonymous = models.BooleanField('Usuario no registrado', null=True, blank=True)
ip_address = models.GenericIPAddressField('IP usuario', null=True, blank=True) ip_address = models.GenericIPAddressField('IP usuario', null=True, blank=True)
geo = models.PointField('Ubicación aproximada', null=True, blank=True ) geo = models.PointField('Ubicación aproximada', null=True, blank=True )
contact = models.BooleanField('Empresa contactada', null=True) contact = models.BooleanField('Empresa contactada', null=True, blank=True)
shop = models.BooleanField('Redirigido por botón "Comprar"', null=True) shop = models.BooleanField('Redirigido por botón "Comprar"', null=True, blank=True)
# internal # internal
created = models.DateTimeField('date of creation', auto_now_add=True) created = models.DateTimeField('date of creation', auto_now_add=True)

View File

@@ -1,5 +1,7 @@
import django_filters import django_filters
from rest_framework.filters import BaseFilterBackend
from companies.models import Company from companies.models import Company
from products.models import Product from products.models import Product
@@ -26,10 +28,19 @@ class ProductTagFilter(django_filters.FilterSet):
class Meta: class Meta:
model = Product model = Product
fields = ['name', 'tags', 'category', 'attributes'] fields = ['name', 'tags', 'category', 'attributes', 'company', 'created',]
def tag_filter(self, queryset, name, value): def tag_filter(self, queryset, name, value):
return queryset.filter(**{ return queryset.filter(**{
name: value, name: value,
}) })
class ProductOrderFilter(BaseFilterBackend):
def filter_queryset(self, request, queryset, view):
order_field = request.GET.get('order', None)
if order_field is not None:
return queryset.order_by(order_field)
else:
return queryset

View File

@@ -89,7 +89,7 @@ def create_imported_product(info, company, history, user):
return new return new
else: else:
logging.error(f"{serializer.errors}") logging.error(f"{serializer.errors}")
return [] return None
def migrate_shop_products(url, key, secret, user=None, version="wc/v3"): def migrate_shop_products(url, key, secret, user=None, version="wc/v3"):
@@ -145,6 +145,7 @@ def migrate_shop_products(url, key, secret, user=None, version="wc/v3"):
counter = 0 counter = 0
for product in products: for product in products:
new = create_imported_product(product, company, history, user) new = create_imported_product(product, company, history, user)
if new is not None:
new_products.append(new) new_products.append(new)
counter += 1 counter += 1
logging.info(f"Product '{new.name}' created") logging.info(f"Product '{new.name}' created")