Django NoReverseMatch error on URL - regex

I'm trying to use a named regular-expression group to pass a keyword arguments to a view.
I'm very new to using regular-expressions (and Django) and keep getting a NoReverseMatch error.
In my template has a table with the following:
<td><i class="icon-forward"></i></td>
The URL that corresponds to "{% url profile player.user %}" is:
url(r'^profile/(?P<players_username>\w)/$', profile_page, name='profile'),
Also I'm not sure if "\w" was correct for this regex. Ideally I it could receive any character.
And my view "profile_page" is:
#login_required
def profile_page(request,players_username):
return render(request, 'portal/portal_partial_profile.html')
I'm not sure why I'm getting this error? I appreciate any feedback and expertise.

Since you are assigning the match to a variable (its a keyword), you need to pass it in, like this:
{% url profile players_username=player.user %}
Another minor correction, your regular expression should be \w+. The + means "one or more, but at least one", otherwise your regular expression will not work as you expect (unless all your players have one character usernames).

Related

identical views different URLs

I have following routs:
url(r'^future/programs/$', main.programs, {'period': 'future'}),
url(r'^past/programs/$', main.programs, {'period': 'past'}),
When I try to display link in template, using template tag url like this
{% url main.views.main.programs %}
I always get link /past/programs/. When I try like this
{% url main.views.main.programs period="future" %}
I get an error:
Caught NoReverseMatch while rendering: Reverse for
'main.views.main.programs' with arguments '()' and keyword arguments
'{'period': u'future'}' not found.
How i can display link to /future/programs/?
I think you might want to approach it with one single url pattern:
url(r'^(?P(<period>[\w]+)/programs/$', main.views.programs),
and in your view:
def programs(request, period):
if period == 'future':
...
elif period == 'past':
...
and in templates:
{% url main.views.main.programs period="future" %}
In your approach, you are mistaking the forward flow with the reverse flow, i.e. the extra keyword arguments of the url conf with the keyword arguments that are passed to match a pattern.
The former is extra data you are allowed to pass to a view when it is matched (i.e. when a user goes to /future/programs/, the pattern is matched and period=future is passed to the view), the latter is the actual data used to match the url (i.e. the period=future is passed to the reverse() function which tries to match a pattern that excepts those keyword arguments - which you haven't outlined)
Edit:
A more appropriate pattern to use in your url would be something like:
url(r'^(?P(<period>past|future)/programs/$', main.views.programs),
where the selection could only be 'past' or 'future'. This is fine for incoming urls, but django's reverse() function (which is used in the url template tag) can't handle alternative choices:
https://docs.djangoproject.com/en/dev/topics/http/urls/#reverse
The main restriction at the moment is that the pattern cannot contain alternative choices using the vertical bar ("|") character.
I would rather assign each url a name:
url(r'^future/programs/$', main.programs,
{'period': 'future'},
name='future_programs'),
url(r'^past/programs/$', main.programs,
{'period': 'past'},
name='past_programs'),
And to display the link in your template:
Past programs: {% url past_programs %}
Future programs: {% url future_programs %}
I think this solution is better because if you just have two options for that view, you can forget about passing parameters and validating them.
Now, if those two options (future, past) can grow into several more, the other solution would be better, but I think this is not the case.

Whats the correct way to use and refer to a slugfield in a django 1.3

Whats the correct way to use and refer to a slugfield in a django 1.3
for example the following code should link via slug to a generic view however the NoReverseMatch error is received.
Caught NoReverseMatch while rendering: Reverse for 'single_post' with arguments '('', u'post-2')' and keyword arguments '{}' not found.
From my understanding this saying that the error lies in the template however being a newbie and having tried many different variations on {% url single_post slug=post.slug %} this may not be the case.
Could someone please explain why this is happening so that I can understand where the problem lies andhow to fix.
Ive tried {% url single_post slug=post.slug %},{% url single_post slug %}{% url single_post slug=post.slug %} and many other variations
All help is greatly appreciated
model
slug = models.SlugField(max_length=120, unique=True)
url
url(r'^post/(?P<slug>[a-z-]+)/$', list_detail.object_detail,
{'queryset': Post.objects.all(), 'template_object_name': 'post', 'slug_field': 'slug'}, name="single_post"),
template
{% url single_post slug post.slug %}
Your regex doesn't allow for numeric values. Try:
(?P<slug>[\w-]+)
In your template, assuming post is an instance of your model:
{% url single_post post.slug %}
Your url regex should look like the following:
url(r'^post/(?P<slug>[\w-]+)/$', ...
To test the above regex, try to access a few posts directly in your browser with a variety of valid slugs and see if they works. Once this is done, start testing the url names.
A slug value can contain any a-z, A-Z, 0-9, _ and -. The first 3 are represented by the special character w and since - itself is a special character, we need to use represent them both using a backslash \. So the correct expression becomes
url(r'^post/(?P<slug>[\w\-]+)/$', ...
At least this is what is working in my case.
In Django 1.5 the slug validator uses this regex:
slug_re = re.compile(r'^[-a-zA-Z0-9_]+$')
See https://github.com/django/django/blob/stable/1.5.x/django/core/validators.py#L106
You can use this regex in urls.py:
url(r'^post/(?P<slug>[-a-zA-Z0-9_]+)/$', ...
In earlier versions it was [-\w]+ but I guess in Python3 \w matches non ascii characters like umlauts.

Django: Passing model object values through url

I'm having problems with passing model object values through a URL pattern. The URL:
url(r'^cities/(?P<city>\w+)/$', 'city_firm', name='city_firm'),
In the template (from the index page) I have:
{{ city }}
This is in a for loop.
The related view is:
def city_firm(request, city):
city1 = Cities.objects.get(city=city)
cityf = city1.Firms.all()
return render_to_response('cityfirm.html', {'cityf': cityf})
The two models (Cities, Firms) are in a many to many relationship.
I keep getting TemplateSyntaxError at index (NoReverseMatch while rendering: Reverse for 'city_firm' with arguments '(<Cities: >,)' and keyword arguments '{}' not found). In the template link tag I tried: {% url city_firm city=city %}, {% url city_firm city=cities.city %}. Nothing changed. The urlconf part seems right. The problem seems to be in the template. Maybe there is an issue with the string values of the object as they aren't in English. But I took several precautions to prevent this. There is maybe something wrong with the view but the error says template. Any ideas?
Solution:
Thanks everyone! Finally I figured it out. The problem was simple: I was trying to send object attribute names through the url, that had non-English characters and spaces. To fix it, I had to edit my models.
The issue is that you can't pass an object in a URL, you can only pass characters. So you need to put the part of the city object that contains the text you want to be in the URL - in your case, it appears to be an attribute also called city, which is what you use to in the lookup to get the object in the view. So it should be:
{{ city }}
I don't think name means what you think it does - remove that and read this: http://docs.djangoproject.com/en/dev/topics/http/urls/#naming-url-patterns
As far as the error... the NoReverseMatch is telling you that it's not seeing any arguments. Remember that nonexisting template variables expand to "". Make sure city is in context when you're running that code - maybe post the for in the template?

Django Generic object_list pagination. Adding instead of replacing arguments

I'm having some trouble with the django generic object_list function's pagination not really being "smart" enough to compensate my daftness.
I'm trying to do a url for listing with optional arguments for page number and category.
The url in urls.py looks like this:
url(r'^all/(?:(?P<category>[-\w]+)/page-(?P<urlpage>\d+))?/$',
views.listing,
),
The category and urlpage arguments are optional beacuse of the extra "(?: )?" around them and that works nicely.
views.listing is a wrapper function looking like this( i don't think this is where my problem occurs):
def listing(request,category="a-z",urlpage="1"):
extra_context_dict={}
if category=="a-z":
catqueryset=models.UserProfile.objects.all().order_by('user__username')
elif category=="z-a":
catqueryset=models.UserProfile.objects.all().order_by(-'user__username')
else:
extra_context_dict['error_message']='Unfortunately a sorting error occurred, content is listed in alphabetical order'
catqueryset=models.UserProfile.objects.all().order_by('user__username')
return object_list(
request,
queryset=catqueryset,
template_name='userlist.html',
page=urlpage,
paginate_by=10,
extra_context=extra_context_dict,
)
In my template userlist.html I have links looking like this (This is where I think the real problem lies):
{%if has_next%}
<a href=page-{{next}}>Next Page> ({{next}})</a>
{%else%}
Instead of replacing the page argument in my url the link adds another page argument to the url. The urls ends up looking like this "/all/a-z/page-1/page-2/
It's not really surprising that this is what happens, but not having page as an optional argument actually works and Django replaces the old page-part of the url.
I would prefer this DRYer (atleast I think so) solution, but can't seem to get it working.
Any tips how this could be solved with better urls.py or template tags would be very appreciated.
(also please excuse non-native english and on the fly translated code. Any feedback as to if this is a good or unwarranted Stack-overflow question is also gladly taken)
You're using relative URLs here - so it's not really anything to do with Django. You could replace your link with:
Next Page> ({{ next }})
and all would be well, except for the fact that you'd have a brittle link in your template, which would break as soon as you changed your urls.py, and it wouldn't work unless category happened to be a-z.
Instead, use Django's built-in url tag.
Next Page> ({{ next }})
To make that work, you'll have to pass your category into the extra_context_dict, which you create on the first line of your view code:
extra_context_dict = { 'category': category }
Is /all/a-z/page-1/page-2/ what appears in the source or where the link takes you to? My guess is that the string "page-2" is appended by the browser to the current URL. You should start with a URL with / in order to state a full path.
You should probably add the category into the extra_context and do:
next page ({{next}})
"Instead of replacing the page argument in my url the link adds another page argument to the url. The urls ends up looking like this "/all/a-z/page-1/page-2/"
that is because
'<a href=page-{{next}}>Next Page> ({{next}})</a>'
links to the page relative to the current url and the current url is already having /page-1/ in it.
i'm not sure how, not having page as an optional argument actually works and Django replaces the old page-part of the url
one thing i suggest is instead of defining relative url define absolute url
'Next Page> ({{ next }})'

Django - How to pass several arguments to the url template tag

In my urls.py I have:
(r'^(?P<year>\d{4})/(?P<month>\d{2})/(?P<day>\d{2})/section/(?P<slug>[-\w]+)/$',
'paper.views.issue_section_detail',
{},
'paper_issue_section_detail'
),
and I'm trying to do this in a template:
{% url paper_issue_section_detail issue.pub_date.year,issue.pub_date.month,issue.pub_date.day,section_li.slug %}
but I get this error:
TemplateSyntaxError
Caught an exception while rendering: Reverse for 'paper_issue_section_detail' with arguments '(2010, 1, 22, u'business')' and keyword arguments '{}' not found.
However, if I change the URL pattern to only require a single argument it works fine. ie:
(r'^(?P<year>\d{4})/$',
'paper.views.issue_section_detail',
{},
'paper_issue_section_detail'
),
and:
{% url paper_issue_section_detail issue.pub_date.year %}
So it seems to complain when I pass more than a single argument using the 'url' template tag - I get the same error with two arguments. Is there a different way to pass several arguments? I've tried passing in named keyword arguments and that generates a similar error.
For what it's worth, the related view starts like this:
def issue_section_detail(request, year, month, day, slug):
How do I pass more than a single argument to the url template tag?
I had the same issue (I'm using Django 1.3.1) and tried Gregor Müllegger's suggestion, but that didn't work for two reasons:
there should be no commas between year, month and day values
my class-based generic view seems to take only keyword arguments
Thus the only working solution was:
{% url news_detail slug=object.slug year=object.date|date:"Y" month=object.date|date:"m" day=object.date|date:"d" %}
The problem lives in the /(?P<month>\d{2})/ part of your url configuration. It only allows exactly two digits (\d{2}) while issue.pub_date.month is only one digit.
You can do either allow also one digit in the URL (but this will violate the principle of unique URLs, /2010/1/... would be the same as /2010/01/...) or pass two digits to the month argument in your url templatetag.
You can use the date filter to achieve a consistent formating of date objects. Use the url tag like this:
{% url paper_issue_section_detail issue.pub_date|date:"Y",issue.pub_date|date:"m",issue.pub_date|date:"d",section_li.slug %}
Look at the month and day argument: It will be always displayed as two digits (with a leading zero if necessary). Have a look at the documentation of the now tag to see which options are possible for the date filter.
Your month expression is (?P<month>\d{2}), but you're sending it the argument 1. The 1 doesn't match \d{2}, so the url resolver isn't finding your view.
Try changing the month expression to \d{1,2} (or something to that effect).