Django Slugs as principal url - python

I want to do the following, so that the profile of each registered user can be seen as follows:
http://127.0.0.1:8000/username/
I was able to achieve this, the problem is when wanting to create another page, for example
http://127.0.0.1:8000/explore/
Django consider "explore" as a user and throw me a 404 error.
this is my urls.py
urlpatterns = [
path("<slug:slug>/", PerfilView.as_view(), name="perfil"),
path("explore/", UserListView.as_view(), name="explore"),
]
Am I doing it the right way or am I unable to do this with django?
Regads

You should swap the two path(…): if you visit explore/ it will first match with the PerfilView since the slug can take 'explore' as value.
You thus should rewrite the urlpatterns to:
urlpatterns = [
# &downarrow; first explore
path('explore/', UserListView.as_view(), name='explore'),
path('<slug:slug>/', PerfilView.as_view(), name='perfil'),
]
This also means that you can not use explore as a slug here, since then it will match with the UserListView.

Related

In django how to generate dynamic url after domain name for every page?

I am building a blog website where I set a unique title for every article. I want the article should have url domain_name/<article_title>/.
Suppose I have model A and Moel B:
class A(models.Model):
title = models.CharField(max_length=500,unique=True)
class B(models.Model):
title = models.CharField(max_length=500,unique=True)
app.urls.py file :
urlpatterns = [
path('',view.index,name="index"),
path('contact/', contact, name="contact"),
path('about/', about, name="about"),
path('terms-and-conditions/', terms, name="terms_and_conditions"),
path('privacy/', privacy, name="privacy"),
path('<str:title>/', article_details, name="article_details"),
]
I have view file as follows:
def article_details(request,title):
if 'title_in_model_A':
render 'some_page_A'
if 'title_in_model_B:
render 'some_page_B'
render(request,'app/404.html')
project.urls file:
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('app.urls')),
]
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
handler404 = 'app.views.view_404'
My question is:
Is this type of page rendering good or not?
Does 404 request handles correctly?
The way OP is doing is ok, but if one wills it's possible to simplify the article_details view by using the shortcut get_object_or_404, like
from django.shortcuts import get_object_or_404
def article_details(request,title):
article = get_object_or_404(A, title=title)
In order to customize the 404 view one can use handlers. Here's a good example in the docs.
Hard to say if OP's renders correctly because the question doesn't show that OP has a clothes app with a view_404 in views.py.
As per OP's new requirement, in the case of having two models and wanting to check the existence of instances that have the title matching a specific one, then OP can use exists() as follows
def article_details(request,title):
if A.objects.filter(title=title).exists():
# render page A
elif B.objects.filter(title=title).exists():
# render page A
else:
# 404
Note that this method is good if one doesn't need the model but are just checking the existence. If one does need it as well, then one can include inside of the condition the following (before the render)
my_model = MyModel.objects.get(title=title)

Django page not found (404) in my core/urls.py file. Only works when the urls are rearranged

I am relatively new to Django. I've set up my URLs in my core/urls.py file this way and I do get a 404 error when I opened localhost:8000/posts/ on the browser. Code is shown here
urlpatterns = [
path('', views.IndexView.as_view(), name='index'),
path('<slug:slug>/', views.SingleView.as_view(), name='single'),
path('posts/', views.PostsView.as_view(), name='posts'),
]
However, everything works fine when I reverse the slug and posts/ to make the posts come before the slug. Like this:
urlpatterns = [
path('', views.IndexView.as_view(), name='index'),
path('posts/', views.PostsView.as_view(), name='posts'),
path('<slug:slug>/', views.SingleView.as_view(), name='single'),
]
Please help me figure it out.
That's how Django (and most other frameworks) work. When a request comes in, Django will check the routes that you specified and it uses the same order that you specified them. So in your first example, '' is the first one and then '<slug:slug>/' and 'posts/' after that. this means that every time a request comes in, Django will check for routes on that order. basically how a for loop works:
Example URL: yoursite.com/posts/
Path: "posts/"
routes = ["", "<slug:slug>/", "posts/"]
path = "posts/"
for route in routes:
if route == path:
# use view for this route
return
So in this case, it will match with index 1 which is <slug:slug>/, and returns the view specified for it.
Now to understand why <slug:slug>/ == "posts/" returns True you need to understand what slug means in Django:
slug - Matches any slug string consisting of ASCII letters or numbers, plus the hyphen and underscore characters. https://docs.djangoproject.com/en/3.1/topics/http/urls/#example
So it will accept any path that matches those requirements and posts/ actually matches those requirements. Django doesn't check any other routes if it finds a match so it will never gets to path('posts/', views.PostsView.as_view(), name='posts') because '<slug:slug>/' has higher priority being in the smaller index over 'posts/'. And you probably check for that slug in your models which isn't there so it will return a 404.
By changing the route order, you change the routes to ["", "posts/", "<slug:slug>/"]. Now "posts/" has higher priority and django will use PostsView.

Forward url arguments to view in Django

