mirror of
https://github.com/TandoorRecipes/recipes.git
synced 2026-01-06 14:48:02 -05:00
Merge branch 'develop' into keyword_todo
This commit is contained in:
@@ -4,11 +4,11 @@ from recipes import settings
|
||||
from django.contrib.postgres.search import (
|
||||
SearchQuery, SearchRank, TrigramSimilarity
|
||||
)
|
||||
from django.db.models import Count, Q, Subquery, Case, When, Value
|
||||
from django.db.models import Count, Max, Q, Subquery, Case, When, Value
|
||||
from django.utils import translation
|
||||
|
||||
from cookbook.managers import DICTIONARY
|
||||
from cookbook.models import Food, Keyword, ViewLog
|
||||
from cookbook.models import Food, Keyword, Recipe, ViewLog
|
||||
|
||||
|
||||
# TODO create extensive tests to make sure ORs ANDs and various filters, sorting, etc work as expected
|
||||
@@ -30,24 +30,30 @@ def search_recipes(request, queryset, params):
|
||||
search_random = params.get('random', False)
|
||||
search_new = params.get('new', False)
|
||||
search_last_viewed = int(params.get('last_viewed', 0))
|
||||
orderby = []
|
||||
|
||||
# TODO update this to concat with full search queryset qs1 | qs2
|
||||
if search_last_viewed > 0:
|
||||
last_viewed_recipes = ViewLog.objects.filter(
|
||||
created_by=request.user, space=request.space,
|
||||
created_at__gte=datetime.now() - timedelta(days=14)
|
||||
).order_by('pk').values_list('recipe__pk', flat=True).distinct()
|
||||
created_at__gte=datetime.now() - timedelta(days=14) # TODO make recent days a setting
|
||||
).order_by('-pk').values_list('recipe__pk', flat=True)
|
||||
last_viewed_recipes = list(dict.fromkeys(last_viewed_recipes))[:search_last_viewed] # removes duplicates from list prior to slicing
|
||||
|
||||
return queryset.filter(pk__in=last_viewed_recipes[len(last_viewed_recipes) - min(len(last_viewed_recipes), search_last_viewed):])
|
||||
# return queryset.annotate(last_view=Max('viewlog__pk')).annotate(new=Case(When(pk__in=last_viewed_recipes, then=('last_view')), default=Value(0))).filter(new__gt=0).order_by('-new')
|
||||
# queryset that only annotates most recent view (higher pk = lastest view)
|
||||
queryset = queryset.annotate(last_view=Max('viewlog__pk')).annotate(recent=Case(When(pk__in=last_viewed_recipes, then=('last_view')), default=Value(0)))
|
||||
orderby += ['-recent']
|
||||
|
||||
orderby = []
|
||||
# TODO create setting for default ordering - most cooked, rating,
|
||||
# TODO create options for live sorting
|
||||
# TODO make days of new recipe a setting
|
||||
if search_new == 'true':
|
||||
queryset = queryset.annotate(
|
||||
new_recipe=Case(When(created_at__gte=(datetime.now() - timedelta(days=7)), then=Value(100)),
|
||||
default=Value(0), ))
|
||||
orderby += ['new_recipe']
|
||||
else:
|
||||
queryset = queryset
|
||||
queryset = (
|
||||
queryset.annotate(new_recipe=Case(
|
||||
When(created_at__gte=(datetime.now() - timedelta(days=7)), then=('pk')), default=Value(0),))
|
||||
)
|
||||
orderby += ['-new_recipe']
|
||||
|
||||
search_type = search_prefs.search or 'plain'
|
||||
if len(search_string) > 0:
|
||||
@@ -124,7 +130,7 @@ def search_recipes(request, queryset, params):
|
||||
queryset = queryset.filter(query_filter).annotate(rank=search_rank)
|
||||
orderby += ['-rank']
|
||||
else:
|
||||
queryset = queryset.filter(query_filter)
|
||||
queryset = queryset.filter(name__icontains=search_string)
|
||||
|
||||
if len(search_keywords) > 0:
|
||||
if search_keywords_or == 'true':
|
||||
@@ -163,39 +169,50 @@ def search_recipes(request, queryset, params):
|
||||
queryset = queryset.order_by("?")
|
||||
else:
|
||||
# TODO add order by user settings
|
||||
orderby += ['name']
|
||||
# orderby += ['name']
|
||||
queryset = queryset.order_by(*orderby)
|
||||
return queryset
|
||||
|
||||
|
||||
def get_facet(qs, params, space):
|
||||
|
||||
def get_facet(qs, request):
|
||||
# NOTE facet counts for tree models include self AND descendants
|
||||
facets = {}
|
||||
ratings = params.getlist('ratings', [])
|
||||
keyword_list = params.getlist('keywords', [])
|
||||
ingredient_list = params.getlist('foods', [])
|
||||
book_list = params.getlist('book', [])
|
||||
search_keywords_or = params.get('keywords_or', True)
|
||||
search_foods_or = params.get('foods_or', True)
|
||||
search_books_or = params.get('books_or', True)
|
||||
ratings = request.query_params.getlist('ratings', [])
|
||||
keyword_list = request.query_params.getlist('keywords', [])
|
||||
food_list = request.query_params.getlist('foods', [])
|
||||
book_list = request.query_params.getlist('book', [])
|
||||
search_keywords_or = request.query_params.get('keywords_or', True)
|
||||
search_foods_or = request.query_params.get('foods_or', True)
|
||||
search_books_or = request.query_params.get('books_or', True)
|
||||
|
||||
# if using an OR search, will annotate all keywords, otherwise, just those that appear in results
|
||||
if search_keywords_or:
|
||||
keywords = Keyword.objects.filter(space=space).annotate(recipe_count=Count('recipe'))
|
||||
keywords = Keyword.objects.filter(space=request.space).annotate(recipe_count=Count('recipe'))
|
||||
else:
|
||||
keywords = Keyword.objects.filter(recipe__in=qs, space=space).annotate(recipe_count=Count('recipe'))
|
||||
keywords = Keyword.objects.filter(recipe__in=qs, space=request.space).annotate(recipe_count=Count('recipe'))
|
||||
# custom django-tree function annotates a queryset to make building a tree easier.
|
||||
# see https://django-treebeard.readthedocs.io/en/latest/api.html#treebeard.models.Node.get_annotated_list_qs for details
|
||||
kw_a = annotated_qs(keywords, root=True, fill=True)
|
||||
|
||||
# if using an OR search, will annotate all keywords, otherwise, just those that appear in results
|
||||
if search_foods_or:
|
||||
foods = Food.objects.filter(space=request.space).annotate(recipe_count=Count('ingredient'))
|
||||
else:
|
||||
foods = Food.objects.filter(ingredient__step__recipe__in=list(qs.values_list('id', flat=True)), space=request.space).annotate(recipe_count=Count('ingredient'))
|
||||
food_a = annotated_qs(foods, root=True, fill=True)
|
||||
|
||||
# TODO add rating facet
|
||||
facets['Ratings'] = []
|
||||
facets['Keywords'] = fill_annotated_parents(kw_a, keyword_list)
|
||||
# TODO add food facet
|
||||
facets['Foods'] = []
|
||||
facets['Foods'] = fill_annotated_parents(food_a, food_list)
|
||||
# TODO add book facet
|
||||
facets['Books'] = []
|
||||
|
||||
facets['Recent'] = ViewLog.objects.filter(
|
||||
created_by=request.user, space=request.space,
|
||||
created_at__gte=datetime.now() - timedelta(days=14) # TODO make days of recent recipe a setting
|
||||
).values_list('recipe__pk', flat=True)
|
||||
return facets
|
||||
|
||||
|
||||
@@ -262,6 +279,8 @@ def annotated_qs(qs, root=False, fill=False):
|
||||
dirty = False
|
||||
current_node = node_queue[-1]
|
||||
depth = current_node.get_depth()
|
||||
# TODO if node is at the wrong depth for some reason this fails
|
||||
# either create a 'fix node' page, or automatically move the node to the root
|
||||
parent_id = current_node.parent
|
||||
if root and depth > 1 and parent_id not in nodes_list:
|
||||
parent_id = current_node.parent
|
||||
|
||||
Reference in New Issue
Block a user