Noelia  Graham

Noelia Graham

1660513680

Recherche De Base Et En Texte Intégral Avec Django Et Postgres

Contrairement aux bases de données relationnelles, la recherche plein texte n'est pas standardisée. Il existe plusieurs options open source comme ElasticSearch, Solr et Xapian. ElasticSearch est probablement la solution la plus populaire ; cependant, il est compliqué à configurer et à entretenir. De plus, si vous ne profitez pas de certaines des fonctionnalités avancées offertes par ElasticSearch, vous devez vous en tenir aux capacités de recherche en texte intégral que de nombreuses bases de données relationnelles (comme Postgres, MySQL, SQLite) et non relationnelles (comme MongoDB et CouchDB ) offrir. Postgres en particulier est bien adapté à la recherche en texte intégral. Django le prend également en charge immédiatement.

Pour la grande majorité de vos applications Django, vous devriez, à tout le moins, commencer par tirer parti de la recherche en texte intégral de Postgres avant de vous tourner vers une solution plus puissante comme ElasticSearch ou Solr.

Dans ce didacticiel, vous apprendrez à ajouter une recherche de base et en texte intégral à une application Django avec Postgres. Vous optimiserez également la recherche en texte intégral en ajoutant un champ vectoriel de recherche et un index de base de données.

Objectifs

À la fin de ce didacticiel, vous serez en mesure de :

  1. Configurer la fonctionnalité de recherche de base dans une application Django avec le module d'objet Q
  2. Ajouter une recherche en texte intégral à une application Django
  3. Triez les résultats de recherche en texte intégral par pertinence à l'aide de techniques de radicalisation, de classement et de pondération
  4. Ajouter un aperçu à vos résultats de recherche
  5. Optimisez la recherche en texte intégral avec un champ vectoriel de recherche et un index de base de données

Configuration et aperçu du projet

Clonez la branche de base à partir du référentiel django-search :

$ git clone https://github.com/testdrivenio/django-search --branch base --single-branch
$ cd django-search

Vous utiliserez Docker pour simplifier la configuration et l'exécution de Postgres avec Django.

À partir de la racine du projet, créez les images et lancez les conteneurs Docker :

$ docker-compose up -d --build

Ensuite, appliquez les migrations et créez un superutilisateur :

$ docker-compose exec web python manage.py makemigrations
$ docker-compose exec web python manage.py migrate
$ docker-compose exec web python manage.py createsuperuser

Une fois cela fait, accédez à http://127.0.0.1:8011/quotes/ pour vous assurer que l'application fonctionne comme prévu. Vous devriez voir ce qui suit :

Page d'accueil du devis

Vous voulez apprendre à travailler avec Django et Postgres ? Consultez l' article Dockeriser Django avec Postgres, Gunicorn et Nginx .

Prenez note du Quotemodèle dans quotes/models.py :

from django.db import models

class Quote(models.Model):
    name = models.CharField(max_length=250)
    quote = models.TextField(max_length=1000)

    def __str__(self):
        return self.quote

Ensuite, exécutez la commande de gestion suivante pour ajouter 10 000 devis à la base de données :

$ docker-compose exec web python manage.py add_quotes

Cela prendra quelques minutes. Une fois cela fait, accédez à http://127.0.0.1:8011/quotes/ pour voir les données.

La sortie de la vue est mise en cache pendant cinq minutes, vous pouvez donc commenter le fichier @method_decoratorin quotes/views.py pour charger les guillemets. Assurez-vous de supprimer le commentaire une fois terminé.

Page d'accueil du devis

Dans le fichier quotes/templates/quote.html , vous avez un formulaire basique avec un champ de saisie de recherche :

<form action="{% url 'search_results' %}" method="get">
  <input
    type="search"
    name="q"
    placeholder="Search by name or quote..."
    class="form-control"
  />
</form>

Lors de la soumission, le formulaire envoie les données au backend. Une GETrequête est utilisée plutôt qu'une POSTafin que nous ayons accès à la chaîne de requête à la fois dans l'URL et dans la vue Django, permettant aux utilisateurs de partager les résultats de la recherche sous forme de liens.

Avant d'aller plus loin, jetez un coup d'œil à la structure du projet et au reste du code.

Recherche de base

En ce qui concerne la recherche, avec Django, vous commencerez généralement par effectuer des requêtes de recherche avec containsou icontainspour des correspondances exactes. L' objet Q peut également être utilisé pour ajouter des opérateurs logiques AND ( &) ou OR ( ).|

Par exemple, en utilisant l'opérateur OR, remplacez la valeur par SearchResultsListdéfaut de 's QuerySetdans quotes/views.py comme ceci :

class SearchResultsList(ListView):
    model = Quote
    context_object_name = "quotes"
    template_name = "search.html"

    def get_queryset(self):
        query = self.request.GET.get("q")
        return Quote.objects.filter(
            Q(name__icontains=query) | Q(quote__icontains=query)
        )

Ici, nous avons utilisé la méthode de filtrage pour filtrer les champs ou name. quoteDe plus, nous avons également utilisé l' extension icontains pour vérifier si la requête est présente dans les champs nameou quote(insensible à la casse). Un résultat positif sera renvoyé si une correspondance est trouvée.

N'oubliez pas l'importation :

from django.db.models import Q

Essaye le:

Page de recherche

Pour les petits ensembles de données, c'est un excellent moyen d'ajouter des fonctionnalités de recherche de base à votre application. Si vous avez affaire à un ensemble de données volumineux ou si vous souhaitez une fonctionnalité de recherche qui ressemble à un moteur de recherche Internet, vous souhaiterez passer à la recherche en texte intégral.

Recherche en texte intégral

La recherche de base que nous avons vue précédemment présente plusieurs limites, en particulier lorsque vous souhaitez effectuer des recherches complexes.

Comme mentionné, avec la recherche de base, vous ne pouvez effectuer que des correspondances exactes.

