Включение строки запроса в вызове reverse () django.core.urlresolvers
Я пытаюсь отменить именованный URL и включить в него строку запроса. По сути, я изменил функцию входа в систему, и я хочу отправить ?next=
в этом.
Вот что я делаю сейчас: reverse(name) + "?next=" + reverse(redirect)
Вот что я хотел бы сделать: reverse(name, kwargs = { 'next':reverse(redirect) } )
Мой URL для страницы входа (просто в качестве примера) выглядит следующим образом:
url(r'^login/', custom_login, name = 'login'),
Итак, как мне изменить всю эту вещь (или назвать ее), чтобы включить следующую, не объединяя ее? В лучшем случае это кажется сомнительным решением.
6 ответов
Вы не можете записывать GET-параметры в URL-адресах, поэтому ваш метод правильный.
Я обычно предпочитаю форматирование строк, но это одно и то же."%s?next=%s" % (reverse(name), reverse(redirect))
http://docs.djangoproject.com/en/dev/topics/http/urls/
URLconf выполняет поиск по запрошенному URL как обычная строка Python. Это не включает параметры GET или POST или имя домена.
Я просто сделал свою собственную функцию полезности, подобную той, которая была задана в вопросе:
from django.utils.http import urlencode
def my_reverse(viewname, kwargs=None, query_kwargs=None):
"""
Custom reverse to add a query string after the url
Example usage:
url = my_reverse('my_test_url', kwargs={'pk': object.id}, query_kwargs={'next': reverse('home')})
"""
url = reverse(viewname, kwargs=kwargs)
if query_kwargs:
return u'%s?%s' % (url, urlencode(query_kwargs))
return url
Я думаю, что лучше обернуть обратный метод Джанго, чтобы раскрыть этот API. Вот простой код для этого:
from django.core.urlresolvers import reverse as django_reverse
def reverse(viewname, urlconf=None, args=None, kwargs=None, prefix=None, current_app=None):
"""
Wrapper of django.core.urlresolvers.reverse that attaches arguments in kwargs as query string parameters
"""
if kwargs:
return '%s?%s' % (django_reverse(viewname, urlconf, args, None, prefix, current_app), \
'&'.join(['%s=%s' % (k,v) for k,v in kwargs.items()]))
else:
return django_reverse(viewname, urlconf, args, kwargs, prefix, current_app)
Поместите этот код в какую-нибудь утилиту или обычное приложение, которое зависит только от Django, и вместо импорта django.core.urlresolvers.reverse просто импортируйте myproject.myutils.urlresolvers.reverse.
Я был обеспокоен тем же вопросом и нашел эту ссылку. Видимо, ваше решение совсем не плохо спроектировано. Согласно обсуждению билета, Django не будет предоставлять эту функциональность.
Вы можете использовать urlobject или furl.
Другой способ - использовать вашу собственную функцию, чтобы сделать это более понятным способом. Вот тот, который заявлен в обсуждении
from django.utils.http import urlencode
from django.core.urlresolvers import reverse as original_reverse
def reverse(*args, **kwargs):
get = kwargs.pop('get', {})
url = original_reverse(*args, **kwargs)
if get:
url += '?' + urlencode(get)
return url
В случае вопроса это можно использовать следующим образом
from [myfunctions] import reverse
...
reverse('login', get={next: reverse(redirect)})
Чтобы запрос оставался необязательным, вы можете обернуть функцию реверса Django своей собственной функцией, которая также обрабатывает запрос, что позволяет правильно обрабатывать функцию реверса.
Создание правильного запроса - обратите внимание, что query_kwargs
не является обязательным, поэтому вам не нужно отправлять его
# from a views in views.py
def sendingView(request, truckID, fleetSlug):
#in the GET or POST
return HttpResponseRedirect(reverse('subAppName:urlViewName',
kwargs={'anyPassedKawrgs':goHere,…},
query_kwargs={'queries': goHere}
))
# from a template in specificTemplate.html
<a class="nav-link" href="{% url 'subAppName:urlViewName' kwarg1=kwarg1 kwarg2=kwarg2 … query_kwargs={'dict':here} %}">Link</a>
#from a model in models.py
class Truck(models.Model):
name = models.CharField(…)
def get_absolute_wi_url(self):
return reverse('subAppName:urlViewName', kwargs={'kwarg1':kwarg1,'kwarg2':kwarg2})
В utils.py
файл (на основе документов) для (1.11 и выше?)
-myMainApp
-apps
-static
...
-utils
-__init__.py
-utils.py
from django.core.urlresolvers import reverse as django_reverse
def reverse(viewname, urlconf=None, args=None, kwargs=None, current_app=None, query_kwargs=None):
"""
Wrapper of django.core.urlresolvers.reverse that attaches arguments in kwargs as query string parameters
"""
if query_kwargs:
return '%s?%s' % (django_reverse(viewname, urlconf, args, kwargs, current_app), \
'&'.join(['%s=%s' % (k,v) for k,v in query_kwargs.items()]))
else:
return django_reverse(viewname, urlconf, args, kwargs, current_app)
В URL-адресах конф urls.py
app_name = 'subAppName'
urlpatterns = [
url(r'^(?P<kawrg1>[a-zA-Z0-9]+)/(?P<kawrg2>[a-zA-Z0-9]+)/path/to/here/$', views.urlViewFunctionName, name='urlViewName'),
И получение доступа к запросу
#in a view
def urlViewFunctionName(request, kwarg1, kwarg2):
if request.GET.get('submittedData'):
submittedQuery = request.GET.get('submittedData')
else:
submittedQuery = None
return render(request, 'trucks/weeklyInspectionSuccess.html', {
'truck': truck,
'submittedQuery': submittedQuery
})
#in a template
<div class="container">
Success for {{kwarg1}}
{{submittedQuery}}
</div>
Принимая идею @chrisFrisina, надежное решение:
from django.core import urlresolvers
from urllib.parse import urlencode
def reverse(viewname, urlconf=None, args=None, kwargs=None, current_app=None, query_kwargs=None):
base = urlresolvers.reverse(viewname, urlconf, args, kwargs, current_app)
if query_kwargs:
query = urlencode(query_kwargs)
return f'{base}?{query}'
else:
return base