django redirect view with parameter - python

In my App I have the file urls.py that contains these rows:
...
path('home/', views.home, name='home'),
path('page/', views.page, name='page'),
....
and in my view.py file i have two view like this:
def home(request, value=0):
print("value=", value)
return render(request, 'template.html', context)
def page(request):
if bad:
return redirect(reverse('home'), value=1)
Is it possible to have the view function with a parameter (like the value in this case) and then use redirection from the page view passing some value based on the same condition like value=1, in this case, using the format described in the urls.py?
The code above always prints value=0 no matter what.
The only way I can think to do this is to use global variables which I would really like to avoid...

Yes, but you need to add the parameter to the URL:
path('home/', views.home, name='home1'),
path('home/<int:value>/', views.home, name='home2'),
Then you need to pass the page in the redirect itself, together with the name of the view, you should not use reverse(..) here:
def page(request):
if bad:
return redirect('home2', value=1)

Related

Django Urls - two views with same regular expression

I have two views with the same regular expression, as you can see below. It's a Category and an Article view, their entry slugs will never be the same so it should be no problem. But at the moment it doesn't work well, as you prolly know the category-view will get triggered.
Please do not suggest to make the url structure unique, the slugs of categories and articles will never be the same. It should be as short as possible.
urls.py
urlpatterns = [
url(r'^index', index.Index.as_view(), name='index'),
url(r'^search', search.Index.as_view(), name='search'),
url(r'^(?P<slug>.+)$', category.Index.as_view(), name='category'),
url(r'^(?P<slug>.+)$', article.Index.as_view(), name='article'),
]
I tried to reverse from views.category back to urls.py if there is no category to find like this:
views.category.py
class Index(View):
def get(self, request, slug):
category = CategoryModel.objects.get(slug=slug)
if category is None:
return HttpResponseRedirect(reverse('article', args=[slug]))
context = {
'category': category
}
return render(request, 'category/index.html', context)
The error (but there is a article with slug 'test123'):
NoReverseMatch at /wiki/test123
Reverse for 'article' with arguments '('test123',)' and keyword arguments '{}' not found. 0 pattern(s) tried: []
Using Python 3.6
Why dont you try differentiating the URLs like so
urlpatterns = [
url(r'^index', index.Index.as_view(), name='index'),
url(r'^search', search.Index.as_view(), name='search'),
url(r'^category/(?P<slug>.+)$', category.Index.as_view(), name='category'),
url(r'^article/(?P<slug>.+)$', article.Index.as_view(), name='article'),
]
You get to use the same regular expressions without the URL being ambiguous.
You can remove the article.Index view and rather than trying to redirect when there's no object for Category, you can call the method you defined in article.Index with the same parameters as the get method takes in article.Index view.
Example:
urls.py
urlpatterns = [
url(r'^index', index.Index.as_view(), name='index'),
url(r'^search', search.Index.as_view(), name='search'),
url(r'^(?P<slug>.+)$', category.Index.as_view(), name='category'),
# article url removed
]
views.category.py
from path.to.article import Index as ArticleIndexView
class Index(View):
def get(self, request, slug):
category = CategoryModel.objects.get(slug=slug)
if category is None:
# calling article app's Index get method
article_index_view_obj = ArticleIndexView()
return article_index_view_obj.get(request, slug)
context = {
'category': category
}
return render(request, 'category/index.html', context)
If you make the article.Index class view as function-based view.
You can import from path.to.article import index as article_index
and then, instead of instantiating the object, you can directly call article_index(request, slug).
There are several issues here.
(1) You call reverse with args but you have specified a kwarg.
if category is None:
return HttpResponseRedirect(reverse('article', args=[slug]))
Reverse for 'article' with arguments '('test123',)' and keyword arguments '{}' not found.
Says exactly that - as you did not provide the keyword argument, it could not find the matching URL pattern. This would be correct:
if category is None:
return HttpResponseRedirect(reverse('article', kwargs={'slug':slug}))
(2) You will end up in that same code again and again - is what I expect to happen once you fix (1). Because if reverse really does reverse the URL - the result of reverse will of course also match the category URL which means it will simply call the category.Index view - again.
I think your URL setup could actually work because the resolver does try all URLs sequentially until one comes along that matches. I'm just not sure if you can make the view return something that will lead to the URL resolver to kick in and decide to take the next URL (article) instead of category which just resolved. Probably not.
In this case, if you are fine with redirects, you could just define 3 URL patterns. 1 for the view that will operate as a switch and redirect to the CategoryView or ArticleView respectively.
Otherwise go with Sachin Kukreja's solution of handling both in one view.
Finally I made it like this. Actually I wanna use 2 different views but I guess it's fine too. Does someone see a mistake?
class Index(View):
def get(self, request, slug):
self.request = request
self.slug = slug
self.item = None
is_article = ArticleModel.objects.filter(slug=self.slug).exists()
if is_article:
self.item = 'article'
return self.article()
is_category = CategoryModel.objects.filter(slug=self.slug).exists()
if is_category:
self.item = 'category'
return self.category()
self.item = None
# 404 here
return HttpResponse(self.item)
def article(self):
article = ArticleModel.objects.get(slug=self.slug)
context = {
'article': article
}
return render(self.request, 'article/index.html', context)
def category(self):
category = CategoryModel.objects.get(slug=self.slug)
context = {
'category': category
}
return render(self.request, 'article/index.html', context)

