Exemple #1
0
    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)
Exemple #2
0
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,
    })
Exemple #3
0
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)
        )
Exemple #5
0
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,
        }
    )
Exemple #6
0
    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)
Exemple #7
0
    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
Exemple #9
0
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
Exemple #10
0
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,
    })
Exemple #11
0
    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),
                {},
            )
Exemple #12
0
    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)
Exemple #13
0
    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 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)
Exemple #16
0
    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)
Exemple #18
0
    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)
Exemple #19
0
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)
Exemple #20
0
    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()
Exemple #21
0
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,
        })
Exemple #22
0
 def is_searchable(self):
     return class_is_indexed(self.model)
Exemple #23
0
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'})
Exemple #24
0
 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')
Exemple #25
0
    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
Exemple #26
0
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)
Exemple #27
0
 def add_generic_relations(cls):
     for model in apps.get_models():
         if class_is_indexed(model):
             TextIDGenericRelation(cls).contribute_to_class(model,
                                                            'index_entries')
Exemple #28
0
    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)
Exemple #29
0
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)
Exemple #30
0
    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
Exemple #31
0
 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