Une autre limitation est celle des mots vides . Les mots vides sont des mots tels que "un", "un" et "le". Ces mots sont courants et insuffisamment significatifs, ils doivent donc être ignorés. Pour tester, essayez de rechercher un mot précédé de "le". Disons que vous avez recherché "le milieu". Dans ce cas, vous ne verrez que les résultats pour "le milieu", donc vous ne verrez aucun résultat contenant le mot "moyen" sans "le" avant.

Supposons que vous ayez ces deux phrases :

  1. Je suis au milieu.
  2. Tu n'aimes pas le collège.

Vous obtiendrez les éléments suivants renvoyés avec chaque type de recherche :

RequêteRecherche de baseRecherche en texte intégral
"le milieu"première1 et 2
"milieu"1 et 21 et 2

Un autre problème est celui d'ignorer des mots similaires. Avec la recherche de base, seules les correspondances exactes sont renvoyées. Cependant, avec la recherche plein texte, les mots similaires sont pris en compte. Pour tester, essayez de trouver des mots similaires comme "poney" et "poneys". Avec la recherche de base, si vous recherchez "poney", vous ne verrez pas les résultats contenant "poneys" - et vice versa.

Dites que vous avez ces deux phrases.

  1. je suis un poney.
  2. Vous n'aimez pas les poneys

Vous obtiendrez les éléments suivants renvoyés avec chaque type de recherche :

RequêteRecherche de baseRecherche en texte intégral
"poney"première1 et 2
"poneys"21 et 2

Avec la recherche en texte intégral, ces deux problèmes sont atténués. Cependant, gardez à l'esprit qu'en fonction de votre objectif, la recherche en texte intégral peut en fait diminuer la précision (qualité) et le rappel (quantité de résultats pertinents). En règle générale, la recherche de texte intégral est moins précise que la recherche de base, car la recherche de base donne des correspondances exactes. Cela dit, si vous effectuez une recherche dans de grands ensembles de données avec de gros blocs de texte, la recherche en texte intégral est préférable car elle est généralement beaucoup plus rapide.

La recherche en texte intégral est une technique de recherche avancée qui examine tous les mots de chaque document stocké en essayant de faire correspondre les critères de recherche. De plus, avec la recherche en texte intégral, vous pouvez utiliser des racines spécifiques à la langue sur les mots indexés. Par exemple, les mots "drives", "drove" et "driven" seront enregistrés sous le mot concept unique "drive". La radicalisation est le processus de réduction des mots à leur racine, leur base ou leur racine.

Il suffit de dire que la recherche plein texte n'est pas parfaite. Il est susceptible de récupérer de nombreux documents qui ne sont pas pertinents (faux positifs) pour la requête de recherche prévue. Cependant, certaines techniques basées sur des algorithmes bayésiens peuvent aider à réduire ces problèmes.

Pour profiter de la recherche plein texte de Postgres avec Django, ajoutez django.contrib.postgresà votre INSTALLED_APPSliste :

INSTALLED_APPS = [
    ...

    "django.contrib.postgres",  # new
]

Examinons ensuite deux exemples rapides de recherche plein texte, sur un seul champ et sur plusieurs champs.

Recherche de champ unique

Mettez à jour la get_querysetfonction sous la SearchResultsListfonction d'affichage comme ceci :

class SearchResultsList(ListView):
    model = Quote
    context_object_name = "quotes"
    template_name = "search.html"

    def get_queryset(self):
        query = self.request.GET.get("q")
        return Quote.objects.filter(quote__search=query)

Ici, nous configurons la recherche en texte intégral sur un seul champ - le champ de citation.

Page de recherche

Comme vous pouvez le voir, il prend en compte les mots similaires. Dans l'exemple ci-dessus, "poneys" et "poney" sont traités comme des mots similaires.

Recherche multi-champs

Pour effectuer une recherche sur plusieurs champs et sur des modèles associés, vous pouvez utiliser la SearchVectorclasse.

Encore une fois, mettez à jour SearchResultsList:

class SearchResultsList(ListView):
    model = Quote
    context_object_name = "quotes"
    template_name = "search.html"

    def get_queryset(self):
        query = self.request.GET.get("q")
        return Quote.objects.annotate(search=SearchVector("name", "quote")).filter(
            search=query
        )

Pour effectuer une recherche sur plusieurs champs, vous annotez le jeu de requêtes à l'aide d'un SearchVector. Le vecteur correspond aux données que vous recherchez, qui ont été converties en un formulaire facile à rechercher. Dans l'exemple ci-dessus, ces données sont les champs nameet de votre base de données.quote

Assurez-vous d'ajouter l'importation :

from django.contrib.postgres.search import SearchVector

Essayez quelques recherches.

Enracinement et classement

Dans cette section, vous combinerez plusieurs méthodes telles que SearchVector , SearchQuery et SearchRank pour produire une recherche très robuste qui utilise à la fois la radicalisation et le classement.

Encore une fois, le stemming est le processus de réduction des mots à leur forme de radical, de base ou de racine. Avec la racine, des mots comme "enfant" et "enfants" seront traités comme des mots similaires. Le classement, en revanche, nous permet de classer les résultats par pertinence.

Mise à jour SearchResultsList:

class SearchResultsList(ListView):
    model = Quote
    context_object_name = "quotes"
    template_name = "search.html"

    def get_queryset(self):
        query = self.request.GET.get("q")
        search_vector = SearchVector("name", "quote")
        search_query = SearchQuery(query)
        return (
            Quote.objects.annotate(
                search=search_vector, rank=SearchRank(search_vector, search_query)
            )
            .filter(search=search_query)
            .order_by("-rank")
        )

