Django-fr

Forum

#1 06-01-2011 15:31:03

Rémycube
Membre
Inscription : 05-01-2011
Messages : 23

Fonction de recherche avancée (multicritère)

Bonjour à tous,

je souhaite créer une fonction de recherche sur mon site.
Mes données sont sous la forme d'un tableau du style:

ville  adresse  tel  nom ....
d1     d2         d3   d4
d5     d6         d7   d8

(avec d1 à d8 les différentes entrées dans ma bd)
Je souhaite pouvoir filtrer le tableau (ce qui reviens à rechercher) par ville ou/et nom ou/et autre....à l'aide d'un menu déroulant proposant toutes les villes de la bd, un autre avec les noms etc....
A chaque choix d'un critere, l'utilisateur appuye sur "rechercher" et la recherche s'affine.

Comment ráliser ca le plus simplement possible ?
J'ai regardé sur internet, on parle beaucoup de Haystack mais il n'existe aucune "demo" de ce que l'on peut faire avec et il n'a pas l'air tout simple à utiliser... De plus, n'est ce pas "trop" évolué pour réaliser ce que je cherche à faire ?

Merci pour vos réponses

Hors ligne

#2 06-01-2011 15:55:09

Jonathan Leroy - Inikup
Membre
Lieu : Nîmes, france
Inscription : 11-08-2010
Messages : 27
Site Web

Re : Fonction de recherche avancée (multicritère)

Le 06/01/11 15:31, Rémycube a écrit :
> Bonjour à tous,

Bonjour Rémy,

> je souhaite créer une fonction de recherche sur mon site.
> Mes données sont sous la forme d'un tableau du style:
>
> ville  adresse  tel  nom ....
> d1     d2         d3   d4
> d5     d6         d7   d8
>
> (avec d1 à d8 les différentes entrées dans ma bd)
> Je souhaite pouvoir filtrer le tableau (ce qui reviens à rechercher) par
> ville ou/et nom ou/et autre....

Le plus simple est d'utiliser filter() avec un dictionnaire: c'est très
pratique lorsque la requête à effectuer n'est pas connue à l'avance et
que peut dont pas être codée en dur.

Exemple (ici le Model utilisé est "Client", le nom entré "Martin" et la
ville "Paris"):

myquery = {}

# Une ville a été spécifiée pour la recherche.
if form.cleaned_data['ville']:
     myquery['ville'] = form.cleaned_data['ville']

# Un nom a été spécifié.
# Recherche sur une partie du nom. Ignore la case.
if form.cleaned_data['nom']:
     myquery['nom__icontains'] = form.cleaned_data['nom']

[...]

# Retourne tous les clients dont le nom contient "Martin" et habitant
Paris.
recherche = Client.objects.filter(**myquery)

C'est tout simple smile

Hors ligne

#3 06-01-2011 16:01:26

Rémycube
Membre
Inscription : 05-01-2011
Messages : 23

Re : Fonction de recherche avancée (multicritère)

