Domanda

Ho una vista in Django che può accettare una serie di parametri di filtro diversi, ma sono tutti opzionali. Se ho 6 filtri opzionali, devo davvero scrivere URL per ogni combinazione del 6 o c'è un modo per definire quali parti dell'URL sono opzionali?

Per darti un esempio con solo 2 filtri, potrei avere tutte queste possibilità di 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>/

Tutti questi URL indicano la stessa visione e gli unici parametri richiesti sono la città e lo stato. Con 6 filtri, questo diventa ingestibile.

Qual è il modo migliore per fare ciò che voglio ottenere?

È stato utile?

Soluzione

Un metodo sarebbe quello di rendere l'espressione regolare leggere tutti i filtri indicati come una singola stringa, quindi dividerli in singoli valori nella vista.

Mi è venuto in mente il seguente URL:

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

Abbinare la città e lo stato richiesti è facile. Il filters La parte è un po 'più complicata. La parte interna - (?:/[^/]+/[^/]+)* - corrisponde ai filtri indicati nel modulo /name/value. in ogni caso, il * quantificatore (come tutti i quantificatori di espressione regolare di Python) restituisce solo l'ultima partita trovata, quindi se l'URL era /radius/80/company/mycompany/ solo company/mycompany verrebbe immagazzinato. Invece, gli diciamo di non catturare i singoli valori (il ?: All'inizio) e mettilo all'interno di un blocco di cattura che memorizzerà tutti i valori di filtro come una singola stringa.

La logica di visualizzazione è abbastanza semplice. Si noti che l'espressione regolare corrisponderà solo alle coppie di filtri - quindi /company/mycompany/radius/ non sarà abbinato. Ciò significa che possiamo tranquillamente supporre che abbiamo coppie di valori. La vista con cui ho testato è la seguente:

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)

Due cose da notare su questo. Innanzitutto, consente voci di filtro sconosciute nella tua vista. Per esempio, /fakefilter/somevalue è valido. Il codice di visualizzazione sopra li ignora, ma probabilmente si desidera segnalare un errore all'utente. In tal caso, modifica il codice ottenendo i valori su

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

Eventuali voci rimaste in filters Il dizionario sono valori sconosciuti su cui puoi lamentarti.

In secondo luogo, se l'utente ripete un filtro, verrà utilizzato l'ultimo valore. Per esempio, /radius/80/radius/50 imposterà il raggio su 50. Se si desidera rilevare questo, dovrai scansionare l'elenco dei valori prima che venga convertito in un dizionario:

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

Altri suggerimenti

Questo è assolutamente il caso d'uso per i parametri GET. Il tuo URLConf dovrebbe essere solo /city/state/, quindi i vari filtri vanno alla fine come Ottieni variabili:

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

Ora, a tuo avviso, accetti city e state come parametri normali, ma tutto il resto è archiviato in request.GET Querydict.

Potresti anche fare un solo URL (che controlla solo l'inizio del percorso, che dovrebbe essere lo stesso) indicando il tuo punto di vista e poi analizza request.path a tuo avviso. D'altra parte, se hai davvero molti parametri di filtro opzionali in varie combinazioni, la soluzione migliore è molto spesso fare il filtro tramite GET-Parameters, specialmente se gli URL utilizzati per il filtraggio non devono essere ottimizzati per qualsiasi motore di ricerca ...

Prova a usare qualcosa del genere nei tuoi urls.py:

url(r'^(?P<city>[^/]+)/(?P<state>[^/]+)/(radius/(?P<miles>[^/]+)/|company/(?P<company_name>[^/]+)/)*$', 'view')
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top