urls not overlapping -- How to fix - django

I am trying to filter products either by brand or category but the url path will only execute path('<slug:brand_slug>/', views.product_list,name='product_list_by_brand'), since it appears first and would not execute the second.
Is there a way I can probably merge both paths or cause both paths to work independently without taking order into consideration.
from . import views
app_name = 'shop'
urlpatterns = [
path('', views.product_list, name='product_list'),
path('<slug:brand_slug>/', views.product_list,name='product_list_by_brand'),
path('<slug:category_slug>/', views.product_list,name='product_list_by_category'),
]
Thank you in advance for your response.

the problem is your upper url pattern is overriding second URL because of same slug and some other reasons.
FIX
change your URL pattern
path('<slug:brand_slug>/brand/', views.product_list,name='product_list_by_brand'),
path('<slug:category_slug>/', views.product_list,name='product_list_by_category'),
Another Thing You Can Do!
modify your function and url pattern.
def product_list(request, slug):
mode = request.GET.get("mode")
if mode.lower() == "brand":
''' your brand code '''
pass
else:
''' your category code '''
pass
path('<slug:slug>/', views.product_list,name='product_list_by_category'),
if you want to execute brand code your URL pattern would look like this.
127.0.0.1:8000/yourslug?mode=brand
and with this url pattern it will execute category code.
127.0.0.1:8000/yourslug
so by default it will execute category code.

Related

Django urlpatterns when a category is included into URL

Django 3.0.6
urlpatterns = [
path('', HomeView.as_view(), name='home'),
path('{}'.format("admin/" if DEBUG else "dhjfsljdasdhje32/"), admin.site.urls), # Change admin url for security reasons.
path('image/', include(('image.urls', 'image'), namespace="image")),
path('polls/', include(('polls.urls', 'polls'), namespace="polls")),
path('applications/', include(('applications.urls', 'applications'), namespace="applications")),
]
def _get_categories_url_pattern():
"""
Organize urls with posts categories.
URL format:
<category>/<post_slug>
Example: linux/how_to_install_ubuntu/
"""
categories = Category.objects.all().values_list("slug", flat=True)
for category in categories:
urlpatterns.append(path('{}/'.format(category), include('post.urls')))
urlpatterns.append(path('draft/{}/'.format(category), include('post.urls')))
_get_categories_url_pattern()
Please, concentrate your attention on how categories in urls are handled.
Problems with this code:
When a new category is added in the admin site, Django project has
to be relaunched (at least with the built in dev server).
When last time I did python manage.py makemigrations it blew up. I
had to comment out anything having anything to do with
_get_categories_url_pattern. Then it made migrations. Now I can't reproduce this error anymore. But there seems to be some danger in this code.
Could you help me understand how to refactor this code for it to work at least without restarting the dev server when a new category is added.
The urls are loaded when the server starts, so you should avoid doing database queries there.
When you run migrate for a fresh database, your code will give the error because the category table hasn't been created yet. Once you have done the first migration, the code will run without error, but as you have noticed, the URLs will not update as new categories are added.
The normal approach is to add a slug kwarg to the URL pattern.
path('applications/', include(('applications.urls', 'applications'), namespace="applications")),
path('<slug:slug>', include('post.urls')),
path('draft/<slug:slug>', include('post.urls')),
Then in the view, use get_object_or_404 to make sure that the category exists.
from django.shortcuts import get_object_or_404
def category_view(request, slug):
category = get_object_or_404(Category, slug=slug)
...
One problem with this, is that <slug:slug>/ will match other URLs, e.g. /image/ or /polls/. In the above code, I've avoided that problem by putting <slug:slug> at the bottom of the URL patterns. Another option would be to use something like categories/<slug:slug>/ so that it doesn't match other URLs.

Dynamic and custom Urls

I'm currently working at my first Django REST Api and I have a question about the routing.
I have a JSON and the short form looks like this:
{
"name": "Summer Festival",
"date": "2020-01-05",
"deadline": "2020-01-01",
"address": "Fantasy Road 50",
"postcode": 12346,
"location": "New York",
(...)
}
I use this ViewSet:
class EventViewSet(viewsets.ModelViewSet):
queryset = Event.objects.all()
serializer_class = EventSerializer
and this serializer:
class EventSerializer(serializers.ModelSerializer):
class Meta:
model = Event
fields = "__all__"
My urls.py:
router = routers.DefaultRouter()
router.register("events", views.EventViewSet)
urlpatterns = [
path('', include(router.urls)),
path(
'events/location=<str:address>&from=<str:from>&to=<str:to>',
views.EventViewSet.as_view({"get": "list"})),
path('api-auth/', include('rest_framework.urls', namespace='rest_framework')),
]
The scenario:
On my frontend is a form where you can pick your postcode and a date range.
When the user just inserts his postcode he gets all events up today and the url should look like this:
http://127.0.0.1:8000/events/postcode=12345
When the user picks a from date and postcode it should like this:
http://127.0.0.1:8000/events/postcode=12345&from=2019-01-01
With a daterange + postcode like this:
http://127.0.0.1:8000/events/postcode=12345&from=2019-01-01&to=2019-02-01
The url should be dynamically build.
The second path in my urls.py code snippet is a workaround but this urls isn't dynamically created. My first idea was to just set the values null but the result is just a large url with no information.
I already tried to work with the lookup field but you just can use it with a single value.
Is there another builtin django or django rest approach to achieve this dynamic url with dynamic query parameters?
Django take help of URL dispatchers to router request to appropriate view.
Django provide both(static and dynamic) options for URL.
In django if you want to generate dynamic URL you take help of regular expression
https://docs.djangoproject.com/en/3.0/topics/http/urls/#using-regular-expressions

