Issue encoding an email for my app - python

I am configuring an app that operates subscriptions only with emails, all runs perfectly except a part of my form that should encode all email received.
This is the error obtained when i sign up with an email:
**Unicode-objects must be encoded before hashing**
Traceback: File "/home/draicore/SUNFLOWER/AMBIENTE1/lib/python3.4/site-packages/django/core/handlers/base.py" in get_response
132. response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/home/draicore/SUNFLOWER/AMBIENTE1/lib/python3.4/site-packages/django/views/generic/base.py" in view
71. return self.dispatch(request, *args, **kwargs)
File "/home/draicore/SUNFLOWER/AMBIENTE1/lib/python3.4/site-packages/django/views/generic/base.py" in dispatch
89. return handler(request, *args, **kwargs)
File "/home/draicore/SUNFLOWER/AMBIENTE1/lib/python3.4/site-packages/django/views/generic/edit.py" in post
214. if form.is_valid():
File "/home/draicore/SUNFLOWER/AMBIENTE1/lib/python3.4/site-packages/django/forms/forms.py" in is_valid
184. return self.is_bound and not self.errors
File "/home/draicore/SUNFLOWER/AMBIENTE1/lib/python3.4/site-packages/django/forms/forms.py" in errors
176. self.full_clean()
File "/home/draicore/SUNFLOWER/AMBIENTE1/lib/python3.4/site-packages/django/forms/forms.py" in full_clean
393. self._clean_form()
File "/home/draicore/SUNFLOWER/AMBIENTE1/lib/python3.4/site-packages/django/forms/forms.py" in _clean_form
417. cleaned_data = self.clean()
File "/home/draicore/SUNFLOWER/GIRASOL/apps/newsletter/forms.py" in clean
47. self.cleaned_data['activation_key'] = generate_activation_key(data['email'])
File "/home/draicore/SUNFLOWER/GIRASOL/apps/newsletter/forms.py" in generate_activation_key
16. salt = hashlib.md5(str(random.random())).hexdigest()[:10]
Exception Type: TypeError at /request/
Exception Value: Unicode-objects must be encoded before hashing
I have this code that is responsible of encoding emails on my forms.py:
def generate_activation_key(email):
if isinstance(email, str):
email = email.encode('utf-8')
salt = hashlib.md5(str(random.random()).encode('utf-8')).hexdigest()[:10]
return hashlib.md5(salt+email).hexdigest()
class EmailSubscriberForm(forms.ModelForm):
email = forms.EmailField(max_length=256, label=_('Email'), required=True)
captcha = CaptchaField(label=_('Security code'))
activation_key = forms.CharField(widget=forms.HiddenInput(), required=False)
activation_request_sent_at = forms.DateField(widget=forms.HiddenInput(), required=False)
class Meta:
model = EmailSubscriber
fields = (
'email',
'activation_key',
'activation_request_sent_at',
)
def clean_email(self):
email = self.cleaned_data['email'].strip()
try:
self.instance = EmailSubscriber.objects.get(email__iexact=email)
if self.instance is not None:
return email.lower()
except EmailSubscriber.DoesNotExist:
return email.lower()
raise forms.ValidationError(_('This email is already subscribed.'))
def clean(self):
data = self.cleaned_data
if 'email' in data:
self.cleaned_data['activation_key'] = generate_activation_key(data['email'])
self.cleaned_data['activation_request_sent_at'] = timezone.now()
return self.cleaned_data
I believe that this issue is caused for an incompatibility of version of python (i have Python 3.4.1) and i was trying to looking for solutions here in other questions and i found answers that say about a new format to set the .encode('utf-8'). and I dont know what i should change.
apologizeme in advance if I overlook something. Any contribution is wellcome, Thanks for evaluate!
Have a great day!!

You should also encode your random salt string:
str(random.random()).encode('utf-8')
However, then you'll receive a new error...because email is bytes and salt is a string. I'll leave it up to you to determine how you want to normalize these so that they can be added together.

Related

How to solve a attribute error in Django?

