The http://127.0.0.1:8000/song/299d8fe1-7d9f-434a-ba64-94fb7a16b1a6/gives me the desired page based on the uuid of the song and works fine.
(It's the second url.)
Here is the urls.py
urlpatterns = patterns('',
url(r'^$', views.index, name='index'),
url(r'^song/(?P<uuid>\S+)/$', views.song, name='song'),
--> url(r'^song/(?P<uuid>\S+)/song_info/$', views.song_info, name='song_info'),
)
The third url,
http://127.0.0.1:8000/song/299d8fe1-7d9f-434a-ba64-94fb7a16b1a6/song_info/
the one the arrow is pointing at, gives me a 404 error, with the message "No Song matches the given query."
I'm guessing there's an error with the regex, but I can't figure it out.
EDIT
Here are the views for both the song and song info:
views.py
imports....
#login_required
def song(request, uuid):
song = get_object_or_404(Song, uuid=uuid)
song_status = song.get_status()
form = SongInfoForm(initial={'song_info': song.song_info}, user=request.user)
return render(request, 'songapp/song.html',
{'form': form, 'song': song, 'song_status': song_status})
def song_info(request):
return render(request, 'songapp/song_info.html')
\S+ matches any sequence of characters, including '/'. So your second regex is matching the entire string of "299d8fe1-7d9f-434a-ba64-94fb7a16b1a6/song_info/" as the UUID parameter, and sending it to views.song, which unsurprisingly does not find a matching song.
You should make your regexes more discriminating:
url(r'^song/(?P<uuid>[\w-]+)/$', views.song, name='song'),
url(r'^song/(?P<uuid>[\w-]+)/song_info/$', views.song_info, name='song_info'),
Also, you should usually put your regexes in order of more specific to more general; Django matches in order, so if you had put song_info first that would also have solved your problem.
you should use this url
url(r'^song/(?P<id>[a-zA-Z0-9]{0,30}[^/]+)/song_info/$
Here, [^/] represents any type of character but /, and the + right after matches this class of character one or more times. You do not want the final / to be in the uuid var, so put it outside the parentheses
Related
I am trying to make urls pattern to catch all urls from root.
my main urls.py is:
path('', (include('myapp.urls', namespace='app1')
I am using two url patterns in app1.urls:
re_path(r'^(?P<url_var1>[-\w./]+)/$', DetailView1.as_view(), name='DetailView1'),
re_path(r'^(?P<url_var2>[-\w./]+)/$', DetailView2.as_view(), name='DetailView2'),
My views.py file is as:
class DetailView1(View):
template_name = 'detail.html'
def get(self, request, url_var1):
obj1 = model1.objects.get(my_url=url_var1)
return render(request, self.template_name, {'obj1':obj1})
class DetailView2(View):
template_name = 'detail.html'
def get(self, request, url_var2):
obj2 = model2.objects.get(my_url=url_var2)
return render(request, self.template_name, {'obj2':obj2})
when i request url "/first-post/my-first-post/", It checks out the url which is in my "model1" under ther header "my_url" and return the page.
But when I request url "/second-post/my-second-post/", It checks out the url in "model1" and throws an error, as the url is in "model2" under header "my_url".
I know that the urlpattern follows a squence check, and stops at the pattern which matches the first urlpattern(DetailView1), thats why It is giving me this error.
I want to know is there a way I can override this behavior of urlpattern.
I have also tried reverse, when url is not found in DetailView1:
try:
obj1 = model1.objects.get(my_url=url_var1)
except:
return reverse('app1:DetailView2')
But Its still giving me an error.
If any of you got any other suggestions for catching urlpattern from root for mare than two type of urlpattern please tell me.
I am making a product cum blog website which has two models "model1" which is a product model, and "model2" which is a blog model. Now the "model1" is for automobile having 2 main categories "car" and "bike" and "model2" is having the same as "latest in cars" & "latest in bikes". For these categories I want to pick up urls from the root which have been given as "/cars/lexus.....", "/bike/ducati....". Also, there can be further additions of subfolder url and all urls have product IDs having "." and numbers. So is there is way i can pick urls frm root for both models using the above url pattern.
Its not possible to have multiple views and single urlpattern in Django.
Take a look at your views. They are almost the same. You should put the logic handling different url parameters in single view.
My advice would be also to carefully review your model design, it looks like you have two models that are essentially the same. I feel that this is the root of your problem.
Additionally I assume that you are trying to create some kind of blog.
Django had its beginning as framework powering news site. And it has some helpful tools. For example take a look at SlugField This may provide you with functionality you are looking for. Without over complicating the urlpatterns.
There are two models: groups and posts. The post can be of one of two kinds: assigned to the group, and not assigned to the group. The foreign key field in posts model, which assigns the group to the post, is optional. The post, which belongs to a group, should have a different address than one, which does not belong to the group. Here is the general rule. The former address is when a post does not belong to any group and the latter one if it does.
.../posts/[year]/[month]/[day]/[slug of the post]/
.../groups/[name of the group]/posts/[year]/[month]/[day]/[slug of the post]/
The problem appears. After creating the post both url addresses work.
It is not a surprise, because I include the urls from posts app in urls.py in groups app.
What I want to do is to make the url addresses optional regarding to the group parameter (whether it is passed or not). It can work as something like:
if groups parameter is not None choose the url from groups.urls
if groups parameter is not None exclude url from posts.urls
Basically I want to choose just one url, not two.
Is it possible in Django to do it in a simple way? Or is the only solution creating two models/two apps instead of one?
Excerpt of my code:
groups/urls.py
app_name = 'groups'
urlpatterns = [
...
path('<slug:slug>/posts/', include('posts.urls', namespace='grouppost')),
...
]
posts/urls.py
app_name = 'posts'
urlpatterns = [
path('', views.PostList.as_view(), name='list'),
path('create', views.CreatePost.as_view(), name='create'),
path('<int:year>/<int:month>/<int:day>/<slug:slug>/', views.PostDetail.as_view(), name='detail'),
path('<int:year>/<int:month>/<int:day>/<slug:slug>/update/', views.UpdatePost.as_view(), name='update'),
path('<int:year>/<int:month>/<int:day>/<slug:slug>/delete/', views.DeletePost.as_view(), name='delete'),
]
I am using Django 2.0.7.
Update 16.08
I also include the path in mu root urls.py. Sorry for the omission of this important information.
urls.py
urlpatterns = [
...
path('groups/', include('groups.urls')),
path('posts/', include('posts.urls')),
...
]
You should try to avoid logic in urls. That's what views or business logic in even lower levels are for. Instead, you could create a view that acts as a redirection page that takes the parameter you want and, depending on what it is, redirects to the right url.
If you do that, you would need to keep track of any request arguments.
# url (located wherever you want):
(r'post-redirection/<string:posts_or_group>/<int:year>/<int:month>/<int:day>/<slug:slug>/', post_redirection, name="post_redirection")
# view:
def post_redirection(request, post_or_group, year, month, day, slug):
if post_or_group == "post":
post_url_name = "..." # This is the url that you want to go to if it is a request to .../posts/[year]/[month]/[day]/[slug of the post]/
return HttpResponseRedirect(reverse(post_url_name, kwargs={"year": year, "month": month, "day": day, "slug": slug}))
elif post_or_group == "groups":
group_url_name = "..." # This is the url that you want to go to if it is a request to .../groups/[name of the group]/posts/[year]/[month]/[day]/[slug of the post]/
return HttpResponseRedirect(reverse(group_url_name, kwargs={"year": year, "month": month, "day": day, "slug": slug}))
else:
# error. However you want to handle it. You could return an error response or do something else. Maybe return a message that says they didn't choose the right option.
The only issue you might run into is preserving request data (i.e request.POST or request.GET). You would still be able to use this methodology, you would just need to find a way to pass that data on in the new redirection request as that data only lasts for one single request.
So I have a list of items and I want to have all of the items direct the user to a standard info page about that item when clicked. I don't full understand the dynamic url system in django. My html file for the content is called detail.html. The goal is to click a movie item, and be directed to a page title "blahblah.com/specific_movie_title"
In views.py I have:
def detail(reuqest, movie_title):
moviePage = Movie.objects.get(pk=movie_title)
return render_to_response('detail.html', {'detail':moviePage, RequestContext(request))
In the urls.py the line I have to correspond with this is:
url(r'^$', views.detail, name='detail')
Could I get help with correcting these two chunks of code?
In django, urls are matched by a regular expression pattern.
The general format of the url line is:
url(the_pattern, the_view_name_or_callable, **any_extra_arguments)
The key point is the_pattern, which is a regular expression and whatever is matched can be passed as an argument to the view function.
It is important that any parts of the pattern that are captured and passed on to the view function, actually match the function's signature (the def line, where you define the name and arguments). Otherwise, django will throw an error.
So now, with that out of the way - lets deal with the actual issue.
Your want a url like /the_great_gatsby to redirect to the page for The Great Gatsby.
The first step is to identify a pattern that matches the_great_gatsby. You can use [_\w]+ which means "one or more word characters or _", and plug it into the URL:
url(r'/[_\w]+$', views.detail, name='detail')
Next, you have to tell django how to capture that pattern and pass it to the view method as an argument.
Your view method is: def detail(request, movie_title). So django must pass whatever is after the / in the url (and matches the pattern) to the argument name movie_title, so what we want is this:
def detail(request, movie_title)
^^^^^^^^^^^
---------------|
|
vvvvvvv
url(r'/[_\w]+$', views.detail, name='detail')
We modify the regular expression to make sure that django captures whatever matches, and then assigns it a name. To do that, wrap the part of the regular expression in (?P<name_of_variable>expression) like this:
url(r'/(?P<movie_title>[_\w+])$', views.detail, name='detail')
Now, whatever is captured after / will be passed as the argument movie_title to the views.detail method.
Of course, you have to make sure your view function is doing the right thing with the captured string. In your case, your view method is searching by the primary key and will fail to produce any results (and will raise an exception) since there is no movie that will have the title as the primary key; but that's another problem.
you can configure your url and view like this
urls.py
url(r'^movie/(?P<movie_title>\w+)$', views.movie_detail, name='detail')
views.py
def movie_detail(request, movie_title):
movie_object = Movie.objects.get(pk=movie_title)
return render(request, 'moview-detail.html', {'movie_object':movie_object}
and in your html {% url 'app_name:detail' movie_title %}
In one of my view function, under certain condition I want to redirect to another URL.
So I am doing
return HttpResponseRedirect(reverse(next_view, kwargs={'name': name1}))
Now I have another view function like
def next_view(request, name):
I also put following line in relevant urls.py file
from wherever import next_view
urlpatterns = patterns("",
url(r"^next_view/(?P<name>w+)/", next_view, name="next_view"),
)
This does not work, I get
Reverse for 'next_view' with arguments '()' and keyword arguments '{'name': u'test'}' not found.
I'm guessing that the regex isn't matching properly. How about:
r"^next_view/(?P<name>\w+)/"
Note the backslash before the 'w'.
For urls.py you want to add the backslash before the w+ and also add a $ sign at then end of the URL so that any other URL's joined onto this will be accepted:
urlpatterns = patterns("",
url(r"^next_view/(?P<name>\w+)/$", next_view, name="next_view"),
)
For views.py you want to add parenthesis around your view name:
def example_view(self):
# view code
return HttpResponseRedirect(reverse('next_view', kwargs={'name': name1}))
I'm having an html form which inserts data into one table called srv.
I've built the urls.py in such a way to capture every insertion:
for item in srv.objects.all():
linkSrv = item.loc.lower() + '/srv/' + item.subctg.lower() + '/' + item.title.lower()
urlpatterns += patterns('',
url(r'^' + linkSrv + '/$', 'beta.views.queryFromIndexDeep'),
)
After the one insertion is being made, e.g. loc='loc', subctg='subctg' and title='title'
if i point my browser to 127.0.0.1:8000/loc/srv/subctg/title/ i get the http404 error (no matching url)
If I 'force-save' the urls.py (vim urls.py then :x! ) - after loc,subct,title were inserted - then I can successfully access 127.0.0.1:8000/loc/srv/subctg/title/
Anyone can shed some light? It looks like the urlpatterns need to be 'updated' each time a row is insterted in srv table.
You should just use something like this:
urlpatterns += patterns('',
url(r'^(?P<loc>\w+)/(?P<subctg>\w+)/(?P<title>\w+)/$',
'beta.views.queryFromIndexDeep'),
)
Using regular expressions to match your view is way easier, and recommended. In your view, the above would match a function defined like beta.views.queryFromIndexDeep(request, loc, subctg, title), from where you can continue to work with these variables to extract the relevant data from your defined models.
add a slugfield (unique) to your srv model and add a method to the model
def get_absolute_url(self):
return /yourapp/%s/ % self.slug
Then in urls use a pattern to match this
url(r'^srv/(?P<slug>[-\w]+)/$', yourgenericview),
Look into the django slugify snippit for fun http://djangosnippets.org/snippets/690/