django url _reverse _ not a valid view function or pattern name

the redirect url is
"liveinterviewList/2"
and, ofcourse, I declare that url in url.py
more over, when I type that url in browser manualy, it works well.
what's the matter?
more question.
at this case, I write the user_id on the url.
I think, it is not good way to make url pattern.
but I don't know how I deliver the user_id variable without url pattern.
please give me a hint.
What HariHaraSudhan left out was how to use parameters. For your case, you would want something like:
path(r'liveinterviewList/<int:userId>', ..., name='live-interview'),
And then when you are ready to reverse, use this:
reverse('app:live-interview', kwargs={ 'userId': userId })
where app is the name of the app in which your view lives. If your url lives in the main urls file , you don't need the app: prefix.
Django reverse function accepts the name of the path not the URL.
lets say i have url patterns like this
urlpatterns = [
path('/users/list', name="users-list")
]
In my view i can use like this
def my_view(request):
return redirect(reverse("users-list"));
You should add a name to your path url and use it to redirect.
As the django doc says :
urls :
urlpatterns = [
path('/name', name="some-view-name")
]
def my_view(request):
...
return redirect('some-view-name')

Django - Retrieve url origin from view - multiple urls to 1 view

I have several urls mapping to one view. Inside the url, I would like to know the url origin? It is to avoid writing multiple views (DRY).
urlpatterns = [
path('path1/', views.IndexView.as_view(), name='index'),
path('path2/', views.IndexView.as_view(), name='index')
]
class IndexView(generic.ListView):
url_origin = ... #would like path1 or path2
I looked for 'reverse' but it does not seem to be a solution to my problem. It returns an error.
reverse('index')
Thank you in advance
You can obtain the original path with request.path [Django-doc] (so in a view function for a class-based view, you can access this with self.request.path.
You can however fix this, for example by providing an extra parameter, like:
urlpatterns = [
path('path1/', views.IndexView.as_view(), name='index1', kwargs={'through': 'path1'}),
path('path2/', views.IndexView.as_view(), name='index2', kwargs={'through': 'path2'})
]
Then you can inspect the self.kwargs['through'] parameter in your class-based view.
Note that you better give the different paths a different name, since otherwise, it will indeed raise an error. By giving these as name 'index1' and 'index2', you can simply use reverse('index1'), and it is not ambiguous to what URL it should redirect.

redirect vs reverse django

I have experienced using reverse within get_absolute_url method in the model, but I wish I have an idea about the difference between reverse and redirect, I have tried to search on google about it but there is almost nothing
I don't know what should I write also to convince stack overflow that I don't have any other description
Reverse and redirect have a different meaning. Here is a simple explanation:
reverse in Django is used to find the URL of a given resource. Let's say that you have a blog website and from the main page, you want to provide links to your blog posts. You can of course just hard-code /posts/123/ and just change the ID of your blog post in URL, but that makes it hard to change your URL for the post in the future. That's why Django comes with reverse function. All you need to do is to pass the name of your URL path (defined in your urlpatterns) and Django will find for you the correct URL. It is called reverse because it is a reverse process of determining which view should be called for a given URL (which process is called resolving).
Redirects are not specific to Django or any other web frameworks. Redirect means that for a given URL (or action), the user should be instructed to visit a specific URL. This can be done by sending a special redirect request and from there the browser will handle it for the user, so no user action is required in that process. You can use reverse in redirect process to determine the URL that the user should be redirected to.
GwynBleidD has given you the answer, but there is a reason why you might be getting confused. The Django redirect shortcut accepts arguments in several different forms. One of them is a URLpattern mane, with arguments, that is then passed to reverse to generate the actual URL to redirect to. But that's just a shortcut, to enable a common pattern.
here's an example
app/views
#imports
def indexView(request):
....
return render(request, 'index.html', context)
def loginView(request):
....
return redirect('index')
def articleDetailView(request, id):
....
return redirect(reverse('article-comments', kwargs={'id':id})
def articleCommentsView(request, id):
....
return render(request, 'comment_list.html', context)
proj/urls
#imports
urlpatterns = [
....,
path('', include(app.urls))
]
app/urls
#imports
urlpatterns = [
....,
path('index/', index, name='index'),
path('login/', loginView, name='login'),
path('article/<int:id>/detail', articleDetailView, name='article-detail'),
path('article/<int:id>/comments/',articleCommentsView, name='article-comments')
....,
]
For loginView redirect will return url as-is i.e. 'index' which will be appended to base(project) urlpatterns. Here redirect(reverse('index')) will also work since kwargs is None by default for reverse function and 'index' view doesn't require any kwarg. It returns '/index/' which is passed to redirect(which again will be appended to base urls).
One thing to note is that reverse is used to make complete url - needed for redirect - that is shown in 'articleDetailview'.
The most basic difference between the two is :
Redirect Method will redirect you to a specific route in General.
Reverse Method will return the complete URL to that route as a String.