Qu'est-ce qu'il se passe ici?

  1. SearchVector- encore une fois, vous avez utilisé un vecteur de recherche pour effectuer une recherche dans plusieurs champs. Les données sont converties sous une autre forme puisque vous ne recherchez plus simplement le texte brut comme vous le faisiez lorsqu'il icontainsétait utilisé. Par conséquent, avec cela, vous pourrez facilement rechercher des pluriels. Par exemple, rechercher "flask" et "flasks" donnera la même recherche car ils sont, eh bien, fondamentalement la même chose.
  2. SearchQuery- traduit les mots qui nous sont fournis sous forme de requête à partir du formulaire, les fait passer par un algorithme de radicalisation, puis recherche des correspondances pour tous les termes résultants.
  3. SearchRank- permet de classer les résultats par pertinence. Il prend en compte la fréquence d'apparition des termes de la requête dans le document, la proximité des termes sur le document et l'importance de la partie du document où ils apparaissent.

Ajoutez les importations :

from django.contrib.postgres.search import SearchVector, SearchQuery, SearchRank

Page de recherche

Comparez les résultats de la recherche de base à ceux de la recherche en texte intégral. Il y a une nette différence. Dans la recherche de texte intégral, la requête avec les résultats les plus élevés est affichée en premier. C'est le pouvoir de SearchRank. La combinaison SearchVectorde , SearchQueryet SearchRankest un moyen rapide de produire une recherche beaucoup plus puissante et précise que la recherche de base.

Ajout de poids

La recherche en texte intégral nous donne la possibilité d'ajouter plus d'importance à certains champs de notre table dans la base de données par rapport à d'autres champs. Nous pouvons y parvenir en ajoutant des poids à nos requêtes.

Le poids doit être l'une des lettres suivantes D, C, B, A. Par défaut, ces poids font référence aux nombres 0,1, 0,2, 0,4 et 1,0, respectivement.

Mise à jour SearchResultsList:

class SearchResultsList(ListView):
    model = Quote
    context_object_name = "quotes"
    template_name = "search.html"

    def get_queryset(self):
        query = self.request.GET.get("q")
        search_vector = SearchVector("name", weight="B") + SearchVector(
            "quote", weight="A"
        )
        search_query = SearchQuery(query)
        return (
            Quote.objects.annotate(rank=SearchRank(search_vector, search_query))
            .filter(rank__gte=0.3)
            .order_by("-rank")
        )

Ici, vous avez ajouté des pondérations à l' SearchVectoraide des champs nameet . quoteDes pondérations de 0,4 et 1,0 ont été appliquées respectivement aux champs de nom et de citation. Par conséquent, les correspondances entre guillemets prévaudront sur les correspondances avec le contenu du nom. Enfin, vous avez filtré les résultats pour n'afficher que ceux qui sont supérieurs à 0,3.

Ajout d'un aperçu aux résultats de la recherche

Dans cette section, vous allez ajouter un petit aperçu de votre résultat de recherche via la méthode SearchHeadline . Cela mettra en surbrillance la requête de résultat de recherche.

Mettre à jour SearchResultsListà nouveau :

class SearchResultsList(ListView):
    model = Quote
    context_object_name = "quotes"
    template_name = "search.html"

    def get_queryset(self):
        query = self.request.GET.get("q")
        search_vector = SearchVector("name", "quote")
        search_query = SearchQuery(query)
        search_headline = SearchHeadline("quote", search_query)
        return Quote.objects.annotate(
            search=search_vector,
            rank=SearchRank(search_vector, search_query)
        ).annotate(headline=search_headline).filter(search=search_query).order_by("-rank")

Les SearchHeadlineprises dans le champ que vous souhaitez prévisualiser. Dans ce cas, ce sera le quotechamp avec la requête, qui sera en gras.

Assurez-vous d'ajouter l'importation :

from django.contrib.postgres.search import SearchVector, SearchQuery, SearchRank, SearchHeadline

Avant d'essayer certaines recherches, mettez à jour le fichier <li></li>in quotes/templates/search.html comme ceci :

<li>{{ quote.headline | safe }} - <b>By <i>{{ quote.name }}</i></b></li>

Désormais, au lieu d'afficher les citations comme vous le faisiez auparavant, seul un aperçu du champ de citation complet s'affiche avec la requête de recherche en surbrillance.

Amélioration des performances

La recherche en texte intégral est un processus intensif. Pour lutter contre le ralentissement des performances, vous pouvez :

  1. Enregistrez les vecteurs de recherche dans la base de données avec SearchVectorField . En d'autres termes, plutôt que de convertir les chaînes en vecteurs de recherche à la volée, nous allons créer un champ de base de données séparé contenant les vecteurs de recherche traités et mettre à jour le champ chaque fois qu'il y a une insertion ou une mise à jour des champs quoteou .name
  2. Créez un index de base de données , qui est une structure de données qui améliore la vitesse des processus de récupération de données sur une base de données. Cela accélère donc la requête. Postgres vous donne plusieurs index avec lesquels travailler qui pourraient être applicables à différentes situations. Le GinIndex est sans doute le plus populaire.

Pour en savoir plus sur les performances avec la recherche en texte intégral, consultez la section Performances de la documentation Django.

Champ vectoriel de recherche

Commencez par ajouter un nouveau champ SearchVectorField au modèleQuote dans quotes/models.py :

from django.contrib.postgres.search import SearchVectorField  # new
from django.db import models


class Quote(models.Model):
    name = models.CharField(max_length=250)
    quote = models.TextField(max_length=1000)
    search_vector = SearchVectorField(null=True)  # new

    def __str__(self):
        return self.quote

Créez le fichier de migration :

$ docker-compose exec web python manage.py makemigrations

Désormais, vous ne pouvez remplir ce champ que lorsque les objets quoteou nameexistent déjà dans la base de données. Ainsi, nous devons ajouter un déclencheur pour mettre à jour le search_vectorchamp chaque fois que les champs quoteou namesont mis à jour. Pour cela, créez un fichier de migration personnalisé dans "quotes/migrations" appelé 0003_search_vector_trigger.py :

from django.contrib.postgres.search import SearchVector
from django.db import migrations


def compute_search_vector(apps, schema_editor):
    Quote = apps.get_model("quotes", "Quote")
    Quote.objects.update(search_vector=SearchVector("name", "quote"))


