Jak obsługiwać request.GET z wieloma zmiennymi dla tego samego parametru w Django

82

W widoku Django możesz uzyskać dostęp do request.GET['variablename'], więc w swoim widoku możesz zrobić coś takiego:

myvar = request.GET['myvar']

Rzeczywisty request.GET['myvar']typ obiektu to:

<class 'django.http.QueryDict'>

Teraz, jeśli chcesz przekazać wiele zmiennych o tej samej nazwie parametru, tj .:

http://example.com/blah/?myvar=123&myvar=567

Chciałbyś listzwrócić pythona dla parametru myvar, a następnie zrób coś takiego:

for var in request.GET['myvar']:
    print(var)

Jednak jeśli spróbujesz uzyskać tylko ostatnią wartość przekazaną w adresie URL, tj. W powyższym przykładzie otrzymasz 567 , a wynik w powłoce będzie:

5
6
7

Jednak kiedy robisz wydruk request.GET, wygląda na to, że ma listie:

<QueryDict: {u'myvar': [u'123', u'567']}>

OK Aktualizacja: Jest przeznaczony do zwracania ostatniej wartości, moim przypadkiem użycia jest lista.

z dokumentacji django:

QueryDict. getitem (klucz) Zwraca wartość dla podanego klucza. Jeśli klucz ma więcej niż jedną wartość, getitem () zwraca ostatnią wartość. Podnosi django.utils.datastructures.MultiValueDictKeyError, jeśli klucz nie istnieje. (Jest to podklasa standardowego KeyError w Pythonie, więc możesz trzymać się wychwytywania KeyError

QueryDict.getlist (klucz) Zwraca dane z żądanym kluczem, jako listę Pythona. Zwraca pustą listę, jeśli klucz nie istnieje. Na pewno zwróci jakąś listę.

Aktualizacja: Jeśli ktoś wie, dlaczego deweloperzy django to zrobili, daj mi znać, wydaje się sprzeczne z intuicją, aby wyświetlić listę i nie zachowuje się jak jedna. Niezbyt pytoniczne!

ismail
źródło
4
Myślę, że rozumowanie jest takie, że powinieneś wiedzieć, czy oczekiwać listy, czy indywidualnej wartości. QueryDict.getitem nie powinien czasami zwracać listy, innym razem pojedynczy element - wtedy każdy musiałby zawsze sprawdzić typ zwracanego elementu, aby poprawnie go obsłużyć.
jgiles

Odpowiedzi:

181

Chcesz funkcji getlist () obiektu GET:

request.GET.getlist('myvar')
AndrewF
źródło
10
Może być konieczne dodanie „[]” na końcu nazwy zmiennej, jeśli używasz jquery do wysyłania elementów z powrotem.
Danny Staple,
2
Wiedziałem o getlist, ale „[]” mnie zrzuciło. Mam też przyjaciela o imieniu Andy Staple i przez sekundę myślałem, że wie więcej o Django, niż przypuszczałem. To też mnie rzuciło.
kungphu
1
To musi być umieszczone w całej dokumentacji Django, dokumentacji Django Rest Framework i odwrotnie na moim czole. To naprawdę zaskoczyło mnie
Anthony Manning-Franklin
Wydaje się, że Django rodzaj upuścił piłkę na jednym, nie wiem, czy zamierzony
NaturalBornCamper
1

Innym rozwiązaniem jest utworzenie kopii obiektu żądania ... Zwykle nie można iterować po obiekcie request.GET lub request.POST, ale można na kopii wykonać takie operacje:

res_set = request.GET.copy()
for item in res_set['myvar']:
    item
...
Upadły anioł
źródło
2
Jesteś pewny? nie zmienia to w żaden sposób zachowania QueryDict w moim przypadku. właśnie dostaję kolejny QueryDict z tym samym „ograniczeniem”
orzechy
0

Podczas tworzenia ciągu zapytania z obiektu QueryDict, który zawiera wiele wartości dla tego samego parametru (np. Zestaw pól wyboru), użyj metody urlencode ():

Na przykład musiałem uzyskać przychodzące zapytanie, usunąć parametr i zwrócić zaktualizowany ciąg zapytania do strony wynikowej.

# Obtain a mutable copy of the original string
original_query = request.GET.copy()

# remove an undesired parameter
if 'page' in original_query:
    del original_query['page']

Teraz, jeśli pierwotne zapytanie ma wiele wartości dla tego samego parametru, na przykład: {... 'track_id': ['1', '2'], ...} podczas używania kodu utracisz pierwszy element ciągu zapytania lubić:

new_query = urllib.parse.urlencode(original_query)

prowadzi do...

...&track_id=2&...

Można jednak użyć metody urlencode klasy QueryDict, aby poprawnie uwzględnić wiele wartości:

new_query = original_query.urlencode()

który produkuje ...

...&track_id=1&track_id=2&...
Tomislav Urban
źródło