38

http://example.com/depict?smiles=CO&width=200&height=200のような URL があります(その他のオプションの引数がいくつかあります)

私のurls.pyには以下が含まれています:

urlpatterns = patterns('',
    (r'^$', 'cansmi.index'),
    (r'^cansmi$', 'cansmi.cansmi'),
    url(r'^depict$', cyclops.django.depict, name="cyclops-depict"),

その URL にアクセスして、作成された 200x200 の PNG を取得できるので、その部分が機能することがわかります。

「cansmi.cansmi」応答からのテンプレートで、いくつかのクエリ パラメータを指定して、名前付きテンプレート「cyclops-depict」の URL を作成したいと考えています。できると思った

{% url サイクロプス描写の笑顔=input_smiles 幅=200 高さ=200 %}

「input_smiles」は、フォーム送信によるテンプレートへの入力です。この場合は「CO」という文字列で、一番上のような URL が作成されると思いました。

このテンプレートは TemplateSyntaxError で失敗します:

レンダリング中に例外をキャッチしました: 引数 '()' およびキーワード引数 '{'smiles': u'CO', 'height': 200, 'width': 200}' を持つ 'cyclops-depict' のリバースが見つかりません。

これは、ここ StackOverflow と他の場所の両方で、かなり一般的なエラー メッセージです。私が見つけたすべてのケースで、人々は URL パスの正規表現でパラメーターを使用してそれらを使用していましたが、パラメーターがクエリに入る場合はそうではありません。

つまり、私のやり方が間違っているということです。どうすれば正しくできますか?つまり、テンプレート内の何かを使用して、パスとクエリ パラメーターを含む完全な URL を作成したいと考えています。

参考のため、

% python manage.py shell
Python 2.6.1 (r261:67515, Feb 11 2010, 00:51:29) 
[GCC 4.2.1 (Apple Inc. build 5646)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from django.core.urlresolvers import reverse
>>> reverse("cyclops-depict", kwargs=dict())
'/depict'
>>> reverse("cyclops-depict", kwargs=dict(smiles="CO"))
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/Library/Python/2.6/site-packages/django/core/urlresolvers.py", line 356, in reverse
    *args, **kwargs)))
  File "/Library/Python/2.6/site-packages/django/core/urlresolvers.py", line 302, in reverse
    "arguments '%s' not found." % (lookup_view_s, args, kwargs))
NoReverseMatch: Reverse for 'cyclops-depict' with arguments '()' and keyword arguments '{'smiles': 'CO'}' not found.
4

6 に答える 6

55

いくつかの回答で示唆されているように、文字列を連結してクエリ文字列を使用して URL を作成することは、文字列を連結して SQL クエリを作成するのと同じくらい悪い考えです。ユーザーが提供する (信頼されていない) 入力では、複雑で洗練されておらず、特に危険です。残念ながら、Django はクエリ パラメータを逆関数に渡す簡単な方法を提供していません。

ただし、 Python 標準のurllibは、必要なクエリ文字列エンコーディング機能を提供します。

私のアプリケーションでは、ヘルパー関数を作成しました:

def url_with_querystring(path, **kwargs):
    return path + '?' + urllib.urlencode(kwargs) # for Python 3, use urllib.parse.urlencode instead

次に、ビューで次のように呼び出します。

quick_add_order_url = url_with_querystring(reverse(order_add),
    responsible=employee.id, scheduled_for=datetime.date.today(),
    subject='hello world!')
# http://localhost/myapp/order/add/?responsible=5&
#     scheduled_for=2011-03-17&subject=hello+world%21

スペースや感嘆符などの特殊文字の適切なエンコードに注意してください!

于 2011-03-17T16:05:28.253 に答える
20

正規表現にはプレースホルダーがありません (そのため、NoReverseMatch を取得しています):

url(r'^depict$', cyclops.django.depict, name="cyclops-depict"),

次のようにできます。

{% url cyclops-depict %}?smiles=CO&width=200&height=200

URLconf 検索に GET または POST パラメーターが含まれていない

または、{% url %} タグを使用する場合は、URL パターンを次のように再構築する必要があります。

r'^depict/(?P<width>\d+)/(?P<height>\d+)/(?P<smiles>\w+)$' 

次に、次のようなことができます

{% url cyclops-depict 200 200 "CO" %}

ファローアップ:

カスタムタグの簡単な例:

from django.core.urlresolvers import reverse
from django import template
register = template.Library()

@register.tag(name="myurl")
def myurl(parser, token):
    tokens = token.split_contents()
    return MyUrlNode(tokens[1:])

class MyUrlNode(template.Node):
    def __init__(self, tokens):
        self.tokens = tokens
    def render(self, context):
        url = reverse('cyclops-depict')
        qs = '&'.join([t for t in self.tokens])
        return '?'.join((url,qs))

テンプレートでこのタグを次のように使用できます。

{% myurl width=200 height=200 name=SomeName %}

そしてうまくいけば、それは次のようなものを出力するはずです

/depict?width=200&height=200&name=SomeName
于 2010-05-06T03:38:34.440 に答える
18

組み込みの django のQueryDictを使用することをお勧めします。リストも適切に処理します。End は、一部の特殊文字 (、、、「#」など) を自動的にエスケープし=ます。?/

from django.http import QueryDict
from django.core.urlresolvers import reverse

q = QueryDict('', mutable=True)
q['some_key'] = 'some_value'
q.setlist('some_list', [1,2,3])
'%s?%s' % (reverse('some_view_name'), q.urlencode())
# '/some_url/?some_list=1&some_list=2&some_list=3&some_key=some_value'

q.appendlist('some_list', 4)
q['value_with_special_chars'] = 'hello=w#rld?'
'%s?%s' % (reverse('some_view_name'), q.urlencode())
# '/some_url/?value_with_special_chars=hello%3Dw%23rld%3F&some_list=1&some_list=2&some_list=3&some_list=4&some_key=some_value'

これをテンプレートで使用するには、カスタム テンプレート タグを作成する必要があります。

于 2014-12-24T19:30:06.807 に答える
6

元の回答はどちらも、ビューコードのURLを解決する関連する問題に対処していません。将来の検索者のために、これを行おうとしている場合は、次のようなkwargsを使用してください。

reverse('myviewname', kwargs={'pk': value})
于 2013-01-02T10:18:26.920 に答える
5

urllib を使用した答えは確かに優れていますが、文字列の連結を回避しようとしている間、path + '?' + urllib.urlencode(kwargs). pathにすでにいくつかのクエリ パルマがある場合、これにより問題が発生する可能性があると思います。

変更された関数は次のようになります。

def url_with_querystring(url, **kwargs):
    url_parts = list(urlparse.urlparse(url))
    query = dict(urlparse.parse_qsl(url_parts[4]))
    query.update(kwargs)
    url_parts[4] = urllib.urlencode(query)
    return urlparse.urlunparse(url_parts)
于 2015-11-11T08:27:45.810 に答える
4

以前の回答の実用的なバリエーションと、このようなものを扱った私の経験。

from django.urls import reverse
from django.utils.http import urlencode

def build_url(*args, **kwargs):
    params = kwargs.pop('params', {})
    url = reverse(*args, **kwargs)
    if params:
        url += '?' + urlencode(params)
    return url

使い方:

>>> build_url('products-detail', kwargs={'pk': 1}, params={'category_id': 2})
'/api/v1/shop/products/1/?category_id=2'
于 2018-09-15T11:29:00.843 に答える