class Migration(migrations.Migration):

    dependencies = [
        ("quotes", "0002_quote_search_vector"),
    ]

    operations = [
        migrations.RunSQL(
            sql="""
            CREATE TRIGGER search_vector_trigger
            BEFORE INSERT OR UPDATE OF name, quote, search_vector
            ON quotes_quote
            FOR EACH ROW EXECUTE PROCEDURE
            tsvector_update_trigger(
                search_vector, 'pg_catalog.english', name, quote
            );
            UPDATE quotes_quote SET search_vector = NULL;
            """,
            reverse_sql="""
            DROP TRIGGER IF EXISTS search_vector_trigger
            ON quotes_quote;
            """,
        ),
        migrations.RunPython(
            compute_search_vector, reverse_code=migrations.RunPython.noop
        ),
    ]

Selon la structure de votre projet, vous devrez peut-être mettre à jour le nom du fichier de migration précédent dans dependencies.

Appliquez les migrations :

$ docker-compose exec web python manage.py migrate

Pour utiliser le nouveau champ pour les recherches, procédez à la mise SearchResultsListà jour :

class SearchResultsList(ListView):
    model = Quote
    context_object_name = "quotes"
    template_name = "search.html"

    def get_queryset(self):
        query = self.request.GET.get("q")
        return Quote.objects.filter(search_vector=query)

Mettez à jour à nouveau le fichier <li></li>in quotes/templates/search.html :

<li>{{ quote.quote | safe }} - <b>By <i>{{ quote.name }}</i></b></li>

Indice

Enfin, configurons un index fonctionnel, GinIndex .

Mettez à jour le Quotemodèle :

from django.contrib.postgres.indexes import GinIndex  # new
from django.contrib.postgres.search import SearchVectorField
from django.db import models


class Quote(models.Model):
    name = models.CharField(max_length=250)
    quote = models.TextField(max_length=1000)
    search_vector = SearchVectorField(null=True)

    def __str__(self):
        return self.quote

    # new
    class Meta:
        indexes = [
            GinIndex(fields=["search_vector"]),
        ]

Créez et appliquez les migrations une dernière fois :

$ docker-compose exec web python manage.py makemigrations
$ docker-compose exec web python manage.py migrate

Testez-le.

Conclusion

Dans ce didacticiel, vous avez été guidé dans l'ajout d'une recherche de base et de texte intégral à une application Django. Nous avons également examiné comment optimiser la fonctionnalité de recherche en texte intégral en ajoutant un champ vectoriel de recherche et un index de base de données.

Récupérez le code complet du référentiel django-search .

Source :  https://testdrive.io

#django #postgre 

What is GEEK

Buddha Community

Recherche De Base Et En Texte Intégral Avec Django Et Postgres
Noelia  Graham

Noelia Graham

1660513680

Recherche De Base Et En Texte Intégral Avec Django Et Postgres

Contrairement aux bases de données relationnelles, la recherche plein texte n'est pas standardisée. Il existe plusieurs options open source comme ElasticSearch, Solr et Xapian. ElasticSearch est probablement la solution la plus populaire ; cependant, il est compliqué à configurer et à entretenir. De plus, si vous ne profitez pas de certaines des fonctionnalités avancées offertes par ElasticSearch, vous devez vous en tenir aux capacités de recherche en texte intégral que de nombreuses bases de données relationnelles (comme Postgres, MySQL, SQLite) et non relationnelles (comme MongoDB et CouchDB ) offrir. Postgres en particulier est bien adapté à la recherche en texte intégral. Django le prend également en charge immédiatement.

Pour la grande majorité de vos applications Django, vous devriez, à tout le moins, commencer par tirer parti de la recherche en texte intégral de Postgres avant de vous tourner vers une solution plus puissante comme ElasticSearch ou Solr.

Dans ce didacticiel, vous apprendrez à ajouter une recherche de base et en texte intégral à une application Django avec Postgres. Vous optimiserez également la recherche en texte intégral en ajoutant un champ vectoriel de recherche et un index de base de données.

Objectifs

À la fin de ce didacticiel, vous serez en mesure de :

  1. Configurer la fonctionnalité de recherche de base dans une application Django avec le module d'objet Q
  2. Ajouter une recherche en texte intégral à une application Django
  3. Triez les résultats de recherche en texte intégral par pertinence à l'aide de techniques de radicalisation, de classement et de pondération
  4. Ajouter un aperçu à vos résultats de recherche
  5. Optimisez la recherche en texte intégral avec un champ vectoriel de recherche et un index de base de données

Configuration et aperçu du projet

Clonez la branche de base à partir du référentiel django-search :

$ git clone https://github.com/testdrivenio/django-search --branch base --single-branch
$ cd django-search

Vous utiliserez Docker pour simplifier la configuration et l'exécution de Postgres avec Django.

À partir de la racine du projet, créez les images et lancez les conteneurs Docker :

$ docker-compose up -d --build

Ensuite, appliquez les migrations et créez un superutilisateur :

$ docker-compose exec web python manage.py makemigrations
$ docker-compose exec web python manage.py migrate
$ docker-compose exec web python manage.py createsuperuser

Une fois cela fait, accédez à http://127.0.0.1:8011/quotes/ pour vous assurer que l'application fonctionne comme prévu. Vous devriez voir ce qui suit :

Page d'accueil du devis

Vous voulez apprendre à travailler avec Django et Postgres ? Consultez l' article Dockeriser Django avec Postgres, Gunicorn et Nginx .

Prenez note du Quotemodèle dans quotes/models.py :

from django.db import models

class Quote(models.Model):
    name = models.CharField(max_length=250)
    quote = models.TextField(max_length=1000)

    def __str__(self):
        return self.quote

Ensuite, exécutez la commande de gestion suivante pour ajouter 10 000 devis à la base de données :

$ docker-compose exec web python manage.py add_quotes

Cela prendra quelques minutes. Une fois cela fait, accédez à http://127.0.0.1:8011/quotes/ pour voir les données.