How to call a specific url from Django views?

I want to make a call to specific url pattern from Django Views.
The call should be inside first IF conditional and outside the inner if. Is the any function which provides redirection? Or something like redirect(map_vertical_crawl)? The code portion for
Django Views:
def add_vertical(request):
if request.method == 'POST':
form = VerticalForm(request.POST)
if form.is_valid():
form.save()
#I WANT TO CALL URL EXACTLY AT THIS POINT, INSIDE OUTER IF.
verticals = Verticals.objects.all()
return render(request, 'cfman/add_vertical.html',
{'form': VerticalForm(),
'verticals': verticals}
)
Django URLS:
from django.conf.urls import url
from . import views, apps
urlpatterns = [
#Generates Login Screen
url(r'^$', views.LoginView.as_view(), name="login"),
#Directs to manager view level 1
url(r'^manager/$', views.verticals_view, name="manager"),
#Directs to manager view level 2
url(r'^manager/(?P<verticalid>\d+)/$', views.source_list, name='source_list'),
#Add Vertical
url(r'^verticals/add_vertical/$', views.add_vertical, name="add_vertical"),
#Add Source
url(r'^sources/add_source/$', views.add_source, name="add_source"),
#Add Crawl Type
url(r'^crawls/add_crawl/$', views.add_crawl, name="add_crawl"),
#Map verticals and crawl types
url(r'^vertical_crawl/$', views.map_vertical_crawl, name="map_vertical_crawl"),
]
I want to call the last url pattern , 'map_vertical_crawl' from views.
Django's built-in redirect() accepts a view name as parameter, so just do:
redirect('cfman:map_vertical_crawl')

Django, GET parameters keeped into the URL after a POST call

I'm new to Django!
I'm doing a simple registration form, when it is submitted, it returns a label to the previous page, that is the main page:
The form is submitted like this:
<form method="post"">
And its mapped in urls.py:
url(r'^userfilt/insertForm/$', views.insertForm, name='insertForm')
All the urls.py file:
app_name = 'SSO_Management_POC'
urlpatterns = [
url(r'^$', views.IndexView.as_view(), name='index'),
url(r'^user/$', views.user, name='user'),
url(r'^userfilt/$', views.userfilt, name='userfilt'),
url(r'^userfilt/insertForm/$', views.insertForm, name='insertForm'),
#url(r'^updateForm/$', views.updateForm, name='updateForm'),
url(r'^(?P<pk>[0-9]+)/$', views.DetailView.as_view(), name='detail'),
url(r'^(?P<pk>[0-9]+)/results/$', views.ResultsView.as_view(), name='results'),
url(r'^(?P<question_id>[0-9]+)/vote/$', views.vote, name='vote'),
]
So the related "def" its called:
def insertForm(request):
if request.method == 'POST':
#some stuff here
#sending the get parameter to the main page:
return redirect('/SSO_Management_POC/userfilt/?label=User Registered!')
now when i redirect to the main page i'll see something like:
Now i want just continue working so, I'll put a filter into the input and i perform a search, below the code:
if request.method == 'POST':
form = UserForm(data=request.POST)
val = request.POST.get('my_textarea')
return render(request, 'SSO_Management_POC/userfilt.html', {'top_user': TopUser.objects.filter(user_name__regex=val)})
As you can see is a POST call, but it comes the issue, GET parameter is still there so this cause
And obviously i don't want anymore the label there, it should disappear after another call...
And the url still looks like this:
http://127.0.0.1:8000/SSO_Management_POC/userfilt/?label=User%20Registered!
Now, i know i can resolve this with workaround front end side, but i would like to know:
Is there something that is not good as flow of operations?
How can i resolve this? Where am i wrong..?
I tried to look for something to clean the get parameter in the url, or to reset it, beacuse i thought it was the easier way, but the only things i found costs a lot of code, have you other idea about to clean the url?
is there any other Django method that helps you resolve this, or maybe simply avoid this problem?
The problem is that you don't have an action="" in your form tag which simply means that you want to post to the existing URL, including any querystring (ie. existing GET parameters).
Just add action="" to the form tag, such as:
<form method="POST" action="{% url 'insertForm' %}">