I am trying to forward projects/1 to the view, for purpose of getting the project based on the id.
I have tried to change the regex, and the name.
Edit: But the issue is:
The id doesn't get forwarded (Or atleast not correctly) to the views, which results in the filter failing to find the Project based on the id.
Urls related to the 'Project':
urlpatterns = [
url(r'^$', views.index, name='index'),
url(r'^project/(?P<project_id>([0-9]+))$', views.project, name='project'),
]
The view for the 'Project':
def project(request, project_id=1):
template = loader.get_template("project.html")
context = {
'project': Project.objects.filter(project_id=project_id)
}
return HttpResponse(template.render(context, request))
The regex seem a little incorrect to me, especially parentheses. Try this:
url(r'^project/(?P<project_id>[0-9]+)/$', views.project, name='project'),
UPDATE:
So you want to show only one project instead of several. In that case, change Project.objects.filter to Project.objects.get in your view.
Also, try this awesome django tutorial to learn the basics
Hope it helps.

URL Regular Expression mismatch

I am trying to learn Django and I am currently stuck in an issue.
I created an app Contact and run the server, I get the error.
The error page displayed by server:
The urls.py file in the app Contact
urls.py in conatct
When the pattern in urls.py is
urlpatterns =[url(r'^$', views.form, name ='form')]
it works properly, but not with other pattern shown in the picture
Your help would be greatly appreciated.
The Page not found error message tells you what went wrong: For the URL (/contact) you requested, Django was unable to find a suitable view. Because you have debugging enabled, you get some information, including a list of registered views.
First things first: You probably have url(r'^contact/', include('contact.urls')) somewhere in your top level urls.py. This makes the URLs defined in the contact/urls.py available under the prefix /contact.
With
urlpatterns = [
url(r'^form/', views.form, name='form'),
]
in contact/urls.py you are telling Django that you want urls starting with contact/form/ to be handled by views.form.
Consequently, when you access http://localhost:8000/contact/ in your browser, there is no view associated with that URL, hence the 404. Your view is reacting to to http://localhost:8000/contact/form, not http://localhost:8000/contact.
When you change the URL pattern to
urlpatterns = [
url(r'^$', views.form, name='form'),
]
you modify the URL views.form reacts to.

Multiple django apps using same url pattern

I'd like to run two apps with the same url patterns. I would like to avoid having an app-specific slug like domain.com/pages/something-here or domain.com/blog/something-there.
I tried this:
# urls.py
urlpatterns = patterns('',
url(r'^$', 'my.homepage.view'),
url(r'^admin/', include(admin.site.urls)),
url(r'^', include('pages.urls')),
url(r'^', include('blog.urls')),
)
# pages/urls.py
urlpatterns = patterns('',
url(r'^(.+)/$', views.page),
)
# blog/urls.py
urlpatterns = patterns('',
url(r'^(.+)/$', views.post),
)
My code doesn't work, whichever include comes first (here, pages.urls) works ok, other urls (for blog) throw 404.
Thanks in advance
EDIT: I did it like this: created glue.py in the same directory as settings.py. It will handle my homepage and this dispatcher view:
def dispatcher(request, slug):
try:
page = get_object_or_404(Page, slug=slug)
return render(request, 'pages/page.html', {'page': page})
except:
post = get_object_or_404(Post, slug=slug)
return render(request, 'blog/post.html', {'post': post})
I don't know if it's ok. I hope there is a better way.
Thanks for the comments.
I don't know if this is a better answer. But, if these situations are satisfied for you..
if your django app is based on django template rendering.
The url you are talking about, need not be accessed directly by typing the endpoint in the browser itself.
Then, maybe you could consider url namespaces and template redirections.
https://docs.djangoproject.com/en/1.11/topics/http/urls/#url-namespaces
This doesn't work because django urls are resolved in order, meaning that the first url that matches the regexp will be the resolved one. In your case, the the urls included from the blogs application will never be searched, as django already resolved the url on the pages includes line.
Also, the django url module is not supposed to know if a certain page or blog post exists, as i believe in your application this is determined with a database lookup.
The urls module just executes the view that is connected to the first regexp that matches.
You should change your logic, e.g. with perpending "blog/" to blog urls (what's wrong with that?)
url(r'^blog/', include('blog.urls')),
url(r'^', include('pages.urls')),
Notice that the i moved the blog url up, as most generic regxexp should always be the last to be tried by django url resolver.
Alternatively, you could code a proxy view that tries both blog posts and pages. but it doesn't seem the best way to do it to me.
How would you like this to work? They're both using the same URL (which of course is causing problems). How would a user get to a "page" rather than a "blog" or vice versa?
In general, you can't have overlapping URLs in your URL patterns (without including additional data).
EDIT:
So you want the first app to check if it has a view to match the URL and next to take over if the first doesn't? You could do something complicated like writing a "view matcher" to do want you want, but there are much more straigtforward solutions.
The easiest way would be to alter the slug generation function for one of your apps. Have one use some delimeter other than underscores, or always append the name of the app to the slug. This way you could find pages because their url would be "some-slug-page" and blogs would be "some-slug-blog", which you could then write a URL pattern for. If you don't want to add the entire URL, you can append/prepend just the first letter, or whatever you want.
Just think about a way that's acceptable to you to generate URLs for each app which, just by reading the URL, lets you know which app the page belongs to.

Categories

Resources