La sortie de la vue est mise en cache pendant cinq minutes, vous pouvez donc commenter le fichier @method_decoratorin quotes/views.py pour charger les guillemets. Assurez-vous de supprimer le commentaire une fois terminé.

Page d'accueil du devis

Dans le fichier quotes/templates/quote.html , vous avez un formulaire basique avec un champ de saisie de recherche :

<form action="{% url 'search_results' %}" method="get">
  <input
    type="search"
    name="q"
    placeholder="Search by name or quote..."
    class="form-control"
  />
</form>

Lors de la soumission, le formulaire envoie les données au backend. Une GETrequête est utilisée plutôt qu'une POSTafin que nous ayons accès à la chaîne de requête à la fois dans l'URL et dans la vue Django, permettant aux utilisateurs de partager les résultats de la recherche sous forme de liens.

Avant d'aller plus loin, jetez un coup d'œil à la structure du projet et au reste du code.

Recherche de base

En ce qui concerne la recherche, avec Django, vous commencerez généralement par effectuer des requêtes de recherche avec containsou icontainspour des correspondances exactes. L' objet Q peut également être utilisé pour ajouter des opérateurs logiques AND ( &) ou OR ( ).|

Par exemple, en utilisant l'opérateur OR, remplacez la valeur par SearchResultsListdéfaut de 's QuerySetdans quotes/views.py comme ceci :

class SearchResultsList(ListView):
    model = Quote
    context_object_name = "quotes"
    template_name = "search.html"

    def get_queryset(self):
        query = self.request.GET.get("q")
        return Quote.objects.filter(
            Q(name__icontains=query) | Q(quote__icontains=query)
        )

Ici, nous avons utilisé la méthode de filtrage pour filtrer les champs ou name. quoteDe plus, nous avons également utilisé l' extension icontains pour vérifier si la requête est présente dans les champs nameou quote(insensible à la casse). Un résultat positif sera renvoyé si une correspondance est trouvée.

N'oubliez pas l'importation :

from django.db.models import Q

Essaye le:

Page de recherche

Pour les petits ensembles de données, c'est un excellent moyen d'ajouter des fonctionnalités de recherche de base à votre application. Si vous avez affaire à un ensemble de données volumineux ou si vous souhaitez une fonctionnalité de recherche qui ressemble à un moteur de recherche Internet, vous souhaiterez passer à la recherche en texte intégral.

Recherche en texte intégral

La recherche de base que nous avons vue précédemment présente plusieurs limites, en particulier lorsque vous souhaitez effectuer des recherches complexes.

Comme mentionné, avec la recherche de base, vous ne pouvez effectuer que des correspondances exactes.

Une autre limitation est celle des mots vides . Les mots vides sont des mots tels que "un", "un" et "le". Ces mots sont courants et insuffisamment significatifs, ils doivent donc être ignorés. Pour tester, essayez de rechercher un mot précédé de "le". Disons que vous avez recherché "le milieu". Dans ce cas, vous ne verrez que les résultats pour "le milieu", donc vous ne verrez aucun résultat contenant le mot "moyen" sans "le" avant.

Supposons que vous ayez ces deux phrases :

  1. Je suis au milieu.
  2. Tu n'aimes pas le collège.

Vous obtiendrez les éléments suivants renvoyés avec chaque type de recherche :

RequêteRecherche de baseRecherche en texte intégral
"le milieu"première1 et 2
"milieu"1 et 21 et 2

Un autre problème est celui d'ignorer des mots similaires. Avec la recherche de base, seules les correspondances exactes sont renvoyées. Cependant, avec la recherche plein texte, les mots similaires sont pris en compte. Pour tester, essayez de trouver des mots similaires comme "poney" et "poneys". Avec la recherche de base, si vous recherchez "poney", vous ne verrez pas les résultats contenant "poneys" - et vice versa.

Dites que vous avez ces deux phrases.

  1. je suis un poney.
  2. Vous n'aimez pas les poneys

Vous obtiendrez les éléments suivants renvoyés avec chaque type de recherche :

RequêteRecherche de baseRecherche en texte intégral
"poney"première1 et 2
"poneys"21 et 2

Avec la recherche en texte intégral, ces deux problèmes sont atténués. Cependant, gardez à l'esprit qu'en fonction de votre objectif, la recherche en texte intégral peut en fait diminuer la précision (qualité) et le rappel (quantité de résultats pertinents). En règle générale, la recherche de texte intégral est moins précise que la recherche de base, car la recherche de base donne des correspondances exactes. Cela dit, si vous effectuez une recherche dans de grands ensembles de données avec de gros blocs de texte, la recherche en texte intégral est préférable car elle est généralement beaucoup plus rapide.

La recherche en texte intégral est une technique de recherche avancée qui examine tous les mots de chaque document stocké en essayant de faire correspondre les critères de recherche. De plus, avec la recherche en texte intégral, vous pouvez utiliser des racines spécifiques à la langue sur les mots indexés. Par exemple, les mots "drives", "drove" et "driven" seront enregistrés sous le mot concept unique "drive". La radicalisation est le processus de réduction des mots à leur racine, leur base ou leur racine.

Il suffit de dire que la recherche plein texte n'est pas parfaite. Il est susceptible de récupérer de nombreux documents qui ne sont pas pertinents (faux positifs) pour la requête de recherche prévue. Cependant, certaines techniques basées sur des algorithmes bayésiens peuvent aider à réduire ces problèmes.

Pour profiter de la recherche plein texte de Postgres avec Django, ajoutez django.contrib.postgresà votre INSTALLED_APPSliste :

INSTALLED_APPS = [
    ...

    "django.contrib.postgres",  # new
]

Examinons ensuite deux exemples rapides de recherche plein texte, sur un seul champ et sur plusieurs champs.

Recherche de champ unique

Mettez à jour la get_querysetfonction sous la SearchResultsListfonction d'affichage comme ceci :

