Question

J'ai une vue dans django qui peut accepter un certain nombre de paramètres de filtre différents, mais ils sont tous optionnels.Si j'ai 6 filtres optionnels, dois-je vraiment écrire des URL pour chaque combinaison des 6 ou y a-t-il un moyen de définir quelles parties de l'URL sont facultatives?

Pour vous donner un exemple avec seulement 2 filtres, je pourrais avoir toutes ces possibilités d'URL:

/<city>/<state>/
/<city>/<state>/radius/<miles>/
/<city>/<state>/company/<company-name>/
/<city>/<state>/radius/<miles>/company/<company-name>/
/<city>/<state>/company/<company-name>/radius/<miles>/

Toutes ces URL pointent vers la même vue et les seuls paramètres requis sont la ville et l'état.Avec 6 filtres, cela devient ingérable.

Quelle est la meilleure façon de faire ce que je veux accomplir?

Était-ce utile?

La solution

Une méthode serait de faire en sorte que l'expression régulière lise tous les filtres donnés comme une seule chaîne, puis de les diviser en valeurs individuelles dans la vue.

J'ai trouvé l'URL suivante:

(r'^(?P<city>[^/]+)/(?P<state>[^/]+)(?P<filters>(?:/[^/]+/[^/]+)*)/?$',
 'views.my_view'),

Il est facile de faire correspondre la ville et l'état requis. La partie filters est un peu plus compliquée. La partie interne - (?:/[^/]+/[^/]+)* - correspond aux filtres donnés sous la forme /name/value. Cependant, le quantificateur * (comme tous les quantificateurs d'expression régulière Python) ne renvoie que la dernière correspondance trouvée - donc si l'URL était /radius/80/company/mycompany/, seul company/mycompany serait stocké. Au lieu de cela, nous lui disons de ne pas capturer les valeurs individuelles (le ?: au début), et de le placer dans un bloc de capture qui stockera toutes les valeurs de filtre dans une seule chaîne.

La logique de vue est assez simple. Notez que l'expression régulière ne correspondra qu'à des paires de filtres - donc /company/mycompany/radius/ ne sera pas mis en correspondance. Cela signifie que nous pouvons supposer que nous avons des paires de valeurs. La vue avec laquelle j'ai testé ceci est la suivante:

def my_view(request, city, state, filters):
    # Split into a list ['name', 'value', 'name', 'value']. Note we remove the
    # first character of the string as it will be a slash.
    split = filters[1:].split('/')

    # Map into a dictionary {'name': 'value', 'name': 'value'}.
    filters = dict(zip(split[::2], split[1::2]))

    # Get the values you want - the second parameter is the default if none was
    # given in the URL. Note all entries in the dictionary are strings at this
    # point, so you will have to convert to the appropriate types if desired.
    radius = filters.get('radius', None)
    company = filters.get('company', None)

    # Then use the values as desired in your view.
    context = {
        'city': city,
        'state': state,
        'radius': radius,
        'company': company,
    }
    return render_to_response('my_view.html', context)

Deux choses à noter à ce sujet. Premièrement, il autorise les entrées de filtre inconnues dans votre vue. Par exemple, /fakefilter/somevalue est valide. Le code de vue ci-dessus les ignore, mais vous souhaitez probablement signaler une erreur à l'utilisateur. Si tel est le cas, modifiez le code pour obtenir les valeurs

radius = filters.pop('radius', None)
company = filters.pop('company', None)

Toutes les entrées restantes dans le dictionnaire filters sont des valeurs inconnues dont vous pouvez vous plaindre.

Deuxièmement, si l'utilisateur répète un filtre, la dernière valeur sera utilisée. Par exemple, /radius/80/radius/50 définira le rayon sur 50. Si vous voulez le détecter, vous devrez parcourir la liste des valeurs avant qu'elle ne soit convertie en dictionnaire:

given = set()
for name in split[::2]:
    if name in given:
        # Repeated entry, complain to user or something.
    else:
        given.add(name)

Autres conseils

C'est absolument le cas d'utilisation des paramètres GET.Votre urlconf doit simplement être /city/state/, puis les différents filtres se terminent par des variables GET:

/city/state/?radius=5&company=google

À présent, à votre avis, vous acceptez city et state comme paramètres normaux, mais tout le reste est stocké dans le request.GET QueryDict.

Vous pouvez également créer une seule URL (qui ne vérifie que le début du chemin, cela devrait être le même) pointant vers votre vue, puis analyser request.path dans votre vue. D'un autre côté, si vous avez vraiment beaucoup de paramètres de filtrage optionnels dans diverses combinaisons, la meilleure solution est très souvent de faire le filtrage via GET-parameters, surtout si les URL utilisées pour le filtrage n'ont pas besoin d'être optimisées pour aucun moteur de recherche...

Essayez d'utiliser quelque chose comme ça dans votre urls.py:

url(r'^(?P<city>[^/]+)/(?P<state>[^/]+)/(radius/(?P<miles>[^/]+)/|company/(?P<company_name>[^/]+)/)*$', 'view')
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top