def _search(self, query_compiler_class, query, model_or_queryset, **kwargs): # Find model/queryset if isinstance(model_or_queryset, QuerySet): model = model_or_queryset.model queryset = model_or_queryset else: model = model_or_queryset queryset = model_or_queryset.objects.all() # Model must be a class that is in the index if not class_is_indexed(model): return EmptySearchResults() # Check that theres still a query string after the clean up if query == "": return EmptySearchResults() # Search query_compiler_class = query_compiler_class search_query = query_compiler_class( queryset, query, **kwargs ) # Check the query search_query.check() return self.results_class(self, search_query)
def list(request, app_label, model_name): model = get_snippet_model_from_url_params(app_label, model_name) permissions = [ get_permission_name(action, model) for action in ['add', 'change', 'delete'] ] if not any([request.user.has_perm(perm) for perm in permissions]): return permission_denied(request) items = model.objects.all() # Preserve the snippet's model-level ordering if specified, but fall back on PK if not # (to ensure pagination is consistent) if not items.ordered: items = items.order_by('pk') # Search is_searchable = class_is_indexed(model) is_searching = False search_query = None if is_searchable and 'q' in request.GET: search_form = SearchForm(request.GET, placeholder=_("Search %(snippet_type_name)s") % { 'snippet_type_name': model._meta.verbose_name_plural }) if search_form.is_valid(): search_query = search_form.cleaned_data['q'] search_backend = get_search_backend() items = search_backend.search(search_query, items) is_searching = True else: search_form = SearchForm(placeholder=_("Search %(snippet_type_name)s") % { 'snippet_type_name': model._meta.verbose_name_plural }) paginator = Paginator(items, per_page=20) paginated_items = paginator.get_page(request.GET.get('p')) # Template if request.is_ajax(): template = 'wagtailsnippets/snippets/results.html' else: template = 'wagtailsnippets/snippets/type_index.html' return render(request, template, { 'model_opts': model._meta, 'items': paginated_items, 'can_add_snippet': request.user.has_perm(get_permission_name('add', model)), 'can_delete_snippets': request.user.has_perm(get_permission_name('delete', model)), 'is_searchable': is_searchable, 'search_form': search_form, 'is_searching': is_searching, 'query_string': search_query, })
def choose(request, app_label, model_name): model = get_snippet_model_from_url_params(app_label, model_name) items = model.objects.all() # Preserve the snippet's model-level ordering if specified, but fall back on PK if not # (to ensure pagination is consistent) if not items.ordered: items = items.order_by('pk') # Search is_searchable = class_is_indexed(model) is_searching = False search_query = None if is_searchable and 'q' in request.GET: search_form = SearchForm(request.GET, placeholder=_("Search %(snippet_type_name)s") % { 'snippet_type_name': model._meta.verbose_name }) if search_form.is_valid(): search_query = search_form.cleaned_data['q'] search_backend = get_search_backend() items = search_backend.search(search_query, items) is_searching = True else: search_form = SearchForm(placeholder=_("Search %(snippet_type_name)s") % { 'snippet_type_name': model._meta.verbose_name }) # Pagination paginator = Paginator(items, per_page=25) paginated_items = paginator.get_page(request.GET.get('p')) # If paginating or searching, render "results.html" if request.GET.get('results', None) == 'true': return render(request, "wagtailsnippets/chooser/results.html", { 'model_opts': model._meta, 'items': paginated_items, 'query_string': search_query, 'is_searching': is_searching, }) return render_modal_workflow( request, 'wagtailsnippets/chooser/choose.html', None, { 'model_opts': model._meta, 'items': paginated_items, 'is_searchable': is_searchable, 'search_form': search_form, 'query_string': search_query, 'is_searching': is_searching, }, json_data={'step': 'choose'} )
def add_item(self, item): # Make sure the object can be indexed if not class_is_indexed(item.__class__): return # Get mapping mapping = self.mapping_class(item.__class__) # Add document to index self.es.index( self.name, mapping.get_document_type(), mapping.get_document(item), id=mapping.get_document_id(item) )
def choose(request): # TODO: Ideally this would return the endnotes for the current article. items = EndNote.objects.all() # Search is_searchable = class_is_indexed(EndNote) is_searching = False search_query = None if is_searchable and 'q' in request.GET: search_form = SearchForm(request.GET, placeholder=_("Search End Notes")) if search_form.is_valid(): search_query = search_form.cleaned_data['q'] search_backend = get_search_backend() items = search_backend.search(search_query, items) is_searching = True else: search_form = SearchForm(placeholder=_("Search End Notes")) # Pagination p = request.GET.get("p", 1) paginator = Paginator(items, 25) try: paginated_items = paginator.page(p) except PageNotAnInteger: paginated_items = paginator.page(1) except EmptyPage: paginated_items = paginator.page(paginator.num_pages) # If paginating or searching, render "results.html" if request.GET.get('results', None) == 'true': return render(request, "content_notes/chooser/results.html", { 'items': paginated_items, 'query_string': search_query, 'is_searching': is_searching, }) return render_modal_workflow( request, 'content_notes/chooser/choose.html', 'content_notes/chooser/choose.js', { 'items': paginated_items, 'is_searchable': is_searchable, 'search_form': search_form, 'query_string': search_query, 'is_searching': is_searching, } )
def search(self, query, model_or_queryset, fields=None, filters=None, prefetch_related=None, operator=None, order_by_relevance=True, include_partials=True, return_pks=False): # Find model/queryset if isinstance(model_or_queryset, QuerySet): model = model_or_queryset.model queryset = model_or_queryset else: model = model_or_queryset queryset = model_or_queryset.objects.all() # Model must be a class that is in the index if not class_is_indexed(model): return EmptySearchResults() # Check that theres still a query string after the clean up if query == "": return EmptySearchResults() # Apply filters to queryset if filters: queryset = queryset.filter(**filters) warnings.warn( "The 'filters' argument on the 'search()' method is deprecated. " "Please apply the filters to the base queryset instead.", category=RemovedInWagtail22Warning ) # Prefetch related if prefetch_related: for prefetch in prefetch_related: queryset = queryset.prefetch_related(prefetch) warnings.warn( "The 'prefetch_related' argument on the 'search()' method is deprecated. " "Please add prefetch_related to the base queryset instead.", category=RemovedInWagtail22Warning ) # Search search_query = self.query_compiler_class( queryset, query, fields=fields, operator=operator, order_by_relevance=order_by_relevance, include_partials=include_partials ) # Check the query search_query.check() return self.results_class(self, search_query, return_pks=return_pks)
def search(self, query_string, model_or_queryset, fields=None, filters=None, prefetch_related=None, operator=None, order_by_relevance=True): # Find model/queryset if isinstance(model_or_queryset, QuerySet): model = model_or_queryset.model queryset = model_or_queryset else: model = model_or_queryset queryset = model_or_queryset.objects.all() # Model must be a class that is in the index if not class_is_indexed(model): return EmptySearchResults() # Check that theres still a query string after the clean up if query_string == "": return EmptySearchResults() # Only fields that are indexed as a SearchField can be passed in fields if fields: allowed_fields = {field.field_name for field in model.get_searchable_search_fields()} for field_name in fields: if field_name not in allowed_fields: raise FieldError( 'Cannot search with field "' + field_name + '". Please add index.SearchField(\'' + field_name + '\') to ' + model.__name__ + '.search_fields.' ) # Apply filters to queryset if filters: queryset = queryset.filter(**filters) # Prefetch related if prefetch_related: for prefetch in prefetch_related: queryset = queryset.prefetch_related(prefetch) # Check operator if operator is not None: operator = operator.lower() if operator not in ['or', 'and']: raise ValueError("operator must be either 'or' or 'and'") # Search search_query = self.query_class( queryset, query_string, fields=fields, operator=operator, order_by_relevance=order_by_relevance ) return self.results_class(self, search_query)
def delete_item(self, item): # Make sure the object can be indexed if not class_is_indexed(item.__class__): return # Get mapping mapping = self.mapping_class(item.__class__) # Delete document try: self.es.delete( self.name, mapping.get_document_type(), mapping.get_document_id(item), ) except NotFoundError: pass # Document doesn't exist, ignore this exception
def resolve_queryset( qs, info, limit=None, offset=None, search_query=None, id=None, order=None, **kwargs ): """ Add limit, offset and search capabilities to the query. This contains argument names used by :class:`~wagtail_graphql.types.structures.QuerySetList`. :param qs: Query set to be modified. :param info: Graphene's info object. :param limit: Limit number of objects in the QuerySet. :type limit: int :param id: Filter by the primary key. :type limit: int :param offset: Omit a number of objects from the beggining of the query set :type offset: int :param search_query: Using wagtail search exclude objects that do not match the search query. :type search_query: str :param order: Use Django ordering format to order the query set. :type order: str """ offset = int(offset or 0) if id is not None: qs = qs.filter(pk=id) if id is None and search_query: # Check if the queryset is searchable using Wagtail search. if not class_is_indexed(qs.model): raise TypeError("This data type is not searchable by Wagtail.") if settings.GRAPPLE_ADD_SEARCH_HIT is True: query = Query.get(search_query) query.add_hit() return get_search_backend().search(search_query, qs) if order is not None: qs = qs.order_by(*map(lambda x: x.strip(), order.split(","))) if limit is not None: limit = int(limit) qs = qs[offset : limit + offset] return qs
def list(request): items = EndNote.objects.all() # Search is_searchable = class_is_indexed(EndNote) is_searching = False search_query = None if is_searchable and 'q' in request.GET: search_form = SearchForm(request.GET, placeholder=_("Search End Notes")) if search_form.is_valid(): search_query = search_form.cleaned_data['q'] search_backend = get_search_backend() items = search_backend.search(search_query, items) is_searching = True else: search_form = SearchForm(placeholder=_("Search End Notes")) # Pagination p = request.GET.get('p', 1) paginator = Paginator(items, 20) try: paginated_items = paginator.page(p) except PageNotAnInteger: paginated_items = paginator.page(1) except EmptyPage: paginated_items = paginator.page(paginator.num_pages) # Template if request.is_ajax(): template = 'content_notes/endnotes/results.html' else: template = 'content_notes/endnotes/type_index.html' return render(request, template, { 'items': paginated_items, 'is_searchable': is_searchable, 'search_form': search_form, 'is_searching': is_searching, 'query_string': search_query, })
def get_filter_form_class(self): if self.filter_form_class: return self.filter_form_class else: bases = [BaseFilterForm] if self.model_class: if class_is_indexed(self.model_class): bases.insert(0, SearchFilterMixin) if issubclass(self.model_class, CollectionMember): bases.insert(0, CollectionFilterMixin) if issubclass(self.model_class, TranslatableMixin): bases.insert(0, LocaleFilterMixin) return type( "FilterForm", tuple(bases), {}, )
def add_items(self, model, items): if not class_is_indexed(model): return # Get mapping mapping = self.mapping_class(model) doc_type = "_doc" # Create list of actions actions = [] for item in items: # Create the action action = {"_type": doc_type, "_id": mapping.get_document_id(item)} action.update(mapping.get_document(item)) actions.append(action) # Run the actions bulk(self.es, actions, index=self.name)
def get_queryset(self): queryset = super().get_queryset() search_form = self.get_search_form() if search_form.is_valid(): q = search_form.cleaned_data['q'] if class_is_indexed(queryset.model): search_backend = get_search_backend() queryset = search_backend.search(q, queryset, fields=self.search_fields) else: filters = { field + '__icontains': q for field in self.search_fields or [] } queryset = queryset.filter(**filters) return queryset
def add_items(self, model, items): if not class_is_indexed(model): return # Get mapping mapping = self.mapping_class(model) doc_type = mapping.get_document_type() # Create list of actions actions = [] for item in items: # Create the action action = { '_type': doc_type, '_id': mapping.get_document_id(item), } action.update(mapping.get_document(item)) actions.append(action) # Run the actions bulk(self.es, actions, index=self.name)
def search(self, query_string, model_or_queryset, fields=None, filters=None, prefetch_related=None, operator=None, order_by_relevance=True, extra_raw_filters=None, partial_match=True): # Find model/queryset if isinstance(model_or_queryset, QuerySet): model = model_or_queryset.model queryset = model_or_queryset else: model = model_or_queryset queryset = model_or_queryset.objects.all() # Model must be a class that is in the index if not class_is_indexed(model): return [] # Check that theres still a query string after the clean up if query_string == "": return [] # Apply filters to queryset if filters: queryset = queryset.filter(**filters) # Prefetch related if prefetch_related: for prefetch in prefetch_related: queryset = queryset.prefetch_related(prefetch) # Check operator if operator is not None: operator = operator.lower() if operator not in ['or', 'and']: raise ValueError("operator must be either 'or' or 'and'") # Search search_query = self.query_compiler_class( queryset, query_string, fields=fields, operator=operator, order_by_relevance=order_by_relevance, extra_raw_filters=extra_raw_filters ) return self.results_class(self, search_query)
def add_items(self, model, items): if not class_is_indexed(model): return # Get mapping mapping = self.mapping_class(model) doc_type = mapping.get_document_type() # Create list of actions actions = [] for item in items: # Create the action action = { '_index': self.name, '_type': doc_type, '_id': mapping.get_document_id(item), } action.update(mapping.get_document(item)) actions.append(action) # Run the actions bulk(self.es, actions)
def _search(self, query_compiler_class, query, model_or_queryset, **kwargs): # Find model/queryset if isinstance(model_or_queryset, QuerySet): model = model_or_queryset.model queryset = model_or_queryset else: model = model_or_queryset queryset = model_or_queryset.objects.all() # Model must be a class that is in the index if not class_is_indexed(model): return EmptySearchResults() # Check that there's still a query string after the clean up if query == "": return EmptySearchResults() # Search search_query_compiler = query_compiler_class(queryset, query, **kwargs) # Check the query search_query_compiler.check() return self.results_class(self, search_query_compiler)
def resolve_queryset( qs, info, limit=None, offset=None, search_query=None, id=None, order=None, collection=None, **kwargs, ): """ Add limit, offset and search capabilities to the query. This contains argument names used by :class:`~grapple.types.structures.QuerySetList`. :param qs: The query set to be modified. :param info: The Graphene info object. :param limit: Limit number of objects in the QuerySet. :type limit: int :param id: Filter by the primary key. :type id: int :param offset: Omit a number of objects from the beginning of the query set :type offset: int :param search_query: Using Wagtail search, exclude objects that do not match the search query. :type search_query: str :param order: Order the query set using the Django QuerySet order_by format. :type order: str :param collection: Use Wagtail's collection id to filter images or documents :type collection: int """ if id is not None: qs = qs.filter(pk=id) else: qs = qs.all() if id is None and search_query: # Check if the queryset is searchable using Wagtail search. if not class_is_indexed(qs.model): raise TypeError("This data type is not searchable by Wagtail.") if grapple_settings.ADD_SEARCH_HIT: query = Query.get(search_query) query.add_hit() qs = get_search_backend().search(search_query, qs) return _sliced_queryset(qs, limit, offset) if order is not None: qs = qs.order_by(*(x.strip() for x in order.split(","))) if collection is not None: try: qs.model._meta.get_field("collection") qs = qs.filter(collection=collection) except Exception: pass return _sliced_queryset(qs, limit, offset)
def get(self, request, app_label, model_name): self.model = get_snippet_model_from_url_params(app_label, model_name) items = self.model.objects.all() # Preserve the snippet's model-level ordering if specified, but fall back on PK if not # (to ensure pagination is consistent) if not items.ordered: items = items.order_by("pk") # Filter by locale self.locale = None self.locale_filter = None self.selected_locale = None if issubclass(self.model, TranslatableMixin): # 'locale' is the Locale of the object that this snippet is being chosen for if request.GET.get("locale"): self.locale = get_object_or_404( Locale, language_code=request.GET["locale"] ) # 'locale_filter' is the current value of the "Locale" selector in the UI if request.GET.get("locale_filter"): self.locale_filter = get_object_or_404( Locale, language_code=request.GET["locale_filter"] ) self.selected_locale = self.locale_filter or self.locale if self.selected_locale: items = items.filter(locale=self.selected_locale) # Search self.is_searchable = class_is_indexed(self.model) self.is_searching = False self.search_query = None if self.is_searchable and "q" in request.GET: self.search_form = SearchForm( request.GET, placeholder=_("Search %(snippet_type_name)s") % {"snippet_type_name": self.model._meta.verbose_name}, ) if self.search_form.is_valid(): self.search_query = self.search_form.cleaned_data["q"] search_backend = get_search_backend() items = search_backend.search(self.search_query, items) self.is_searching = True else: self.search_form = SearchForm( placeholder=_("Search %(snippet_type_name)s") % {"snippet_type_name": self.model._meta.verbose_name} ) # Pagination paginator = Paginator(items, per_page=25) self.paginated_items = paginator.get_page(request.GET.get("p")) self.table = Table( [ SnippetTitleColumn( "title", self.model, label=_("Title"), link_classname="snippet-choice", ), ], self.paginated_items, ) return self.render_to_response()
def list(request, app_label, model_name): model = get_snippet_model_from_url_params(app_label, model_name) permissions = [ get_permission_name(action, model) for action in ['add', 'change', 'delete'] ] if not any([request.user.has_perm(perm) for perm in permissions]): return permission_denied(request) items = model.objects.all() # Preserve the snippet's model-level ordering if specified, but fall back on PK if not # (to ensure pagination is consistent) if not items.ordered: items = items.order_by('pk') # Search is_searchable = class_is_indexed(model) is_searching = False search_query = None if is_searchable and 'q' in request.GET: search_form = SearchForm( request.GET, placeholder=_("Search %(snippet_type_name)s") % {'snippet_type_name': model._meta.verbose_name_plural}) if search_form.is_valid(): search_query = search_form.cleaned_data['q'] search_backend = get_search_backend() items = search_backend.search(search_query, items) is_searching = True else: search_form = SearchForm( placeholder=_("Search %(snippet_type_name)s") % {'snippet_type_name': model._meta.verbose_name_plural}) paginator = Paginator(items, per_page=20) paginated_items = paginator.get_page(request.GET.get('p')) # Template if request.is_ajax(): template = 'wagtailsnippets/snippets/results.html' else: template = 'wagtailsnippets/snippets/type_index.html' return TemplateResponse( request, template, { 'model_opts': model._meta, 'items': paginated_items, 'can_add_snippet': request.user.has_perm(get_permission_name('add', model)), 'can_delete_snippets': request.user.has_perm(get_permission_name('delete', model)), 'is_searchable': is_searchable, 'search_form': search_form, 'is_searching': is_searching, 'query_string': search_query, })
def is_searchable(self): return class_is_indexed(self.model)
def choose(request, app_label, model_name): model = get_snippet_model_from_url_params(app_label, model_name) items = model.objects.all() # Preserve the snippet's model-level ordering if specified, but fall back on PK if not # (to ensure pagination is consistent) if not items.ordered: items = items.order_by('pk') # Filter by locale locale = None locale_filter = None selected_locale = None if issubclass(model, TranslatableMixin): # 'locale' is the Locale of the object that this snippet is being chosen for if request.GET.get('locale'): locale = get_object_or_404(Locale, language_code=request.GET['locale']) # 'locale_filter' is the current value of the "Locale" selector in the UI if request.GET.get('locale_filter'): locale_filter = get_object_or_404( Locale, language_code=request.GET['locale_filter']) selected_locale = locale_filter or locale if selected_locale: items = items.filter(locale=selected_locale) # Search is_searchable = class_is_indexed(model) is_searching = False search_query = None if is_searchable and 'q' in request.GET: search_form = SearchForm( request.GET, placeholder=_("Search %(snippet_type_name)s") % {'snippet_type_name': model._meta.verbose_name}) if search_form.is_valid(): search_query = search_form.cleaned_data['q'] search_backend = get_search_backend() items = search_backend.search(search_query, items) is_searching = True else: search_form = SearchForm( placeholder=_("Search %(snippet_type_name)s") % {'snippet_type_name': model._meta.verbose_name}) # Pagination paginator = Paginator(items, per_page=25) paginated_items = paginator.get_page(request.GET.get('p')) # If paginating or searching, render "results.html" if request.GET.get('results', None) == 'true': return TemplateResponse( request, "wagtailsnippets/chooser/results.html", { 'model_opts': model._meta, 'items': paginated_items, 'query_string': search_query, 'is_searching': is_searching, 'locale': locale, 'locale_filter': locale_filter, 'selected_locale': selected_locale, }) return render_modal_workflow(request, 'wagtailsnippets/chooser/choose.html', None, { 'model_opts': model._meta, 'items': paginated_items, 'is_searchable': is_searchable, 'search_form': search_form, 'query_string': search_query, 'is_searching': is_searching, 'locale': locale, 'locale_filter': locale_filter, 'selected_locale': selected_locale, 'locale_options': Locale.objects.all() if issubclass( model, TranslatableMixin) else [], }, json_data={'step': 'choose'})
def add_generic_relations(cls): for model in apps.get_models(): if class_is_indexed(model): TextIDGenericRelation(cls).contribute_to_class( model, 'postgres_index_entries')
def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) items = self.model.objects.all() enable_locale_filter = getattr(settings, "WAGTAIL_I18N_ENABLED", False) and issubclass( self.model, TranslatableMixin) if enable_locale_filter: if "locale" in self.request.GET: try: locale = Locale.objects.get( language_code=self.request.GET["locale"]) except Locale.DoesNotExist: # Redirect to snippet without locale return redirect("wagtailsnippets:list", self.app_label, self.model_name) else: # Default to active locale (this will take into account the user's chosen admin language) locale = Locale.get_active() items = items.filter(locale=locale) else: locale = None # Preserve the snippet's model-level ordering if specified, but fall back on PK if not # (to ensure pagination is consistent) if not items.ordered: items = items.order_by("pk") # Search is_searchable = class_is_indexed(self.model) is_searching = False search_query = None if is_searchable and "q" in self.request.GET: search_form = SearchForm( self.request.GET, placeholder=_("Search %(snippet_type_name)s") % {"snippet_type_name": self.model._meta.verbose_name_plural}, ) if search_form.is_valid(): search_query = search_form.cleaned_data["q"] search_backend = get_search_backend() items = search_backend.search(search_query, items) is_searching = True else: search_form = SearchForm( placeholder=_("Search %(snippet_type_name)s") % {"snippet_type_name": self.model._meta.verbose_name_plural}) paginator = Paginator(items, per_page=20) paginated_items = paginator.get_page(self.request.GET.get("p")) context.update({ "model_opts": self.model._meta, "items": paginated_items, "can_add_snippet": self.request.user.has_perm(get_permission_name("add", self.model)), "can_delete_snippets": self.request.user.has_perm( get_permission_name("delete", self.model)), "is_searchable": is_searchable, "search_form": search_form, "is_searching": is_searching, "query_string": search_query, "locale": None, "translations": [], }) if enable_locale_filter: context.update({ "locale": locale, "translations": [{ "locale": locale, "url": reverse( "wagtailsnippets:list", args=[self.app_label, self.model_name], ) + "?locale=" + locale.language_code, } for locale in Locale.objects.all().exclude(id=locale.id)], }) return context
def PaginatedQuerySet(of_type, type_class, **kwargs): """ Paginated QuerySet type with arguments used by Django's query sets. This type setts the following arguments on itself: * ``id`` * ``page`` * ``per_page`` * ``search_query`` * ``order`` :param enable_search: Enable search query argument. :type enable_search: bool :param enable_order: Enable ordering via query argument. :type enable_order: bool """ enable_search = kwargs.pop("enable_search", True) enable_order = kwargs.pop("enable_order", True) required = kwargs.get("required", False) type_name = type_class if isinstance(type_class, str) else type_class.__name__ type_name = type_name.lstrip("Stub") # Check if the type is a Django model type. Do not perform the # check if value is lazy. if inspect.isclass(of_type) and not issubclass( of_type, graphene_django.DjangoObjectType ): raise TypeError( f"{of_type} is not a subclass of DjangoObjectType and it " "cannot be used with QuerySetList." ) # Enable page for Django Paginator. if "page" not in kwargs: kwargs["page"] = graphene.Argument( PositiveInt, default_value=1, description=_("Page of resulting objects to return."), ) # Enable per_page for Django Paginator. if "per_page" not in kwargs: kwargs["per_page"] = graphene.Argument( PositiveInt, default_value=10, description=_("The maximum number of items to include on a page."), ) # Enable ordering of the queryset if enable_order is True and "order" not in kwargs: kwargs["order"] = graphene.Argument( graphene.String, description=_("Use the Django QuerySet order_by format.") ) # If type is provided as a lazy value (e.g. using lambda), then # the search has to be enabled explicitly. if (enable_search is True and not inspect.isclass(of_type)) or ( enable_search is True and inspect.isclass(of_type) and class_is_indexed(of_type._meta.model) and "search_query" not in kwargs ): kwargs["search_query"] = graphene.Argument( graphene.String, description=_("Filter the results using Wagtail's search.") ) if "id" not in kwargs: kwargs["id"] = graphene.Argument(graphene.ID, description=_("Filter by ID")) class PaginatedType(BasePaginatedType): items = graphene.List(of_type, required=required) pagination = graphene.Field(PaginationType, required=required) class Meta: name = type_name + "PaginatedType" return graphene.Field(PaginatedType, **kwargs)
def add_generic_relations(cls): for model in apps.get_models(): if class_is_indexed(model): TextIDGenericRelation(cls).contribute_to_class(model, 'index_entries')
def search(self, query_string, model_or_queryset, fields=None, filters=None, prefetch_related=None, operator=None, order_by_relevance=True): # Find model/queryset if isinstance(model_or_queryset, QuerySet): model = model_or_queryset.model queryset = model_or_queryset else: model = model_or_queryset queryset = model_or_queryset.objects.all() # Model must be a class that is in the index if not class_is_indexed(model): return EmptySearchResults() # Check that theres still a query string after the clean up if query_string == "": return EmptySearchResults() # Only fields that are indexed as a SearchField can be passed in fields if fields: allowed_fields = { field.field_name for field in model.get_searchable_search_fields() } for field_name in fields: if field_name not in allowed_fields: raise FieldError('Cannot search with field "' + field_name + '". Please add index.SearchField(\'' + field_name + '\') to ' + model.__name__ + '.search_fields.') # Apply filters to queryset if filters: queryset = queryset.filter(**filters) # Prefetch related if prefetch_related: for prefetch in prefetch_related: queryset = queryset.prefetch_related(prefetch) # Check operator if operator is not None: operator = operator.lower() if operator not in ['or', 'and']: raise ValueError("operator must be either 'or' or 'and'") # Search search_query = self.query_class(queryset, query_string, fields=fields, operator=operator, order_by_relevance=order_by_relevance) return self.results_class(self, search_query)
def list(request, app_label, model_name): model = get_snippet_model_from_url_params(app_label, model_name) permissions = [ get_permission_name(action, model) for action in ['add', 'change', 'delete'] ] if not any([request.user.has_perm(perm) for perm in permissions]): raise PermissionDenied items = model.objects.all() enable_locale_filter = getattr(settings, 'WAGTAIL_I18N_ENABLED', False) and issubclass( model, TranslatableMixin) if enable_locale_filter: if 'locale' in request.GET: try: locale = Locale.objects.get( language_code=request.GET['locale']) except Locale.DoesNotExist: # Redirect to snippet without locale return redirect('wagtailsnippets:list', app_label, model_name) else: # Default to active locale (this will take into account the user's chosen admin language) locale = Locale.get_active() items = items.filter(locale=locale) else: locale = None # Preserve the snippet's model-level ordering if specified, but fall back on PK if not # (to ensure pagination is consistent) if not items.ordered: items = items.order_by('pk') # Search is_searchable = class_is_indexed(model) is_searching = False search_query = None if is_searchable and 'q' in request.GET: search_form = SearchForm( request.GET, placeholder=_("Search %(snippet_type_name)s") % {'snippet_type_name': model._meta.verbose_name_plural}) if search_form.is_valid(): search_query = search_form.cleaned_data['q'] search_backend = get_search_backend() items = search_backend.search(search_query, items) is_searching = True else: search_form = SearchForm( placeholder=_("Search %(snippet_type_name)s") % {'snippet_type_name': model._meta.verbose_name_plural}) paginator = Paginator(items, per_page=20) paginated_items = paginator.get_page(request.GET.get('p')) # Template if request.is_ajax(): template = 'wagtailsnippets/snippets/results.html' else: template = 'wagtailsnippets/snippets/type_index.html' context = { 'model_opts': model._meta, 'items': paginated_items, 'can_add_snippet': request.user.has_perm(get_permission_name('add', model)), 'can_delete_snippets': request.user.has_perm(get_permission_name('delete', model)), 'is_searchable': is_searchable, 'search_form': search_form, 'is_searching': is_searching, 'query_string': search_query, 'locale': None, 'translations': [], } if enable_locale_filter: context.update({ 'locale': locale, 'translations': [{ 'locale': locale, 'url': reverse('wagtailsnippets:list', args=[app_label, model_name]) + '?locale=' + locale.language_code } for locale in Locale.objects.all().exclude(id=locale.id)], }) return TemplateResponse(request, template, context)
def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) items = self.model.objects.all() enable_locale_filter = getattr(settings, 'WAGTAIL_I18N_ENABLED', False) and issubclass( self.model, TranslatableMixin) if enable_locale_filter: if 'locale' in self.request.GET: try: locale = Locale.objects.get( language_code=self.request.GET['locale']) except Locale.DoesNotExist: # Redirect to snippet without locale return redirect('wagtailsnippets:list', self.app_label, self.model_name) else: # Default to active locale (this will take into account the user's chosen admin language) locale = Locale.get_active() items = items.filter(locale=locale) else: locale = None # Preserve the snippet's model-level ordering if specified, but fall back on PK if not # (to ensure pagination is consistent) if not items.ordered: items = items.order_by('pk') # Search is_searchable = class_is_indexed(self.model) is_searching = False search_query = None if is_searchable and 'q' in self.request.GET: search_form = SearchForm( self.request.GET, placeholder=_("Search %(snippet_type_name)s") % {'snippet_type_name': self.model._meta.verbose_name_plural}) if search_form.is_valid(): search_query = search_form.cleaned_data['q'] search_backend = get_search_backend() items = search_backend.search(search_query, items) is_searching = True else: search_form = SearchForm( placeholder=_("Search %(snippet_type_name)s") % {'snippet_type_name': self.model._meta.verbose_name_plural}) paginator = Paginator(items, per_page=20) paginated_items = paginator.get_page(self.request.GET.get('p')) context.update({ 'model_opts': self.model._meta, 'items': paginated_items, 'can_add_snippet': self.request.user.has_perm(get_permission_name('add', self.model)), 'can_delete_snippets': self.request.user.has_perm( get_permission_name('delete', self.model)), 'is_searchable': is_searchable, 'search_form': search_form, 'is_searching': is_searching, 'query_string': search_query, 'locale': None, 'translations': [], }) if enable_locale_filter: context.update({ 'locale': locale, 'translations': [{ 'locale': locale, 'url': reverse('wagtailsnippets:list', args=[self.app_label, self.model_name]) + '?locale=' + locale.language_code } for locale in Locale.objects.all().exclude(id=locale.id)], }) return context
def get_is_searchable(self): if self.model is None: return False if self.is_searchable is None: return class_is_indexed(self.model) or self.search_fields return self.is_searchable