I am trying to log in a user but I am getting an attribute error.
Here is my forms.py:
class Login(forms.Form):
email = forms.EmailField(max_length=250)
password = forms.CharField(widget=forms.PasswordInput)
def login_user(self):
email = self.cleaned_data['email']
password = self.cleaned_data.get('password')
user = authenticate(email=email, password=password)
if user in User.objects.all():
login(self, user)
else:
return render(self, 'todoapp/waiting_2.html')
Here is my views.py:
def login_user(request):
if request.method == 'POST':
login_form = Login(request.POST)
if login_form.is_valid():
login_form.login_user()
login_form.save()
return HttpResponseRedirect(reverse('dashboard'))
else:
return render(request, 'todoapp/waiting_2.html')
return render(request, 'registration/login.html', {'form': Login()})
When I fill in the fields and try to log in, I am getting the error:
AttributeError at /login/
'Login' object has no attribute 'session'
Traceback:
File "/home/gblp250/PycharmProjects/practice/venv/local/lib/python2.7/site-packages/django/core/handlers/exception.py" in inner
41. response = get_response(request)
File "/home/gblp250/PycharmProjects/practice/venv/local/lib/python2.7/site-packages/django/core/handlers/base.py" in _get_response
187. response = self.process_exception_by_middleware(e, request)
File "/home/gblp250/PycharmProjects/practice/venv/local/lib/python2.7/site-packages/django/core/handlers/base.py" in _get_response
185. response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/home/gblp250/PycharmProjects/assignment/todoapp/views.py" in login_user
48. login_form.login_user(request)
File "/home/gblp250/PycharmProjects/assignment/todoapp/forms.py" in login_user
27. login(self, request, user)
File "/home/gblp250/PycharmProjects/practice/venv/local/lib/python2.7/site-packages/django/contrib/auth/__init__.py" in login
126. if SESSION_KEY in request.session:
Exception Type: AttributeError at /login/
Exception Value: 'Login' object has no attribute 'session'
There are a few errors here. The main one of attempting to render within the form login_user method. Apart from anything else, you attempt to pass the self as the request parameter to render, which mages no sense.
Remove all of that if/else. You don't need to render; but also note that your if condition is needlessly inefficient. If you get a user, it's necessarily a User.
Finally, the actual cause of your error, where again you are trying to pass self in the place of a request, but this time as the parameter to login. That code belongs in the view.
And finally, the form is not a ModelForm, so there is no save method.
So, form:
def login_user(self):
email = self.cleaned_data['email']
password = self.cleaned_data.get('password')
return authenticate(email=email, password=password)
and view:
if login_form.is_valid():
user = login_form.login_user()
if user:
login(request, user)
return HttpResponseRedirect(reverse('dashboard'))
Although at this point you may as well move all that logic to the view.
login() get as first argument the request, you call it with the form as first argument.
https://docs.djangoproject.com/en/2.1/topics/auth/default/#django.contrib.auth.login

How to pass username in kwargs of Django filter?

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

NotImplementedError: Django doesn't provide a DB representation for AnonymousUser

