Newbie: URL doesn't match django template name - django

I'm working on my first django application, and I can't find anything in the docs that explains this.
I have a view called submit_proposal. If successful, it stores the relevant objects to the database then sends a user to a listing of all their open proposals. It displays correctly, but the listing page URL isn't shown by the browser.
Here's the code:
context = RequestContext(request,
dict(user_name=gc_user.get_full_name,
game_list=game_list,
POSTData=request.POST,
)
)
template = loader.get_template('user_proposals.html')
return HttpResponse(template.render(context))
This is called from submit_proposal, which passes the returned HttpResponse object back in turn:
result = user_proposals(request)
return result
I've looked at result in the debugger, and as far as I can tell it doesn't include a URL generated from the template name. Should I be doing something else to create the response? Or do I need to use something other than HttpResponse?
Thanks for your help!
Beverly

The most common way to do this in Django is to have two urls, for instance:
urlpatterns = patterns('',
url(r'^proposal/$', 'app.views.submit_proposal', name='submit_proposal'),
url(r'^proposal/all/$', 'app.views.list_proposals', name='list_proposals'),
Then the submit_proposal function should validate, store and redirect the user to list_proposals if successful
from django.shortcuts import redirect
def submit_proposal(request):
...
return redirect('list_proposals')
The argument to redirect is the name of the url for listing proposals.

Related

Permanent redirect absolute url

I am struggling with a basic redirect functionality.
I need to redirect all traffic not matching certain paths to another domain.
in my urls.py
re_path(r'^(?P<shortcode>[\w-]+)/$', core_views.myView)
and the corresponding function in views.py
def myView(request, shortcode=None):
url = 'www.newdomain.cz/' + str(shortcode)
return HttpResponsePermanentRedirect(url)
but what it does is - when called for example www.olddomain.com/sdfasd it redirects me to www.olddomain.com/sdfasd/www.newdomain.cz/sdfasd but I obviously need only www.newdomain.cz/sdfasd
what am I missing?
You need to use a fully qualified url.
def myView(request, shortcode=None):
url = 'http://www.newdomain.cz/' + str(shortcode)
See the doc here.

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.

Django Allauth very specific redirection after Facebook Social Signup

I know there are a few questions on the topic already but I have tried to implement those solutions and could not really solve my problem.
I am talking about social signup with allauth here, and facebook in particular.
DESIRED BEHAVIOR: after facebook signup I want user to go to my url "accounts:welcome", but when they simply login I want them to go to my LOGIN_REDIRECT_URL (which is the site's home page).
After looking here and there this is the code I came up with (writing my custom adapter)
settings.py:
LOGIN_REDIRECT_URL = ("gamestream:home")
SOCIALACCOUNT_ADAPTER = "myproject.users.adapter.MySocialAccountAdapter"
adapter.py:
from django.conf import settings
from allauth.socialaccount.adapter import DefaultSocialAccountAdapter
from django.core.urlresolvers import reverse
from django.shortcuts import redirect
class MySocialAccountAdapter(DefaultSocialAccountAdapter):
def save_user(self, request, sociallogin, form=None):
print('OK11OK')
super().save_user(request, sociallogin, form=form)
return redirect(reverse('accounts:welcome'))
def get_connect_redirect_url(self, request, socialaccount):
print('OK22OK')
assert is_authenticated(request.user)
url = reverse('accounts:welcome')
return url
Please assume that all links/settings are good as for example the console prints out 'OK11OK' when I create myself as a user via the facebook app. The fact is that the method get_connect_redirect_url never gets triggered as I never read 'OK22OK' on the console.
The user is created and I end up on the home page, which is not what I want.
So I thought that after the save_user method something else gets called as I can tell that I pass through accounts:welcome, but then end up on the home page.
I can tell this because if I return an incorrect url in the save_user method I get an error that is specific to that url on that line.
So, what is wrong here?
I think I might be overriding the wrong method but I have read all the code of the base SocialAccountAdapter and I can't see anything else that would be the right choice.
Just wanted to mention that as I have more control on the normal account signup (not social) I have achieved what I wanted.
Any ideas?
Thanks very much!
I had the same problem too, I found two methods:
METHOD 1
Django doesn't use redirection function of the DefaultSocialAccountAdapter, you'll have to override the get_signup_redirect_url function of DefaultAccountAdapter to achieve the result.
First you need to change the default adapter in settings.py:
ACCOUNT_ADAPTER = 'users.adapter.MyAccountAdapter'
Then, just override the get_signup_redirect_url with your url:
# project/users/adapter.py
from allauth.account.adapter import DefaultAccountAdapter
class MyAccountAdapter(DefaultAccountAdapter):
def get_signup_redirect_url(self, request):
return resolve_url('/your/url/')
METHOD 2
This is the easier one
If you take a look at the source code at DefaultAccountAdapter it says:
Returns the default URL to redirect to after logging in. Note
that URLs passed explicitly (e.g. by passing along a next
GET parameter) take precedence over the value returned here.
So, you can pass along a next parameter in your login template to force the redirection. Here is an example using Google social login:
{% load socialaccount %}
{% providers_media_js %}
{# your html tags #}
<body>
SOCIAL LOGIN
</body>
Of course you can personalize the next url (I'm refering to /success/url/) as you wish. You can pass a context variable with your desired url and put it there instead of that hardcoded url.

How to handle url collisions in django/wagtail

how to handle two different views witch match for the same url? (Both views need a database call to determine if the called element is available. Changing the url structure is not an option.)
url(r'^', include(wagtail_urls)),
This wagtail url is matching all url's and is raising an 404 if the according page/slug is not in the database.
But, I also have my own view witch behaves similar. How can I tell django to continue with the next url instead of raising a 404?
(I could place my own view before the wagtail view and modify it, but I don't know how to return to the next url?)
This is my solution at the end:
from wagtail.wagtailcore.views import serve
# ... in my view where I normally return a 404 => I set this:
return serve(self.request, self.request.path)
First of all, Sharing same url pattern in diffrent views is bad idea.
The bigger your project, the harder it will be to maintain it.
Nevertheless, there is a way if you want that way.
You can place your own view first in urls.py like your saying,
process some your own logic first and catch 404 exception when there is nothing to show in your view than simply call the "Wagtail" view with request original parameters(page, slug, etc..) with return statement.
Below is example.
This example is based on Django functional based view, but there is the way in class based view something like this.
def your_own_view(request, slugs):
try:
article = get_object_or_404(Article, slugs=slugs)
except Http404:
return some_wagtail_view(request, slugs)
...
return render(request, "article/view.html", context)

How to redirect page to another page in django for class based view?

I am new in django therefore i don't know how to redirect page to another page in django. Please help me to solve this issue.
This is my urls.py file
urlpatterns = patterns('',
url(r'^demo$', views.BookList.as_view(), name='demo'),
)
This is my views.py file
class BookList(ListView):
model = Book
template_name = "demo.html"
here i am trying to redirect it to my demo.html file. I didn't get any error by this code but still page is not redirected.
To make a view redirect to another page, you have to specify a url where it should redirect.
You don't "redirect" to a template, you "render" a template. You can redirect to a url which renders a template.
To do a redirect in a view, you can use RedirectView. It will redirect to the given URL.
Example:
Suppose there is a view MyView which has a url defined in it. Then, whenever there is a request to MyView, it will redirect to the specified url .
class MyView(RedirectView):
url = 'my_redirect_url'
You can also pass url directly in the urls.py like:
url(r'^my_view_url/$', RedirectView.as_view(url='my-redirect-url'))
In your above code, there was no error because ListView takes template_name as an attribute. It will then use this template to display the list of Book objects. Here there is no redirection happening, infact, the template demo.html is being rendered which displays the list of Book objects.
class BookList(ListView):
model = Book
template_name = "demo.html"