class SearchResultsList(ListView):
    model = Quote
    context_object_name = "quotes"
    template_name = "search.html"

    def get_queryset(self):
        query = self.request.GET.get("q")
        return Quote.objects.filter(quote__search=query)

Ici, nous configurons la recherche en texte intégral sur un seul champ - le champ de citation.

Page de recherche

Comme vous pouvez le voir, il prend en compte les mots similaires. Dans l'exemple ci-dessus, "poneys" et "poney" sont traités comme des mots similaires.

Recherche multi-champs

Pour effectuer une recherche sur plusieurs champs et sur des modèles associés, vous pouvez utiliser la SearchVectorclasse.

Encore une fois, mettez à jour SearchResultsList:

class SearchResultsList(ListView):
    model = Quote
    context_object_name = "quotes"
    template_name = "search.html"

    def get_queryset(self):
        query = self.request.GET.get("q")
        return Quote.objects.annotate(search=SearchVector("name", "quote")).filter(
            search=query
        )

Pour effectuer une recherche sur plusieurs champs, vous annotez le jeu de requêtes à l'aide d'un SearchVector. Le vecteur correspond aux données que vous recherchez, qui ont été converties en un formulaire facile à rechercher. Dans l'exemple ci-dessus, ces données sont les champs nameet de votre base de données.quote

Assurez-vous d'ajouter l'importation :

from django.contrib.postgres.search import SearchVector

Essayez quelques recherches.

Enracinement et classement

Dans cette section, vous combinerez plusieurs méthodes telles que SearchVector , SearchQuery et SearchRank pour produire une recherche très robuste qui utilise à la fois la radicalisation et le classement.

Encore une fois, le stemming est le processus de réduction des mots à leur forme de radical, de base ou de racine. Avec la racine, des mots comme "enfant" et "enfants" seront traités comme des mots similaires. Le classement, en revanche, nous permet de classer les résultats par pertinence.

Mise à jour SearchResultsList:

class SearchResultsList(ListView):
    model = Quote
    context_object_name = "quotes"
    template_name = "search.html"

    def get_queryset(self):
        query = self.request.GET.get("q")
        search_vector = SearchVector("name", "quote")
        search_query = SearchQuery(query)
        return (
            Quote.objects.annotate(
                search=search_vector, rank=SearchRank(search_vector, search_query)
            )
            .filter(search=search_query)
            .order_by("-rank")
        )

Qu'est-ce qu'il se passe ici?

  1. SearchVector- encore une fois, vous avez utilisé un vecteur de recherche pour effectuer une recherche dans plusieurs champs. Les données sont converties sous une autre forme puisque vous ne recherchez plus simplement le texte brut comme vous le faisiez lorsqu'il icontainsétait utilisé. Par conséquent, avec cela, vous pourrez facilement rechercher des pluriels. Par exemple, rechercher "flask" et "flasks" donnera la même recherche car ils sont, eh bien, fondamentalement la même chose.
  2. SearchQuery- traduit les mots qui nous sont fournis sous forme de requête à partir du formulaire, les fait passer par un algorithme de radicalisation, puis recherche des correspondances pour tous les termes résultants.
  3. SearchRank- permet de classer les résultats par pertinence. Il prend en compte la fréquence d'apparition des termes de la requête dans le document, la proximité des termes sur le document et l'importance de la partie du document où ils apparaissent.

Ajoutez les importations :

from django.contrib.postgres.search import SearchVector, SearchQuery, SearchRank

Page de recherche

Comparez les résultats de la recherche de base à ceux de la recherche en texte intégral. Il y a une nette différence. Dans la recherche de texte intégral, la requête avec les résultats les plus élevés est affichée en premier. C'est le pouvoir de SearchRank. La combinaison SearchVectorde , SearchQueryet SearchRankest un moyen rapide de produire une recherche beaucoup plus puissante et précise que la recherche de base.

Ajout de poids

La recherche en texte intégral nous donne la possibilité d'ajouter plus d'importance à certains champs de notre table dans la base de données par rapport à d'autres champs. Nous pouvons y parvenir en ajoutant des poids à nos requêtes.

Le poids doit être l'une des lettres suivantes D, C, B, A. Par défaut, ces poids font référence aux nombres 0,1, 0,2, 0,4 et 1,0, respectivement.

Mise à jour SearchResultsList:

class SearchResultsList(ListView):
    model = Quote
    context_object_name = "quotes"
    template_name = "search.html"

    def get_queryset(self):
        query = self.request.GET.get("q")
        search_vector = SearchVector("name", weight="B") + SearchVector(
            "quote", weight="A"
        )
        search_query = SearchQuery(query)
        return (
            Quote.objects.annotate(rank=SearchRank(search_vector, search_query))
            .filter(rank__gte=0.3)
            .order_by("-rank")
        )

Ici, vous avez ajouté des pondérations à l' SearchVectoraide des champs nameet . quoteDes pondérations de 0,4 et 1,0 ont été appliquées respectivement aux champs de nom et de citation. Par conséquent, les correspondances entre guillemets prévaudront sur les correspondances avec le contenu du nom. Enfin, vous avez filtré les résultats pour n'afficher que ceux qui sont supérieurs à 0,3.

Ajout d'un aperçu aux résultats de la recherche

Dans cette section, vous allez ajouter un petit aperçu de votre résultat de recherche via la méthode SearchHeadline . Cela mettra en surbrillance la requête de résultat de recherche.

Mettre à jour SearchResultsListà nouveau :

class SearchResultsList(ListView):
    model = Quote
    context_object_name = "quotes"
    template_name = "search.html"

    def get_queryset(self):
        query = self.request.GET.get("q")
        search_vector = SearchVector("name", "quote")
        search_query = SearchQuery(query)
        search_headline = SearchHeadline("quote", search_query)
        return Quote.objects.annotate(
            search=search_vector,
            rank=SearchRank(search_vector, search_query)
        ).annotate(headline=search_headline).filter(search=search_query).order_by("-rank")