ok merci pour ta réponse.
Je vais me pencher dessus (car je débute donc je n'assimile pas tout de suite)
Pour la partie html traitant cela je ne suis pas sur non plus de trouver comment l'écrire...
Je teste et je reviens !

Hors ligne

#4 07-01-2011 09:21:28

quinode
Membre
Lieu : Auvergne
Inscription : 14-10-2010
Messages : 89
Site Web

Re : Fonction de recherche avancée (multicritère)

Sinon, si jQuery ne t'effraie pas, tu peux aussi envoyer toutes les lignes en vrac avec django et utiliser un truc comme :
http://tomcoote.co.uk/wp-content/CodeBa … /demo.html
pour faire du filtrage instantané

Hors ligne

#5 07-01-2011 09:36:26

Rémycube
Membre
Inscription : 05-01-2011
Messages : 23

Re : Fonction de recherche avancée (multicritère)

Ha oui c'est trop bien ca !
Et c'est possible de combiner recherche instantannée et menu déroulants ? (car j'aurai des colonnes ou il n'y aura que 2 ou 3 possibilités...

Le code donné pour la recherche instantanné je l'écrit dans quel fichier ? comment dois je l'utiliser ?

Merci beaucoup

Hors ligne

#6 07-01-2011 13:09:30

Rémycube
Membre
Inscription : 05-01-2011
Messages : 23

Re : Fonction de recherche avancée (multicritère)

Alors en fait la première proposition, tout codé en "python/Django", je préfère !

Peux tu m'en dire plus Jonathan ?

Que dois je mettre dans les crochets de "myquery = {}"

Que dois je mettre dans mon html pour exloiter le résultat et ne pas afficher seulement le résultat mais bien tooutes les lignes ou il figure ?

Merci pour votre aide
Rémy

PS: désolé si j'en demande trop

Hors ligne

#7 07-01-2011 15:54:18

Jonathan Leroy - Inikup
Membre
Lieu : Nîmes, france
Inscription : 11-08-2010
Messages : 27
Site Web

Re : Fonction de recherche avancée (multicritère)

Le 07/01/11 13:09, Rémycube a écrit :
> Alors en fait la première proposition, tout codé en "python/Django", je
> préfère !
>
> Peux tu m'en dire plus Jonathan ?
>
> Que dois je mettre dans les crochets de "myquery = {}"

Rien, il s'agît juste de déclarer la variable.
On ne peut pas créer directement le dictionnaire:
myquery = {
    'champs': valeur
}

.. puisqu'il faut spécifier uniquement les critères de recherche
sélectionnés par l'utilisateur. On crée donc le dictionnaire en fonction
des données entrées par le client:

# Crée un dictionnaire vide.
mydict = {}
[...]
# Crée une valeur dans le dictionnaire.
mydict['champs'] = 'valeur'


Voir: http://www.dsimb.inserm.fr/~fuchs/python/python-node11.html
Ce cours de Python est clair et très accessible.

> Que dois je mettre dans mon html pour exloiter le résultat et ne pas
> afficher seulement le résultat mais bien tooutes les lignes ou il figure ?

Comment fais-tu actuellement ? Si tu utilise une boucle {% for %} dans
le template, tu n'as rien à modifier normalement.

Hors ligne

#8 07-01-2011 17:24:23

Rémycube
Membre
Inscription : 05-01-2011
Messages : 23

Re : Fonction de recherche avancée (multicritère)

Meri pour ces précisions et pour le lien, j'y vois un peu plus clair.
J'ai désormais deux autres questions:

Quelle est la différence avec "ma" recherche actuelle écrite comme suit:

views.py
def recherche(request):
    query = request.GET.get('q', '')
    if query:
        qset = (
            Q(titre__icontains=query) |
            Q(proprietaire__nom__icontains=query) |
        )
        results = Lieu.objects.filter(qset).distinct()
    else:
        results = []
    return render_to_response("lieux/recherche.html", {"results": results,"query": query})
html:
<h1>Search</h1>
          <form action="." method="GET"> 
                <label for="q">Search: </label>
                <input type="text" name="q" value="{{ query|escape }}">
                <input type="submit" value="Search">
          </form>

          {% if query %}
                <h2>Results for "{{ query|escape }}":</h2>
                {% if results %}
                  <ul>
                  {% for lieu in results %}
                        <li>{{ lieu|escape }}</l1>
                  {% endfor %}
                  </ul>
                {% else %}
                  <p>No entries found</p>
                {% endif %}
          {% endif %}

et, sais tu pourquoi les résultats donnés par ma rcherche actuelle me donnent seulement 2 champs de ma table "lieu" en guise résultat et pas toutes les valeurs de la table ou bien seulement celle que j'ai recherché...comment faire pour n'afficher que les champs que je souhaite afficher ?

Merci beaucoup

Hors ligne

#9 08-01-2011 00:53:13

Jonathan Leroy - Inikup
Membre
Lieu : Nîmes, france
Inscription : 11-08-2010
Messages : 27
Site Web

Re : Fonction de recherche avancée (multicritère)

Le 07/01/11 17:24, Rémycube a écrit :
> Quelle est la différence avec "ma" recherche actuelle écrite comme suit:
> [...]

La méthode que tu utilise ne permet pas de faire une recherche "fine".
Par exemple si q = "martin", cela va retourner tous les enregistrements
dont le titre OU le nom du propriétaire approchent "martin". Il n'est
donc pas possible de filtrer par champs.

> et, sais tu pourquoi les résultats donnés par ma rcherche actuelle me
> donnent seulement 2 champs de ma table "lieu" en guise résultat et pas
> toutes les valeurs de la table ou bien seulement celle que j'ai
> recherché...

Essaie de supprimer le "distinct()" à la fin de ta requête.

> comment faire pour n'afficher que les champs que je souhaite
> afficher ?

Pas compris la question smile

Hors ligne

#10 08-01-2011 14:10:43

Rémycube
Membre
Inscription : 05-01-2011
Messages : 23

Re : Fonction de recherche avancée (multicritère)

Bonjour bonjour !
C'est encore moi...je crois que je suis en train de me noyer...j'ai fait de multiples essais toute la matinée et j'ai essayé de trouver des réponses sur internet mais bon...rien de sensationnel.

J'arrive à effectuer une recherche...enfin, je crois...mais je n'ai aucun résultat...je pense que tout ce que j'ai écrit est plein de bétises alors voici mon code:
[view.py]
def recherche2(request):
    mondictionnaire = {} # Cree un dictionnaire vide.
    form = LieuForm(request.GET)
    if form.is_valid():
        titre = form.cleaned_data['titre']
        proprietaire = form.cleaned_data['proprietaire']

        if form.cleaned_data['titre']:
            mondictionnaire['titre'] = form.cleaned_data['titre'] # Cree une valeur dans le dictionnaire.

        if form.cleaned_data['nom']:
            mondictionnaire['proprietaire.nom__icontains'] = form.cleaned_data['proprietaire.nom']
#proprétaire étant un models.ForeignKey de la table "lieu" mais est ce correct ?

# Retourne tous les lieux dont le titre contient xxxx et le propriétaire est xxxx.
        recherche2 = Lieu.objects.filter(**mondictionnaire)
    else:
        recherche2 = []
        return render_to_response("lieux/recherche2.html", {"recherche2": recherche2,"mondictionnaire": mondictionnaire})

[html]
          <h1>Search</h1>
          <form action="." method="GET">
                <label for="titre">Entre ta recherche: </label>
                <input type="text" name="titre" value="{{ query|escape }}">
                <input type="submit" value="Recherche">
          </form>
          {% if mondictionnaire %}
                <h2>Results for "{{ query|escape }}":</h2>

                {% if recherche2 %}
                  <ul>
                  {% for lieu in recherche2 %}
                        <li>{{ lieu }}</l1>
                  {% endfor %}
                  </ul>
                {% else %}
                  <p>aucune entrée trouvée</p>
                {% endif %}

Quand à ma question qui je l'avoue était peu claire la revoici:
j'ai supprimé le "distinct()" et cela n'a rien changé...
Ce que je veux c'est afficher en résultat chacun des champs séparéments...mais j'ai trouvé la solution. ({{lieu.monchamp}})

Merci d'avance à mon relecteur

Hors ligne

#11 08-01-2011 20:01:53

Jonathan Leroy - Inikup
Membre
Lieu : Nîmes, france
Inscription : 11-08-2010
Messages : 27
Site Web

Re : Fonction de recherche avancée (multicritère)

Le 08/01/11 14:10, Rémycube a écrit :
>      form = LieuForm(request.GET)

request.POST plutôt, non ?

>          titre = form.cleaned_data['titre']
>          proprietaire = form.cleaned_data['proprietaire']

Ces variables ne sont pas utilisés, je pense que tu peux les supprimer.

>          if form.cleaned_data['titre']:
>              mondictionnaire['titre'] = form.cleaned_data['titre']

Si tu indique simplement le nom du champs comme clé dans le
dictionnaire, la valeur recherchée devra correspondre strictement à la
valeur du champs dans ta table.

Si tu as par ex la table suivante:

| Nom       | Prénom |
| Martin    | Anne   |
| MARTIN    | Bob    |
| martini   | Jean   |

...une recherche sur le nom "martin" ne reverra rien.
Il est donc préférable d'ajouter '__icontains' pour les champs de
formulaire dont la valeur peut être modifiée par l'utilisateur (input
texte, textarea...).