I get the following error:
Traceback:
File "C:\Users\HP\GST\lib\site-packages\django\core\handlers\exception.py"
in inner
35. response = get_response(request)
File "C:\Users\HP\GST\lib\site-packages\django\core\handlers\base.py" in
_get_response
128. response = self.process_exception_by_middleware(e,
request)
File "C:\Users\HP\GST\lib\site-packages\django\core\handlers\base.py" in
_get_response
126. response = wrapped_callback(request, *callback_args,
**callback_kwargs)
File "C:\Users\HP\Desktop\erpcloud\accounts\views.py" in change_password
31. if form.is_valid():
File "C:\Users\HP\GST\lib\site-packages\django\forms\forms.py" in is_valid
179. return self.is_bound and not self.errors
File "C:\Users\HP\GST\lib\site-packages\django\forms\forms.py" in errors
174. self.full_clean()
File "C:\Users\HP\GST\lib\site-packages\django\forms\forms.py" in
full_clean
376. self._clean_fields()
File "C:\Users\HP\GST\lib\site-packages\django\forms\forms.py" in
_clean_fields
397. value = getattr(self, 'clean_%s' % name)()
File "C:\Users\HP\GST\lib\site-packages\django\contrib\auth\forms.py" in
clean_old_password
366. if not self.user.check_password(old_password):
File "C:\Users\HP\GST\lib\site-packages\django\contrib\auth\models.py" in
check_password
396. raise NotImplementedError("Django doesn't provide a DB
representation for AnonymousUser.")
Exception Type: NotImplementedError at /accounts/change-password/
Exception Value: Django doesn't provide a DB representation for
AnonymousUser.
My view looks like this:
def change_password(request):
if request.method == 'POST':
form = PasswordChangeForm(data=request.POST, user=request.user)
if form.is_valid():
form.save()
update_session_auth_hash(request, user)
return redirect(reverse('company:Dashboard'))
else:
return redirect(reverse('accounts:change_password'))
else:
form = PasswordChangeForm(user=request.user)
args = {'form': form}
return render(request, 'accounts/change_password.html', args)
Firstly, I thought that this was due to the fact that I didn't have Django updated, but now I have, and I receive the same error.
I've looked at some solutions that other users asked, but none applied in my case
Any help, please ?
There is nothing wrong with the view itself. The problem is that if a user is not logged in, then request.user will point to a AnonymousUser object. You can see it as a virtual user. This user however has no database representation, since we do not know anything about the user. It is more used to provide a uniform interface.
Now since request.user is an AnonymousUser, you aim to change the password of that user, but you can not store that into a database, hence the error.
The user thus first needs to log in, then request.user will be a real user, and updating the password should work.
I advise however to add a #login_required decorator to the view to prevent this scenario from happening:
from django.contrib.auth.decorators import login_required
#login_required
def change_password(request):
if request.method == 'POST':
form = PasswordChangeForm(data=request.POST, user=request.user)
if form.is_valid():
form.save()
update_session_auth_hash(request, user)
return redirect(reverse('company:Dashboard'))
else:
return redirect(reverse('accounts:change_password'))
else:
form = PasswordChangeForm(user=request.user)
args = {'form': form}
return render(request, 'accounts/change_password.html', args)

Django Registration 'str' object is not callable

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.

Django TastyPie: how do I return something other than 500 for UnsupportedFormat?

Using Django TastyPie, when I give a non-JSON request to an API that only accepts JSON, I get a 500 error and a repsonse containing this traceback:
Traceback (most recent call last):
File ".../lib/python3.3/site-packages/tastypie/resources.py", line 195, in wrapper
response = callback(request, *args, **kwargs)
File ".../lib/python3.3/site-packages/tastypie/resources.py", line 426, in dispatch_list
return self.dispatch('list', request, **kwargs)
File ".../lib/python3.3/site-packages/tastypie/resources.py", line 458, in dispatch
response = method(request, **kwargs)
File ".../lib/python3.3/site-packages/tastypie/resources.py", line 1317, in post_list
deserialized = self.deserialize(request, request.body, format=request.META.get('CONTENT_TYPE', 'application/json'))
File ".../lib/python3.3/site-packages/tastypie/resources.py", line 375, in deserialize
deserialized = self._meta.serializer.deserialize(data, format=request.META.get('CONTENT_TYPE', 'application/json'))
File ".../lib/python3.3/site-packages/tastypie/serializers.py", line 219, in deserialize
raise UnsupportedFormat("The format indicated '%s' had no available deserialization method. Please check your ``formats`` and ``content_types`` on your Serializer." % format)
tastypie.exceptions.UnsupportedFormat: The format indicated 'application/x-www-form-urlencoded' had no available deserialization method. Please check your ``formats`` and ``content_types`` on your Serializer.
I have no intentions of adding support for formdata, so 500 (internal server error) seems inappropriate compared to 400 (bad request) or 415 (unsupported media type). But I can't seem to figure out how you're supposed to specify to TastyPie to return those codes. Is this something that is a feature of TastyPie I haven't found, or am I going to have to hand-roll this functionality?
Part 1 - Serialization
You can create parent resource with extra deserialization:
class ExtraPostResource(object):
def deserialize(self, request, data, format=None):
"""
Changes request stat in to python objects
"""
if not format:
format = request.META.get('CONTENT_TYPE', 'application/json')
if format == 'application/x-www-form-urlencoded':
return request.POST
if format.startswith('multipart'):
multipart_data = request.POST.copy()
multipart_data.update(request.FILES)
return multipart_data
return super(ExtraPostResource, self).deserialize(request, data, format)
Then apply it to resources where you need:
class MyModel(ExtraPostResource, ModelResource):
class Meta:
serializer = Serializer(formats=['json'])
queryset = MyModel.objects.all()
resource_name = 'my_model'
I didn't test the example with application/x-www-form-urlencoded but multipart works perfect for me.
Now part 2 - about 500s
If you want to handle 500s.
try:
from django.views.decorators.csrf import csrf_exempt
except ImportError:
def csrf_exempt(func):
return func
class MyBaseModelResource(ModelResource):
"""
Basically it defines own error feedback format.
"""
def wrap_view(self, view):
"""
Wraps views to return custom error codes instead of generic 500's.
"""
#csrf_exempt
def wrapper(request, *args, **kwargs): # * see annotation below.
try:
callback = getattr(self, view)
response = callback(request, *args, **kwargs)
if request.is_ajax():
patch_cache_control(response, no_cache=True)
return response
# You can handle here many more.
# [...]
except UnsupportedFormat, e:
return self.create_response(
request,
{'success': False,
'code': 123,
'message': e},
response_class=HttpBadRequest, # HttpForbidden, HttpUnauthorized etc.
)
except Exception, e:
# Rather than re-raising, we're going to things similar to
# what Django does. The difference is returning a serialized
# error message.
return self._handle_500(request, e)
return wrapper
*(1) Worth saying is that the version of wrapper method may be slightly or much different grading to version of Tastypie which you currently use. And you must check it.
You have to create your own Serializer class and use that for the resources.
class JsonOnlySerializer(Serializer):
# limit the available formats
formats = ['json']
content_types = {'json': 'application/json'}
# catch the Unsupported exception and raise BadRequest
def deserialize(self, content, format='application/json'):
try:
return super(SafeJsonSerializer, self).deserialize(content, format)
except UnsupportedFormat as e:
raise BadRequest("Unsupported content type (%s)." % format)
Then use it for the resource's config:
class MyModel(ModelResource):
class Meta:
queryset = MyModel.objects.all()
serializer = JsonOnlySerializer()

Categories

Resources