Les SearchHeadlineprises dans le champ que vous souhaitez prévisualiser. Dans ce cas, ce sera le quotechamp avec la requête, qui sera en gras.

Assurez-vous d'ajouter l'importation :

from django.contrib.postgres.search import SearchVector, SearchQuery, SearchRank, SearchHeadline

Avant d'essayer certaines recherches, mettez à jour le fichier <li></li>in quotes/templates/search.html comme ceci :

<li>{{ quote.headline | safe }} - <b>By <i>{{ quote.name }}</i></b></li>

Désormais, au lieu d'afficher les citations comme vous le faisiez auparavant, seul un aperçu du champ de citation complet s'affiche avec la requête de recherche en surbrillance.

Amélioration des performances

La recherche en texte intégral est un processus intensif. Pour lutter contre le ralentissement des performances, vous pouvez :

  1. Enregistrez les vecteurs de recherche dans la base de données avec SearchVectorField . En d'autres termes, plutôt que de convertir les chaînes en vecteurs de recherche à la volée, nous allons créer un champ de base de données séparé contenant les vecteurs de recherche traités et mettre à jour le champ chaque fois qu'il y a une insertion ou une mise à jour des champs quoteou .name
  2. Créez un index de base de données , qui est une structure de données qui améliore la vitesse des processus de récupération de données sur une base de données. Cela accélère donc la requête. Postgres vous donne plusieurs index avec lesquels travailler qui pourraient être applicables à différentes situations. Le GinIndex est sans doute le plus populaire.

Pour en savoir plus sur les performances avec la recherche en texte intégral, consultez la section Performances de la documentation Django.

Champ vectoriel de recherche

Commencez par ajouter un nouveau champ SearchVectorField au modèleQuote dans quotes/models.py :

from django.contrib.postgres.search import SearchVectorField  # new
from django.db import models


class Quote(models.Model):
    name = models.CharField(max_length=250)
    quote = models.TextField(max_length=1000)
    search_vector = SearchVectorField(null=True)  # new

    def __str__(self):
        return self.quote

Créez le fichier de migration :

$ docker-compose exec web python manage.py makemigrations

Désormais, vous ne pouvez remplir ce champ que lorsque les objets quoteou nameexistent déjà dans la base de données. Ainsi, nous devons ajouter un déclencheur pour mettre à jour le search_vectorchamp chaque fois que les champs quoteou namesont mis à jour. Pour cela, créez un fichier de migration personnalisé dans "quotes/migrations" appelé 0003_search_vector_trigger.py :

from django.contrib.postgres.search import SearchVector
from django.db import migrations


def compute_search_vector(apps, schema_editor):
    Quote = apps.get_model("quotes", "Quote")
    Quote.objects.update(search_vector=SearchVector("name", "quote"))


class Migration(migrations.Migration):

    dependencies = [
        ("quotes", "0002_quote_search_vector"),
    ]

    operations = [
        migrations.RunSQL(
            sql="""
            CREATE TRIGGER search_vector_trigger
            BEFORE INSERT OR UPDATE OF name, quote, search_vector
            ON quotes_quote
            FOR EACH ROW EXECUTE PROCEDURE
            tsvector_update_trigger(
                search_vector, 'pg_catalog.english', name, quote
            );
            UPDATE quotes_quote SET search_vector = NULL;
            """,
            reverse_sql="""
            DROP TRIGGER IF EXISTS search_vector_trigger
            ON quotes_quote;
            """,
        ),
        migrations.RunPython(
            compute_search_vector, reverse_code=migrations.RunPython.noop
        ),
    ]

Selon la structure de votre projet, vous devrez peut-être mettre à jour le nom du fichier de migration précédent dans dependencies.

Appliquez les migrations :

$ docker-compose exec web python manage.py migrate

Pour utiliser le nouveau champ pour les recherches, procédez à la mise SearchResultsListà jour :

class SearchResultsList(ListView):
    model = Quote
    context_object_name = "quotes"
    template_name = "search.html"

    def get_queryset(self):
        query = self.request.GET.get("q")
        return Quote.objects.filter(search_vector=query)

Mettez à jour à nouveau le fichier <li></li>in quotes/templates/search.html :

<li>{{ quote.quote | safe }} - <b>By <i>{{ quote.name }}</i></b></li>

Indice

Enfin, configurons un index fonctionnel, GinIndex .

Mettez à jour le Quotemodèle :

from django.contrib.postgres.indexes import GinIndex  # new
from django.contrib.postgres.search import SearchVectorField
from django.db import models


class Quote(models.Model):
    name = models.CharField(max_length=250)
    quote = models.TextField(max_length=1000)
    search_vector = SearchVectorField(null=True)

    def __str__(self):
        return self.quote

    # new
    class Meta:
        indexes = [
            GinIndex(fields=["search_vector"]),
        ]

Créez et appliquez les migrations une dernière fois :

$ docker-compose exec web python manage.py makemigrations
$ docker-compose exec web python manage.py migrate

Testez-le.

Conclusion

Dans ce didacticiel, vous avez été guidé dans l'ajout d'une recherche de base et de texte intégral à une application Django. Nous avons également examiné comment optimiser la fonctionnalité de recherche en texte intégral en ajoutant un champ vectoriel de recherche et un index de base de données.

Récupérez le code complet du référentiel django-search .

Source :  https://testdrive.io

#django #postgre 

Ahebwe  Oscar

Ahebwe Oscar

1620177818

Django admin full Customization step by step

Welcome to my blog , hey everyone in this article you learn how to customize the Django app and view in the article you will know how to register  and unregister  models from the admin view how to add filtering how to add a custom input field, and a button that triggers an action on all objects and even how to change the look of your app and page using the Django suit package let’s get started.

Database

Custom Titles of Django Admin

Exclude in Django Admin

Fields in Django Admin

#django #create super user django #customize django admin dashboard #django admin #django admin custom field display #django admin customization #django admin full customization #django admin interface #django admin register all models #django customization

