django reversing url failure with hyphen in view name - django

My first question, so please be patient if I miss key info or not format it correctly.
I recently started experimenting with django and run into the following error:
Reverse for 'dispatcher' with arguments '(u'to-do',)' and keyword arguments '{}' not found
the relevant line in the template.html (I am showing a menu) is:
<li>{{ item }}</li>
I also includes {% load url from future %} as I read in some other question on this forum.
I have few other items in the list, such as 'today', 'tomorrow' etc. and as long as I don't have a hyphen I don't get any error. If I remove the hype, i.e. instead of to-do use todo, everything works.
snippet of my urls.py is:
urlpatterns = patterns('app.views',
url(r'^$', 'home', name="home"),
url(r'^items/(?P<item>\w+)/$', 'dispatcher', name="dispatcher"),
)
Whether relevant or not, I tracked down to iri_to_url function in encoding.py and saw that hyphen is not part of 'safe'list. But adding '-' to the list didn't solve the problem.
Appreciate your advise and help.

Your regex does not support the - Hence the error. change \w+ to [\w-]+
Try this:
url(r'^items/(?P<item>[\w-]+)/$', 'dispatcher', name="dispatcher")

Related

Custom Django SlugField Validation Breaks URL Matching

I wrote a custom field validator for slugs in my URLs (accepting periods in slugs for one model, SLUG_REGEX = '[-a-zA-Z0-9_.]+$'):
def validate_my_slug(value):
my_slug_re = re.compile(settings.SLUG_REGEX)
if not my_slug_re.match(value):
raise ValidationError(
_('Slugs must consist of letters, numbers, '
'underscores, hyphens, or periods.'),
params={'value': value},
)
The field in models.py:
slug = models.CharField(max_length=64, null=True, blank=True,
validators=[validate_my_slug])
This works when saving models in Django admin. But then in my URLConf, this no longer works (it did work before changing the slug validation):
path('product-release/<slug:slug>', ProductReleaseDetail.as_view(),
name='product-detail')
I found a solution using re_path, but I'm not sure it's the right/best way to do it:
re_path('product-release/(?P<slug>[-a-zA-Z0-9_.]+)$',
ProductReleaseDetail.as_view(),
name='product-release-detail')
Now this no longer works (comes before the re_path pattern above in urls.py):
path('product-releases', ProductReleaseList.as_view(),
name='product-release-list')
Everything works except those matches to product release list. When I changed the slug validator, the URL http://localhost:8080/product-releases stopped working, with the error:
NoReverseMatch at /product-releases
Reverse for 'product-release-detail' with no arguments not found.
1 pattern(s) tried: ['product-release/(?P<slug>[-a-zA-Z0-9_.]+$)']
But this seems wrong since I'm not even trying to reach product-release-detail; I'm trying to reach product-release-list. I must be missing something simple here, but now my vision is clouded.
views.py
. . .
class ProductReleaseList(ListView):
model = ProductRelease
class ProductReleaseDetail(DetailView):
model = ProductRelease
. . .
urlpatterns
. . .
# Product Releases
path('product-releases', ProductReleaseList.as_view(), name='product-release-list'),
re_path('product-release/(?P<slug>[-a-zA-Z0-9_.]+$)', ProductReleaseDetail.as_view(), name='product-release-detail'),
# Release Notes
path('release-notes', ReleaseNoteList.as_view(), name='release-note-list'),
re_path('release-note/(?P<slug>[-a-zA-Z0-9_.]+$)', ReleaseNoteDetail.as_view(), name='release-note-detail'),
. . .
productrelease_list.html
. . .
<h4>{{ p }}</h4>
. . .
In your template you're using something akin to:
{% url "product-release-detail" varname %}
This variable however can apparently be empty (or is even always empty due to a spelling mistake). With /<slug:slug> this goes through (which I don't agree with btw, but that's besides the point). With your more restrictive and better re_path, this now generates an error (correctly), because /product-release/ is not a valid url: a slug should at least have one character.
So the root cause is ether, that the variable is incorrectly named or that you have products without slugs (which you shouldn't have).
Address comments
Commenting out in templates is done with {# #}. Make sure you didn't use <!-- -->, because that still executes the code.
As it stands {% url "product-release-detail" %} is invalid: it requires an argument, namely a slug. If you want to link to the list view, use {% url "product-release-list" %} as that can be called without argument.
I don't know what {{ p }} is, but I'm assuming the product object. In that case, you should use {%url "product-release-detail" p.name_of_slug_field %}.

Add comment to a post - NoReverseMatch error

I am building a website with a simple blog.
I follow the instructions from: http://lightbird.net/dbe/blog.html
I got to a point where I see posts, but then he adds links to each post.
I added :
(r"^(\d+)/$", "post"),
to my urls.py and when I added : Comments everything breaks. It's like it's not sending the value. I think I am doing something wrong with the links..
Can anyone check my app?
Admin account : admin/admin.
Wrong code is in: templates/news/list.html
When I delete that line it works.
Here is my code: https://db.tt/b7qpib28
TRACEBACK : http://dpaste.com/1471932/
You need to remove the $ in url pattern that includes news.urls, so in Uploader/uploader/uploader/urls.py change the line 32:
(r"^news/$", include('news.urls')),
by this
(r"^news/", include('news.urls')),
That's all ;) ...this obstruct the rest of url, you can display the url for news.views.main because it didn't add anything to the url but news.views.post need to add the pk parameter
Firstly, your closing single quote is I the wrong place. Secondly, try using the url pattern name instead of the path to the view.
Try the following:
{% url 'post' post.pk %}

{% url %} gives me NoReverseMatch error while reverse() returns the url just fine. Why?

I don't know if this SO question is of the same problem that I am about to describe, but it does share the same symptoms. Unfortunately, it still remains unresolved as I am writing.
So here is my problem. I am trying to add James Bennett's django-registration app to my django project. I have pretty much finished configuring it to my needs - custom templates and urls. Just when I thought everything was good to go. I got NoReverseMatch error from using {% url 'testing' item_id=123 %} (I also tried using the view name, myapp.views.test, instead but no luck) in one of the custom templates required by django-registration. Interestingly, I tried reverse('testing', kwargs={'item_id':123}) in the shell and the url was returned just fine. I thought {% url %} uses reverse() in the back-end but why did I get different outcomes?
urls.py: (the URLconf of my site)
urlpatterns = patterns('myapp.views',
url(r'^test/(?P<item_id>\d+)/$', 'test', name='testing'),
)
activation_email.txt: (the said template. Note it's intentionally in .txt extension as required by django-registration and that shouldn't be the cause of the problem.)
{% comment %}Used to generate the body of the activation email.{% endcomment %}
Welcome to {{ site }}! Please activate your account by clicking on the following link:
{% url 'testing' item_id=123 %}
Note the activation link/code will be expired in {{ expiration_days }} days.
I don't know if it matters but just thought I should mention activation_email.txt is stored in the templates directory of myapp though it is used by django-registration.
Also, I am using django 1.4
I have a feeling that the problem has something to do with the url namespaces, a topic that I have never understood, but it's just a naive guess. (IMO, the django documentation is great in explaining everything about django, except when it comes to url namespaces)
I'm no expert here, but in a Django project I'm working on at the moment I use the name of the url without quotes. I just added quotes around a similar line in one of my templates and it produced the same error as your error.
Try:
{% url testing item_id=123 %}

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 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 }})'