Is it ever possible to delete a URL path : Django - django

I had in my urls.py file, url patterns for certain data processing requirements and later I realized that from among a bunch of them, one was not intended as its requirement had ceased.
However, when I am trying to delete the particular line (the second pattern in the excerpt of the urls.py reproduced here), I am getting the following error at page load ('holding_list'):
NoReverseMatch at /supp/holding_comp/
Reverse for 'holding_change' not found. 'holding_change' is
not a valid view function or pattern name.
I have checked all the references (I think) wherever the path might have been referred to (including the related template).
urls.py
path('supp/holding_comp/', views.HoldingListView.as_view(), name='holding_list'),
...
...
path('supp/holding_comp/edit/<int:pk>/', views.HoldingUpdateView.as_view(), name='holding_change'),
How do I delete the second url pattern (the one for "edit" view)?
I tried to look for a similar query but failed to (may be for want of a suitable search string). Any clue will be appreciated.

Short answer: there are still things referring to the path, and you should find a way to remove these.
This error means that a template, in this case the template rendered by the 'holding_list' view, contains a {% url ... %} template tag that refers to that path(..).
You thus should search in the template for {% url 'holding_change' ... %} patterns, and decide what to do with links that refer to that path.
Note that this might not be sufficient: in order to be safe, you should search all templates and all Python files for {% url ... %} template tags, redirect(..)s, reverse(..)s, etc. You probably best search for holding_change, and thus look what might still refer to that URL.

Related

django url concatenation. I don't want to concatenate

when I do something in 'profile' page,
the url is concatenated to the next of 'profile'.
but I want to link to just 'signout'. not 'profile/signout'
this is my urls.py.
when ever I do something in 'profile'page,
the href link is concatenated to 'profile'url.
this is href source.
since this href source is header.html,
this page is included another pages.
and in the other pages, it works well.
only in profile page, the href url is concatenated to 'profile/1' url.
how can I fix it?
Yes, a URL not starting with a slash or a scheme is a relative URL. href="foo" is equivalent to href="./foo", i.e. it refers to the path foo relative to the current path. If you want the top-level path, you want href="/foo".
In Django you're supposed to use the {% url %} template tag to generate URLs, you don't hardcode them. Django will take care to generate the correct URL; especially if you move the app around to other environments, the URL may require a prefix or such, so you should never hardcode the URL.

is it good approach to parse urls yourself rather than by urlpattern match groups?

Let's assume I am building a blogging app and create the following url pattern:
url(r'^(?P<category>.+?)/(?P<date>.+)$', views.post_list, name='post_list'),
Then I create multiple templates adding this everywhere:
{% url 'myapp:post_list' category date %}
But then I think hmm... I don't want date there, let it be <category> and <slug> instead.
Then I have to change corresponding {% url tags everywhere in my templates!
Wouldn't it be better to rewrite url regex like this:
url(r'^(?P<url>.+?/.+)$', views.post_list, name='post_list'),
and define some url_split() function somewhere, which would parse it in the views, add url() method or property to corresponding model and be able to use the following url tags:
{% url 'myapp:post_list' obj.url %}
and therefore never touch them in case I want to change something in my url regex/parameters etc?
Is it good design or am I missing something?
But then I think hmm... I don't want date there, let it be
and instead.
Then I have to change corresponding {% url tags everywhere in my
templates!
Why is this a problem?
Is it good design
No it is not:
The function becomes ambiguous. It is doing too many things at once.
You are replicating functionality already available in the framework.
You have now effectively creating a choke point by creating a "blanket" catch-all request method. In this method there will be a bunch of decision tree if/else clauses and such branching is prime spot for bugs.
The entire purpose of doing this is for some imagined use case that may or may not happen.
From xkcd # 974:

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.

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

View referenced by two urls and url tag

I am using url tag in my template for a view, that is used by two different urls. I am getting the wrong url in one place. Is there any way to force django to retrieve different url? Why it doesn't notify my, that such conflict occured and it doesn't know what to do (since python zen says, that is should refuse temptation to guess).
Code in template:
{% url djangoldap.views.FilterEntriesResponse Entry=entry.path as filter_url %}
Code in urls:
(r'^filter_entries/(?P<Entry>.*)/$',
'djangoldap.views.FilterEntriesResponse',
{'filter_template': 'filter_entries.html',
'results_template': 'filter_results.html'}),
(r'^choose_entries/(?P<Entry>.*)/$',
'djangoldap.views.FilterEntriesResponse',
{'filter_template': 'search_entries.html',
'results_template': 'search_results.html'}),
As you can see, those two urls use the same view, but with different templates. How I can force django to retrieve former url, rather than latter?
Name your URLs by adding another item to the tuple:
(r'^choose_entries/(?P<Entry>.*)/$',
'djangoldap.views.FilterEntriesResponse',
{'filter_template': 'search_entries.html',
'results_template': 'search_results.html'},
'sensibleprefix-choose_entries') # <-- this is the name
Then you can use the name in the URL tag.