> #proprétaire étant un models.ForeignKey de la table "lieu" mais est ce
> correct ?

Non, il faut utiliser '__' et non '.'. Attention form.cleaned_data
correspond aux champs de ton formulaire:

mondictionnaire['proprietaire__nom__icontains'] =
form.cleaned_data['proprietaire__nom']

>          return render_to_response("lieux/recherche2.html", {"recherche2":
> recherche2,"mondictionnaire": mondictionnaire})

La variable "mondictionnaire" n'a pas à être utilisée dans le template,
à priori (voir plus bas). Tu peux donc l'envever du render_to_response.
Par contre "form" doit y être ajouté (voir:
http://docs.djangoproject.com/en/dev/topics/forms/)

>            <form action="." method="GET">

<form action="" method="POST">

...à moins que tu es une raison particulière d'utiliser GET, mais je ne
pense pas smile

"action" vide poste le formulaire sur la page courante.

>                  <label for="titre">Entre ta recherche:</label>
>                  <input type="text" name="titre" value="{{ query|escape
> }}">

Tout ça doit être remplacé par:

{{ form.as_p }}

Voir le lien précédent, section "Displaying a form using a template".

>            {% if mondictionnaire %}
>                  <h2>Results for "{{ query|escape }}":</h2>
>
>                  {% if recherche2 %}
>                    <ul>
>                    {% for lieu in recherche2 %}
>                          <li>{{ lieu }}</l1>
>                    {% endfor %}
>                    </ul>
>                  {% else %}
>                    <p>aucune entrée trouvée</p>
>                  {% endif %}

Plus simple:

<table>
    <tr>
       <th>Nom</th>
       <th>Ville</th>
    </tr>
    {% for result in recherche2 %}
       <tr>
          <td>{{ result.proprietaire.nom }}</td>
          <td>{{ result.ville }}</td>
       </tr>
    {% empty %}
       <tr>
          <td colspan="2">Aucun r&eacute;sultat.</td>
       </tr>
    {% endfor %}
</table>

L'affichage dans une table sera plus clair. La balise {% empty %}
remplace ton {% if %}: son contenu sera affiché si aucun résultat n'a
été trouvé.

Hors ligne

#12 15-01-2011 18:34:58

Rémycube
Membre
Inscription : 05-01-2011
Messages : 23

Re : Fonction de recherche avancée (multicritère)

Merci pour toutes ces précisions, cela m'a bien aidé et je suis désormais au point.
Rémy

Hors ligne

Pied de page des forums