Django logout() returns none

Morning everyone
Im using django logout() to end my sessions just like django docs says :
views.py
class Logout(View):
def logout_view(request):
logout(request)
return HttpResponseRedirect(reverse('cost_control_app:login'))
and im calling it from this url :
urls.py
url(r'^logout/$', views.Logout.as_view(), name = "logout"),
Buttttttt it's not working, when i do a trace i find that the function :
def logout_view(request):
it's returning "none" and it's nos entering to execute the code inside...
Please help me !
I'm curious, why do you have the method named logout_view()? By default, nothing is going to call that method. You need to change the name to match the HTTP verb which will be used to call the page. For instance, if it's going to be a GET request, you would change it to:
def get(self, request):
If you want it to be a POST request, you would change it to:
def post(self, request):
This is the standard way that class-based views work in Django. Also, you may want to look at the documentation for class-based views, as this may give you a better idea of their workings and what they can provide to you. (Hint: There is a built-in RedirectView)
Django has a built in logout view. I would use that rather than writing your own.
from django.contrib.auth import views as auth_views
from django.core.urlresolvers import reverse_lazy
url(r'^logout/$',
auth_views.logout,
{'next_page': reverse_lazy('cost_control_app:login')},
name='logout',
)
If you want to write your own logout view, then I would stick with a function based view. There's no need to use a class based view here. The docs on logging a user out have an example.
def logout_view(request):
logout(request)
# Redirect to a success page.
Then change the url pattern to
url(r'^logout/$', logout_view, name="logout"),
If you really want to write a class based view, then you need to fix your Logout view. See Joey's answer for more info about this.
Solved it, i just removed the class logout(View) and call the def from the url without the "as_view" and it works. Thanks to all !

How to redirect with variables in django?

How to redirect with variables in django?
Please guide me, thank you.
urls.py:
urlpatterns = patterns('',
url(r'^$', views.index, name='index'),
url(r'^computer/$', views.computer, name='computer'),
url(r'^result/$', views.result, name='result'),
)
This is my original views.py :
def computer(request):
result = Computer.objects.order_by('?')[:1]
return render(request, 'many/result.html',{'result':result})
And I found I problem, render will not redirect to moneymany/result.html on the url,
so if the user refresh, it will get another result on the same page.
So I have to use redirect to many/result.html .
What's the usually way to redirect in django and I have to pass variable result?
I try this,but not work :
def result(request):
return render(request, 'many/result.html')
def computer(request):
result = Computer.objects.order_by('?')[:1]
url = reverse(('many:result'), kwargs={ 'result': result })
return HttpResponseRedirect(url)
you need
url(r'^result/(?P<result>[^\/]*)/$', views.result, name='result'),
and
return redirect(reverse('many:result', kwargs={ 'result': result }))
or (without changing url)
return redirect('/result/?p=%s' % result )
if you want to maintain POST data while redirecting, then it means your design isnot good. quoting Lukasz:
If you faced such problem there's slight chance that you had
over-complicated your design. This is a restriction of HTTP that POST
data cannot go with redirects.
How about using redirect.
from django.shortcuts import redirect
def computer(request):
result = Computer.objects.order_by('?')[:1]
return redirect('view-name-you-want', { 'result'=result })
this worked with i just needed to pass url parameters as arguments
return redirect('pagename' ,param1 , param2)
my url looks like :
path('page', views.somefunction, name="pagename")
Note: in my case somefunction accept only POST parameters
To redirect from a view to another view with data, you can use session with request.session['key'] and in this case, you don't need to modify path() in "myapp/urls.py" as shown below. Then, give the conbination of the app name "myapp", colon ":" and the view name "dest_view" which is set in path() in "myapp/urls.py" as shown below:
# "myapp/views.py"
from django.shortcuts import redirect
def redirect_view(request):
# Here
request.session['person'] = {'name': 'John', 'age': 27}
# Here
return redirect("myapp:dest_view")
# "myapp/urls.py"
from django.urls import path
from . import views
app_name = "myapp"
urlpatterns = [ # This is view name
path('dest/', views.destination_view, name="dest_view")
]
Then, this is how you get the data of "post" method:
# "myapp/index.html"
{{ request.session.person.name }} {# John #}
{{ request.session.person.age }} {# 27 #}

Categories