I'm using django-rest-auth for user signup and verify email.
I'm able to successfully send the email when a user signs up. Howvever, on email verification, I'm getting this error with the following traceback:
File "/Library/Python/2.7/site-packages/django/core/handlers/base.py" in get_response
111. response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/Library/Python/2.7/site-packages/django/views/generic/base.py" in view
69. return self.dispatch(request, *args, **kwargs)
File "/Library/Python/2.7/site-packages/django/views/generic/base.py" in dispatch
87. return handler(request, *args, **kwargs)
File "/Library/Python/2.7/site-packages/django/views/generic/base.py" in get
155. return self.render_to_response(context)
File "/Library/Python/2.7/site-packages/django/views/generic/base.py" in render_to_response
130. template=self.get_template_names(),
File "/Library/Python/2.7/site-packages/django/views/generic/base.py" in get_template_names
142. "TemplateResponseMixin requires either a definition of "
Exception Type: ImproperlyConfigured at /rest-auth/registration/account-confirm-email/vjohhnrf6xpkmn1jxbzaopdn0g79tdyofumeeuyuehcuja8slyz7nzq1idyifcqk/
Exception Value: TemplateResponseMixin requires either a definition of 'template_name' or an implementation of 'get_template_names()'
Any idea on how to fix this ?
While Ricardo's answer is correct, it didn't do much to help me solve my problem. This is what I needed to do for my master urls.py:
from allauth.account.views import confirm_email
.....
url(r'^accounts-rest/registration/account-confirm-email/(?P<key>.+)/$', confirm_email, name='account_confirm_email'),
Make sure that the beginning of the url spec starts with whatever path you are using for allauth REST calls.
Of course, the above is for using the built-in view handling the confirmation.
When you use confirmation email you have two ways to do it.
Using the specified by the API or creating yours. By default it uses django-allauth and a TemplateView on reverse can be used.
If you create yours, you may have to override account_confirm_email and then post to verification_mail.
In urls.py it is defined just reverse so, depending on what you are trying to do you will have first to create your own account_confirm_email, get the required key and post it to verify-email. Here there is more information about this bug.
For the new Django versions re_path url resolver method works properly with this (?P.+) url regex.
from django.urls import re_path
re_path('rest-auth/registration/account-confirm-email/(?P<key>.+)/', CustomConfirmEmailView.as_view(), name='account_confirm_email')
Also I have customized allauth ConfirmEmailView get() method in order to redirect properly
from allauth.account.views import ConfirmEmailView
from django.contrib.auth import get_user_model
class CustomConfirmEmailView(ConfirmEmailView):
def get(self, *args, **kwargs):
try:
self.object = self.get_object()
except Http404:
self.object = None
user = get_user_model().objects.get(email=self.object.email_address.email)
redirect_url = reverse('user', args=(user.id,))
return redirect(redirect_url)
I also have the problem as I read the tutorialHere is the link ,it shows the problem as TemplateResponseMixin requires either a definition of 'template_name' or an implementation of 'get_template_names()'
solution:
I change the location of templates filer and change the templates in the setting.py
1. In the App_Name file,I add the New folder Named:templates
2. In the settings.py: TEMPLATES = [{'DIRS': [BASE_DIR+"/templates",],}]
Related
I upgraded my project from Django 1.11 to 2.2, made all the changes but came with new error that says login() got an unexpected keyword argument 'template_name'.It worked fine with the previous version of Django 1.11 (All the other urls are working, only the landing page gives the error). I couldn't find any references to this issue. Below is the error and urls and views for the issue.
Internal Server Error: /
Traceback (most recent call last):
File "C:\Users\User\venv\lib\site-packages\django\core\handlers\exception.py", line 34, in inner
response = get_response(request)
File "C:\Users\User\venv\lib\site-packages\django\core\handlers\base.py", line 115, in _get_response
response = self.process_exception_by_middleware(e, request)
File "C:\Users\User\venv\lib\site-packages\django\core\handlers\base.py", line 113, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "C:\Users\User\PycharmProjects\MyWebsite\landing\views.py", line 43, in landing_validation
login_response = login(request, template_name='landing.html')
TypeError: login() got an unexpected keyword argument 'template_name'
[19/Apr/2019 16:20:00] "GET / HTTP/1.1" 500 71948
Landing\urls.py
from django.conf.urls import url
from landing.views import landing_validation
app_name='landing'
urlpatterns = [
url(r'^$', landing_validation, name='landing')
]
Landing\views.py
from django.contrib.auth import login
def landing_validation(request):
login_response = login(request, template_name='landing.html')
return login_response
C:\Users\User\venv\Lib\site-packages\django\contrib\auth__init__.py
def login(request, user, backend=None):
"""
Persist a user id and a backend in the request. This way a user doesn't
have to reauthenticate on every request. Note that data set during
the anonymous session is retained when the user logs in.
"""
session_auth_hash = ''
if user is None:
user = request.user
if hasattr(user, 'get_session_auth_hash'):
session_auth_hash = user.get_session_auth_hash()
if SESSION_KEY in request.session:
if _get_user_session_key(request) != user.pk or (
session_auth_hash and
not constant_time_compare(request.session.get(HASH_SESSION_KEY, ''), session_auth_hash)):
# To avoid reusing another user's session, create a new, empty
# session if the existing session corresponds to a different
# authenticated user.
request.session.flush()
else:
request.session.cycle_key()
try:
backend = backend or user.backend
except AttributeError:
backends = _get_backends(return_tuples=True)
if len(backends) == 1:
_, backend = backends[0]
else:
raise ValueError(
'You have multiple authentication backends configured and '
'therefore must provide the `backend` argument or set the '
'`backend` attribute on the user.'
)
else:
if not isinstance(backend, str):
raise TypeError('backend must be a dotted import path string (got %r).' % backend)
request.session[SESSION_KEY] = user._meta.pk.value_to_string(user)
request.session[BACKEND_SESSION_KEY] = backend
request.session[HASH_SESSION_KEY] = session_auth_hash
if hasattr(request, 'user'):
request.user = user
rotate_token(request)
user_logged_in.send(sender=user.__class__, request=request, user=user)
There was no need to do a landing_validation view this line solved the issue.
url(r'^$', LoginView.as_view(template_name='landing.html'), name='landing')
In Django 2.2 app I fixed similar error by using LoginView instead of login.
File users/urls.py:
from django.conf.urls import url
# from django.contrib.auth.views import login
from django.contrib.auth.views import LoginView
from . import views
app_name = 'users'
urlpatterns = [
# url(r'^login/$', login, {'template_name': 'users/login.html'}, name='login'),
url(r'^login/$', LoginView.as_view(template_name='users/login.html'), name='login'),
]
The login function that you're using is not actually a view. It's just a regular function which you can use to authenticate a user and set the session cookie, etc.
Read the docs for it's usage: https://docs.djangoproject.com/en/2.2/topics/auth/default/#django.contrib.auth.login
Judging by your code, it appears you want to use LoginView.
from django.contrib.auth.views import LoginView
def landing_validation(request):
login_response = LoginView.as_view()(request, template_name='landing.html')
return login_response
You can see that django.contrib.auth.login takes request, user, and an optional backend. There is no template_name. This hasn't changed recently, so I think you would get the same problem in 1.11, too.
It looks like you want a view function, but django.contrib.auth.login is not that. It doesn't return a response.
In the webapp, to retrieve all the objects from a specific user I am using user pk. But to make url more readable I want to use username. The problem is in the django view, user pk in kwargs giving the correct values, but when I use username it shows error.
Here are my codes using 'username' as kwargs, that is returning keyerror,
views.py
class UserAllQuestionView(generic.ListView):
model = Question
template_name = 'mechinpy/user_profile_question.html'
context_object_name = 'user_all_questions'
def get_queryset(self):
return Question.objects.filter(user=self.kwargs['username'])
urls.py
path('m/user/<str:slug>/questions/', views.UserAllQuestionView.as_view(), name='user_profile_question_all'),
html
All User Questions
Traceback:
File "C:\Users\Bidhan\AppData\Local\Programs\Python\Python35\lib\site-packages\django\core\handlers\exception.py" in inner
34. response = get_response(request)
File "C:\Users\Bidhan\AppData\Local\Programs\Python\Python35\lib\site-packages\django\core\handlers\base.py" in _get_response
126. response = self.process_exception_by_middleware(e, request)
File "C:\Users\Bidhan\AppData\Local\Programs\Python\Python35\lib\site-packages\django\core\handlers\base.py" in _get_response
124. response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "C:\Users\Bidhan\AppData\Local\Programs\Python\Python35\lib\site-packages\django\views\generic\base.py" in view
68. return self.dispatch(request, *args, **kwargs)
File "C:\Users\Bidhan\AppData\Local\Programs\Python\Python35\lib\site-packages\django\views\generic\base.py" in dispatch
88. return handler(request, *args, **kwargs)
File "C:\Users\Bidhan\AppData\Local\Programs\Python\Python35\lib\site-packages\django\views\generic\list.py" in get
142. self.object_list = self.get_queryset()
File "C:\Users\Bidhan\Desktop\Startup\mysite\mechinpy\views.py" in get_queryset
454. return Question.objects.filter(user=self.kwargs['username'])
Exception Type: KeyError at /m/user/bidhan/questions/
Exception Value: 'username'
Mismatch in URL parameter names
Given I understand your question correctly, you pass the username as a slug to the view, like:
path(
'm/user/<str:slug>/questions/',
views.UserAllQuestionView.as_view(),
name='user_profile_question_all'
),
You name this parameter slug however, but in your view, you call self.kwargs['username']. You thus need to change one of the two. For example:
path(
'm/user/<str:username>/questions/',
views.UserAllQuestionView.as_view(),
name='user_profile_question_all'
),
Furthermore it will probably still not work. If I understand it correctly, your Question class has a ForeignKey to the User model. A User is not the same as its textual representation (for example by means of a username), so the filter will look like:
class UserAllQuestionView(generic.ListView):
model = Question
template_name = 'mechinpy/user_profile_question.html'
context_object_name = 'user_all_questions'
def get_queryset(self):
return Question.objects.filter(user__username=self.kwargs['username'])
Using the user_id instead
That being said, it might be better to user the id of the User instead, which will likely introduce less confusion (for example what if a user manages to use a username with a slash in it, then the URL will no longer work). So a more safe approach might be:
path(
'm/user/<int:userid>/questions/',
views.UserAllQuestionView.as_view(),
name='user_profile_question_all'
),
class UserAllQuestionView(generic.ListView):
model = Question
template_name = 'mechinpy/user_profile_question.html'
context_object_name = 'user_all_questions'
def get_queryset(self):
return Question.objects.filter(user_id=self.kwargs['userid'])
and in the template write it like:
All User Questions
I've created a base api view, which extends from APIView, where I log response time, log request, and other common stuffs.
Now, I also want to add request validation here, using the Serializer defined in sub-class Views. I thought the appropriate place is to put that in dispatch() method. But before I call API.dispatch() method, request.data is not prepared. So, that won't work. Can someone help me in right direction as to how to move validation to a single place?
Here's the class structure:
class BaseView(APIView):
validation_serializer = None
def dispatch(self, request, *args, **kwargs):
# Some code here
# How to use `validation_serializer` here, to validate request data?
# `request.data` is not available here.
response = super(BaseView, self).dispatch(request, *args, **kwargs)
# Some code here
return response
class MyView(BaseView):
validation_serializer = ViewValidationSerializer
def post(self, request, *args, **kwargs):
pass
I thought another approach could be use decorator on the top of post() method. But if only there was an cleaner way, than putting decorators all across the project?
Note: It's similar to the question here: Django - DRF - dispatch method flow. But as per the suggestion there, I don't want to just copy the entire dispatch method from DRF source code.
The method that processes the django request into a DRF request (and adds the request.data property) is the APIView.initialize_request . The APIView.dispatch() method calls it and then proceeds to call the appropriate method handler (post/patch/put).
You can try to do that yourself by calling it and using the returned object:
class BaseView(APIView):
validation_serializer = None
def dispatch(self, request, *args, **kwargs):
request = self.initialize_request(request, *args, **kwargs)
kwargs['context'] = self.get_serializer_context()
serializer = self.validation_serializer(data=request.data, *args, **kwargs)
# use `raise_exception=True` to raise a ValidationError
serializer.is_valid(raise_exception=True)
response = super(BaseView, self).dispatch(request, *args, **kwargs)
return response
However, I would suggest against this, as other functionality of dispatch() probably should be performed prior to handling validation; thus, you could move the above logic to the relevant post/patch/put methods instead.
In these methods you can also use self.request directly since it was already initialized by dispatch().
I think drf-tracking does what you are looking for. You may want to check it out.
I don't think you're going about this the correct way. The best way to log the request, with validation is in your Authentication Class and add the audit log to the request.
Then you can use your APIView to log the render time, against the AuditLog generated in the Authentication Class.
Here's an example using Token Authentication, assuming each request has a header Authorization: Bearer <Token>.
settings.py
...
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'common.authentication.MyTokenAuthenticationClass'
),
...,
}
common/authentication.py
from django.utils import timezone
from django.utils.translation import ugettext_lazy as _
from ipware.ip import get_real_ip
from rest_framework import authentication
from rest_framework import exceptions
from accounts.models import Token, AuditLog
class MyTokenAuthenticationClass(authentication.BaseAuthentication):
def authenticate(self, request):
# Grab the Athorization Header from the HTTP Request
auth = authentication.get_authorization_header(request).split()
if not auth or auth[0].lower() != b'bearer':
return None
# Check that Token header is properly formatted and present, raise errors if not
if len(auth) == 1:
msg = _('Invalid token header. No credentials provided.')
raise exceptions.AuthenticationFailed(msg)
elif len(auth) > 2:
msg = _('Invalid token header. Credentials string should not contain spaces.')
raise exceptions.AuthenticationFailed(msg)
try:
token = Token.objects.get(token=auth[1])
# Using the `ipware.ip` module to get the real IP (if hosted on ElasticBeanstalk or Heroku)
token.last_ip = get_real_ip(request)
token.last_login = timezone.now()
token.save()
# Add the saved token instance to the request context
request.token = token
except Token.DoesNotExist:
raise exceptions.AuthenticationFailed('Invalid token.')
# At this point, insert the Log into your AuditLog table and add to request:
request.audit_log = AuditLog.objects.create(
user_id=token.user,
request_payload=request.body,
# Additional fields
...
)
# Return the Authenticated User associated with the Token
return (token.user, token)
Now, you have access to the AuditLog in your request. So you can log everything before and after validation.
I am using Django-registration-email in my Django project. In there documentation (Django-Registration-Email), I am instructed to add REGISTRATION_EMAIL_REGISTER_SUCCESS_URL in the settings.py. However, this is causing the type error:
'str' object is not callable
In the settings.py, I set the redirect url as such:
REGISTRATION_EMAIL_REGISTER_SUCCESS_URL = '/accounts/register/complete/'
And the the url is copied as such:
url(
r'^accounts/register/$',
RegistrationView.as_view(
template_name='registration/registration_form.html',
form_class=CustomEmailRegistrationForm,
get_success_url=getattr(
settings,'REGISTRATION_EMAIL_REGISTER_SUCCESS_URL',
lambda request, user:'/'),
),
name='registration_register',
),
And the debug information told me that the first error comes from /local/lib/python2.7/site-packages/registration/views.py in form_valid
The indicated error line is
success_url = self.get_success_url(request, new_user)
The whole block is
def form_valid(self, request, form):
new_user = self.register(request, **form.cleaned_data)
success_url = self.get_success_url(request, new_user)
# success_url may be a simple string, or a tuple providing the
# full argument set for redirect(). Attempting to unpack it
# tells us which one it is.
try:
to, args, kwargs = success_url
return redirect(to, *args, **kwargs)
except ValueError:
return redirect(success_url)
The traceback is:
Traceback:
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/core/handlers/base.py" in get_response
114. response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/views/generic/base.py" in view
69. return self.dispatch(request, *args, **kwargs)
File "/Library/Python/2.7/site-packages/registration/views.py" in dispatch
79. return super(RegistrationView, self).dispatch(request, *args, **kwargs)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/views/generic/base.py" in dispatch
87. return handler(request, *args, **kwargs)
File "/Library/Python/2.7/site-packages/registration/views.py" in post
35. return self.form_valid(request, form)
File "/Library/Python/2.7/site-packages/registration/views.py" in form_valid
83. success_url = self.get_success_url(request, new_user)
Exception Type: TypeError at /accounts/register/
Exception Value: 'str' object is not callable
Can anyone help me to solve this issue? Thanks a lot! I am stuck by this problem for one whole day!
OK, when you use
get_success_url=getattr(
settings,'REGISTRATION_EMAIL_REGISTER_SUCCESS_URL',
lambda request, user:'/'),
)
in your url handler, you are setting get_success_url as a string. You are then calling it in form_valid, as a function, trying to pass it variables.
Finally, I find where is the problem: REGISTRATION_EMAIL_REGISTER_SUCCESS_URL is expecting a function rather than a string
So, I should add an one-line function in the settings.py
REGISTRATION_EMAIL_REGISTER_SUCCESS_URL = lambda request, user: '/activate/complete/'
Anyway, I still would like to move to allauth since django-registration-email is no longer maintained.
I'm using python-social-auth in my Django application for authentication via Facebook.
But when a user tries to login, they have been redirected to the Facebook app page, and they click on the "Cancel" button, the following exception appears:
ERROR 2014-01-03 15:32:15,308 base :: Internal Server Error: /complete/facebook/
Traceback (most recent call last):
File "/home/vera/virtualenv/myapp/local/lib/python2.7/site-packages/django/core/handlers/base.py", line 114, in get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/home/vera/virtualenv/myapp/local/lib/python2.7/site-packages/django/views/decorators/csrf.py", line 57, in wrapped_view
return view_func(*args, **kwargs)
File "/home/vera/virtualenv/myapp/local/lib/python2.7/site-packages/social/apps/django_app/utils.py", line 45, in wrapper
return func(request, backend, *args, **kwargs)
File "/home/vera/virtualenv/myapp/local/lib/python2.7/site-packages/social/apps/django_app/views.py", line 21, in complete
redirect_name=REDIRECT_FIELD_NAME, *args, **kwargs)
File "/home/vera/virtualenv/myapp/local/lib/python2.7/site-packages/social/actions.py", line 54, in do_complete
*args, **kwargs)
File "/home/vera/virtualenv/myapp/local/lib/python2.7/site-packages/social/strategies/base.py", line 62, in complete
return self.backend.auth_complete(*args, **kwargs)
File "/home/vera/virtualenv/myapp/local/lib/python2.7/site-packages/social/backends/facebook.py", line 63, in auth_complete
self.process_error(self.data)
File "/home/vera/virtualenv/myapp/local/lib/python2.7/site-packages/social/backends/facebook.py", line 56, in process_error
super(FacebookOAuth2, self).process_error(data)
File "/home/vera/virtualenv/myapp/local/lib/python2.7/site-packages/social/backends/oauth.py", line 312, in process_error
raise AuthCanceled(self, data.get('error_description', ''))
AuthCanceled: Authentication process canceled
Is the any way to catch it Django?
python-social-auth is a newer, derived version of django-social-auth.
AlexYar's answer can be slightly modified to work with python-social-auth by modify settings.py with following changes:
Add a middleware to handle the SocialAuthException
MIDDLEWARE_CLASSES += (
'social.apps.django_app.middleware.SocialAuthExceptionMiddleware',
)
URL to redirect to, when an exception occurred
SOCIAL_AUTH_LOGIN_ERROR_URL = '/'
Note that you also need to set
DEBUG = False
That's all or read http://python-social-auth.readthedocs.org/en/latest/configuration/django.html#exceptions-middleware
you can create a middleware and catch any exceptions,
exception list: https://github.com/omab/python-social-auth/blob/master/social/exceptions.py
in this case your AuthCanceled Exception.
middleware.py
from social.apps.django_app.middleware import SocialAuthExceptionMiddleware
from django.shortcuts import HttpResponse
from social import exceptions as social_exceptions
class SocialAuthExceptionMiddleware(SocialAuthExceptionMiddleware):
def process_exception(self, request, exception):
if hasattr(social_exceptions, 'AuthCanceled'):
return HttpResponse("I'm the Pony %s" % exception)
else:
raise exception
settings.py
MIDDLEWARE_CLASSES = (
.....
'pat_to_middleware.SocialAuthExceptionMiddleware',
)
This is slight modification of #Nicolas answer and this works for me.
middleware.py
from social.apps.django_app.middleware import SocialAuthExceptionMiddleware
from django.shortcuts import render
from social.exceptions import AuthCanceled
class SocialAuthExceptionMiddleware(SocialAuthExceptionMiddleware):
def process_exception(self, request, exception):
if type(exception) == AuthCanceled:
return render(request, "pysocial/authcancelled.html", {})
else:
pass
settings.py
MIDDLEWARE_CLASSES += (
'myapp.middleware.SocialAuthExceptionMiddleware',
)
The 2018 answer:
Add SocialAuthExceptionMiddleware middleware to your config:
MIDDLEWARE_CLASSES = [
...
'social_django.middleware.SocialAuthExceptionMiddleware',
]
Set SOCIAL_AUTH_LOGIN_ERROR_URL in your config:
SOCIAL_AUTH_LOGIN_ERROR_URL = '/login'
Now when you have DEBUG = False, your users will get redirected to your login page when they click cancel in social auth provider's page.
When DEBUG = True you will still see the error page in your browser during development.
Just add in
MIDDLEWARE_CLASSES = (
'social_auth.middleware.SocialAuthExceptionMiddleware',
)
and something like
LOGIN_ERROR_URL = '/'
That's all
or read http://django-social-auth.readthedocs.org/en/latest/configuration.html#exceptions-middleware
If you don't care about handling the exception do the following in your settings.py
SOCIAL_AUTH_RAISE_EXCEPTIONS = False
See this answer: How to solve Authentication process canceled error?
This is a updated imports middleware using social_django
from social_django.middleware import SocialAuthExceptionMiddleware
from social_core import exceptions as social_exceptions
from django.shortcuts import HttpResponse
from django.shortcuts import render, redirect
class FacebookAuthCanceledExceptionMiddleware(SocialAuthExceptionMiddleware):
def process_exception(self, request, exception):
if hasattr(social_exceptions, 'AuthCanceled'):
return redirect('auth_login')
else:
raise exception