Ahebwe  Oscar

Ahebwe Oscar

1624131000

Basic and Full-text Search with Django and Postgres

Unlike relational databases, full-text search is not standardized. There are a number of open-source options like ElasticSearch, Solr, and Xapian. ElasticSearch is probably the most popular solution; however, it’s complicated to set up and maintain. Further, if you’re not taking advantage of some of the advanced features that ElasticSearch offers, you should stick with the full-text search capabilities that many relational (like Postgres, MySQL, SQLite) and non-relational databases (like MongoDB and CouchDB) offer. Postgres in particular is well-suited for full-text search. Django supports it out-of-the-box as well.

For the vast majority of your Django apps, you should, at the very least, start out with leveraging full-text search from Postgres before looking to a more powerful solution like ElasticSearch or Solr.

In this article, we’ll add basic and full-text search to a Django app with Postgres.

Objectives

By the end of this article, you should be able to:

  1. Set up basic search functionality in a Django app with the Q object
  2. Add full-text search to a Django app
  3. Sort full-text search results by relevance using stemming, ranking, and weighting

#basic and full-text search with django and postgres #django #search lookup #postgres #full-text search #postgres full text search

Navigating Between DOM Nodes in JavaScript

In the previous chapters you've learnt how to select individual elements on a web page. But there are many occasions where you need to access a child, parent or ancestor element. See the JavaScript DOM nodes chapter to understand the logical relationships between the nodes in a DOM tree.

DOM node provides several properties and methods that allow you to navigate or traverse through the tree structure of the DOM and make changes very easily. In the following section we will learn how to navigate up, down, and sideways in the DOM tree using JavaScript.

Accessing the Child Nodes

You can use the firstChild and lastChild properties of the DOM node to access the first and last direct child node of a node, respectively. If the node doesn't have any child element, it returns null.

Example

<div id="main">
    <h1 id="title">My Heading</h1>
    <p id="hint"><span>This is some text.</span></p>
</div>

<script>
var main = document.getElementById("main");
console.log(main.firstChild.nodeName); // Prints: #text

var hint = document.getElementById("hint");
console.log(hint.firstChild.nodeName); // Prints: SPAN
</script>

Note: The nodeName is a read-only property that returns the name of the current node as a string. For example, it returns the tag name for element node, #text for text node, #comment for comment node, #document for document node, and so on.

If you notice the above example, the nodeName of the first-child node of the main DIV element returns #text instead of H1. Because, whitespace such as spaces, tabs, newlines, etc. are valid characters and they form #text nodes and become a part of the DOM tree. Therefore, since the <div> tag contains a newline before the <h1> tag, so it will create a #text node.

To avoid the issue with firstChild and lastChild returning #text or #comment nodes, you could alternatively use the firstElementChild and lastElementChild properties to return only the first and last element node, respectively. But, it will not work in IE 9 and earlier.

Example

<div id="main">
    <h1 id="title">My Heading</h1>
    <p id="hint"><span>This is some text.</span></p>
</div>

<script>
var main = document.getElementById("main");
alert(main.firstElementChild.nodeName); // Outputs: H1
main.firstElementChild.style.color = "red";

var hint = document.getElementById("hint");
alert(hint.firstElementChild.nodeName); // Outputs: SPAN
hint.firstElementChild.style.color = "blue";
</script>

Similarly, you can use the childNodes property to access all child nodes of a given element, where the first child node is assigned index 0. Here's an example:

Example

<div id="main">
    <h1 id="title">My Heading</h1>
    <p id="hint"><span>This is some text.</span></p>
</div>

<script>
var main = document.getElementById("main");

// First check that the element has child nodes 
if(main.hasChildNodes()) {
    var nodes = main.childNodes;
    
    // Loop through node list and display node name
    for(var i = 0; i < nodes.length; i++) {
        alert(nodes[i].nodeName);
    }
}
</script>

The childNodes returns all child nodes, including non-element nodes like text and comment nodes. To get a collection of only elements, use children property instead.

Example

<div id="main">
    <h1 id="title">My Heading</h1>
    <p id="hint"><span>This is some text.</span></p>
</div>

<script>
var main = document.getElementById("main");

// First check that the element has child nodes 
if(main.hasChildNodes()) {
    var nodes = main.children;
    
    // Loop through node list and display node name
    for(var i = 0; i < nodes.length; i++) {
        alert(nodes[i].nodeName);
    }
}
</script>

#javascript 

Ahebwe  Oscar

Ahebwe Oscar

1620185280

How model queries work in Django

How model queries work in Django

Welcome to my blog, hey everyone in this article we are going to be working with queries in Django so for any web app that you build your going to want to write a query so you can retrieve information from your database so in this article I’ll be showing you all the different ways that you can write queries and it should cover about 90% of the cases that you’ll have when you’re writing your code the other 10% depend on your specific use case you may have to get more complicated but for the most part what I cover in this article should be able to help you so let’s start with the model that I have I’ve already created it.

**Read More : **How to make Chatbot in Python.

Read More : Django Admin Full Customization step by step

let’s just get into this diagram that I made so in here:

django queries aboutDescribe each parameter in Django querset

we’re making a simple query for the myModel table so we want to pull out all the information in the database so we have this variable which is gonna hold a return value and we have our myModel models so this is simply the myModel model name so whatever you named your model just make sure you specify that and we’re gonna access the objects attribute once we get that object’s attribute we can simply use the all method and this will return all the information in the database so we’re gonna start with all and then we will go into getting single items filtering that data and go to our command prompt.

Here and we’ll actually start making our queries from here to do this let’s just go ahead and run** Python manage.py shell** and I am in my project file so make sure you’re in there when you start and what this does is it gives us an interactive shell to actually start working with our data so this is a lot like the Python shell but because we did manage.py it allows us to do things a Django way and actually query our database now open up the command prompt and let’s go ahead and start making our first queries.

#django #django model queries #django orm #django queries #django query #model django query #model query #query with django