RawPostDataException: You cannot access body after reading from request's data stream - python

I am hosting a site on Google Cloud and I got everything to work beautifully and then all of the sudden I start getting this error..
01:16:22.222
Internal Server Error: /api/v1/auth/login/ (/base/data/home/apps/s~crs-portal/1.395605052160854207/lib/django/core/handlers/exception.py:124)
Traceback (most recent call last):
File "/base/data/home/apps/s~crs-portal/1.395605052160854207/lib/django/core/handlers/exception.py", line 39, in inner
response = get_response(request)
File "/base/data/home/apps/s~crs-portal/1.395605052160854207/lib/django/core/handlers/base.py", line 249, in _legacy_get_response
response = self._get_response(request)
File "/base/data/home/apps/s~crs-portal/1.395605052160854207/lib/django/core/handlers/base.py", line 187, in _get_response
response = self.process_exception_by_middleware(e, request)
File "/base/data/home/apps/s~crs-portal/1.395605052160854207/lib/django/core/handlers/base.py", line 185, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/base/data/home/apps/s~crs-portal/1.395605052160854207/lib/django/views/decorators/csrf.py", line 58, in wrapped_view
return view_func(*args, **kwargs)
File "/base/data/home/apps/s~crs-portal/1.395605052160854207/lib/django/views/generic/base.py", line 68, in view
return self.dispatch(request, *args, **kwargs)
File "/base/data/home/apps/s~crs-portal/1.395605052160854207/lib/rest_framework/views.py", line 474, in dispatch
response = self.handle_exception(exc)
File "/base/data/home/apps/s~crs-portal/1.395605052160854207/lib/rest_framework/views.py", line 434, in handle_exception
self.raise_uncaught_exception(exc)
File "/base/data/home/apps/s~crs-portal/1.395605052160854207/lib/rest_framework/views.py", line 471, in dispatch
response = handler(request, *args, **kwargs)
File "/base/data/home/apps/s~crs-portal/1.395605052160854207/authentication/views.py", line 42, in post
data = json.loads(request.body)
File "/base/data/home/apps/s~crs-portal/1.395605052160854207/lib/rest_framework/request.py", line 359, in __getattribute__
return getattr(self._request, attr)
File "/base/data/home/apps/s~crs-portal/1.395605052160854207/lib/django/http/request.py", line 263, in body
raise RawPostDataException("You cannot access body after reading from request's data stream")
RawPostDataException: You cannot access body after reading from request's data stream
I have no clue what this means, and endless googling has not solved my case in anyway..
Here's the code that is probably relevant:
views.py
class LoginView(views.APIView):
def post(self, request, format=None):
data = json.loads(request.body)
email = data.get('email', None)
password = data.get('password', None)
account = authenticate(email=email, password=password)
if account is not None:
if account.is_active:
login(request, account)
serialized = AccountSerializer(account)
return Response(serialized.data)
else:
return Response({
'status': 'Unauthorized',
'message': 'This account has been disabled.'
}, status=status.HTTP_401_UNAUTHORIZED)
else:
return Response({
'status': 'Unauthorized',
'message': 'Username/password combination invalid.'
}, status=status.HTTP_401_UNAUTHORIZED)
serializer.py
class AccountSerializer(serializers.ModelSerializer):
password = serializers.CharField(write_only=True, required=False)
confirm_password = serializers.CharField(write_only=True, required=False)
class Meta:
model = Account
fields = ('id', 'email', 'username', 'created_at', 'updated_at', 'full_name', 'password', 'confirm_password')
read_only_fields = ('created_at', 'updated_at',)
def create(self, validated_data):
return Account.objects.create(**validated_data)
def update(self, instance, validated_data):
instance.username = validated_data.get('username', instance.username)
instance.save()
password = validated_data.get('password', None)
confirm_password = validated_data.get('confirm_password', None)
if password and confirm_password and password == confirm_password:
instance.set_password(password)
instance.save()
update_session_auth_hash(self.context.get('request'), instance)
return instance

This is occuring is because you are trying to access the data from body
use -> data = json.loads(request.data)

Use request.data instead of request.body.
request.data does not read the data stream again.

hey thanks for the response but I figured it out! It wasn't working because I found a small bug where I am able to access the login page even though I am already logged in, so the error was caused by trying to login again. I fixed the issue by redirecting to home page if login page is tried to be reached

Related

Problen with generating token in login

Hello I would like help I have been trying to learn how to create token with django rest framework and pyjwt
But whenever I do it when I am going to use login it gives me an error I would like to know if it is due to the code since I have seen several videos and I have the same code or it is due to something on my computer and if so, how could I solve it, the error is the next
Internal Server Error: /api/login
Traceback (most recent call last):
File "D:\Users\ferna\Documents\Cursos\Youtube\auth.env\lib\site-packages\django\core\handlers\exception.py", line 47, in inner
response = get_response(request)
File "D:\Users\ferna\Documents\Cursos\Youtube\auth.env\lib\site-packages\django\core\handlers\base.py", line 181, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "D:\Users\ferna\Documents\Cursos\Youtube\auth.env\lib\site-packages\django\views\decorators\csrf.py", line 54, in wrapped_view
return view_func(*args, **kwargs)
File "D:\Users\ferna\Documents\Cursos\Youtube\auth.env\lib\site-packages\django\views\generic\base.py", line 70, in view
return self.dispatch(request, *args, **kwargs)
File "D:\Users\ferna\Documents\Cursos\Youtube\auth.env\lib\site-packages\rest_framework\views.py", line 509, in dispatch
response = self.handle_exception(exc)
File "D:\Users\ferna\Documents\Cursos\Youtube\auth.env\lib\site-packages\rest_framework\views.py", line 469, in handle_exception
self.raise_uncaught_exception(exc)
File "D:\Users\ferna\Documents\Cursos\Youtube\auth.env\lib\site-packages\rest_framework\views.py", line 480, in raise_uncaught_exception
raise exc
File "D:\Users\ferna\Documents\Cursos\Youtube\auth.env\lib\site-packages\rest_framework\views.py", line 506, in dispatch
response = handler(request, *args, **kwargs)
File "D:\Users\ferna\Documents\Cursos\Youtube\auth\users\views.py", line 37, in post
token = jwt.encode(payload, 'secret', algorithm='HS256').decode('utf-8')
AttributeError: 'str' object has no attribute 'decode'
[07/May/2021 21:18:23] ←[35;1m"POST /api/login HTTP/1.1" 500 96900←[0m
the code for view it's
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.exceptions import AuthenticationFailed
from .serializers import UserSerializer
from .models import User
import jwt, datetime
# Create your views here.
class RegisterView(APIView):
def post(self, request):
serializer = UserSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data)
class LoginView(APIView):
def post(self, request):
email = request.data['email']
password = request.data['password']
user = User.objects.filter(email=email).first()
if user is None:
raise AuthenticationFailed('User not found!')
if not user.check_password(password):
raise AuthenticationFailed('Incorrect password!')
payload = {
'id': user.id,
'exp': datetime.datetime.utcnow() + datetime.timedelta(minutes=60),
'iat': datetime.datetime.utcnow()
}
token = jwt.encode(payload, 'secret', algorithm='HS256').decode('utf-8')
response = Response()
response.set_cookie(key='jwt', value=token, httponly=True)
response.data = {
'jwt': token
}
return response
I found actual problem.
The package PyJWT changed return type of jwt.encode(...) with version 2. From now it returns string instead of byte string. Link
After that use these codes:
encoded = jwt.encode({"some": "payload"}, key, algorithm="HS256")
result = jwt.decode(encoded, key, algorithms="HS256")
instead of that this:
result = jwt.encode(payload, 'secret', algorithm='HS256').decode('utf-8')

ModelBackend authenticate doesn't receive credentials when using Admin Panel

I've setup a custom backend with the following configuration:
Settings.py;
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework_simplejwt.authentication.JWTAuthentication',
'users.backends.CustomUserBackend',
'django.contrib.auth.backends.ModelBackend',
),
}
AUTHENTICATION_BACKENDS = ('users.backends.CustomUserBackend',)
backends.py
class CustomUserBackend(ModelBackend):
def authenticate(self, request, username=None, password=None, **kwargs):
if username is None:
username = request.data.get("username")
if password is None:
password = request.data.get("password")
....
return None
def get_user(self, user_id):
try:
return User.objects.get(pk=user_id)
except User.DoesNotExist:
return None
When submitting a request via my API this works as expected and authenticates the user correctly etc. My problem comes when I try and log into the admin panel. The stack trace I'm getting when trying to login is caused by an exception when trying to access request.data which is because it's not the correct type to look at, which is correct to how my logic works.
The problem is the authenticate method in here;
def authenticate(request=None, **credentials):
"""
If the given credentials are valid, return a User object.
"""
for backend, backend_path in _get_backends(return_tuples=True):
print(backend)
try:
inspect.getcallargs(backend.authenticate, request, **credentials)
except TypeError:
# This backend doesn't accept these credentials as arguments. Try the next one.
continue
try:
user = backend.authenticate(request, )
except PermissionDenied:
# This backend says to stop in our tracks - this user should not be allowed in at all.
break
if user is None:
continue
# Annotate the user object with the path of the backend.
user.backend = backend_path
return user
# The credentials supplied are invalid to all backends, fire signal
user_login_failed.send(sender=__name__, credentials=_clean_credentials(credentials), request=request)
In here, credentials has the login data {'username': 'dan', 'password': '12345'}. If I understand this method correctly (my python is knowledge is limited) it's not finding my authenticate method in my backend with the correct parameters so it's falling back to the default?
Full stack trace from the login error;
Traceback (most recent call last):
File ".../env/lib/python3.7/site-packages/django/core/handlers/exception.py", line 34, in inner
response = get_response(request)
File ".../env/lib/python3.7/site-packages/django/core/handlers/base.py", line 115, in _get_response
response = self.process_exception_by_middleware(e, request)
File ".../env/lib/python3.7/site-packages/django/core/handlers/base.py", line 113, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File ".../env/lib/python3.7/site-packages/django/views/decorators/cache.py", line 44, in _wrapped_view_func
response = view_func(request, *args, **kwargs)
File ".../env/lib/python3.7/site-packages/django/contrib/admin/sites.py", line 407, in login
return LoginView.as_view(**defaults)(request)
File ".../env/lib/python3.7/site-packages/django/views/generic/base.py", line 71, in view
return self.dispatch(request, *args, **kwargs)
File ".../env/lib/python3.7/site-packages/django/utils/decorators.py", line 43, in _wrapper
return bound_method(*args, **kwargs)
File ".../env/lib/python3.7/site-packages/django/views/decorators/debug.py", line 76, in sensitive_post_parameters_wrapper
return view(request, *args, **kwargs)
File ".../env/lib/python3.7/site-packages/django/utils/decorators.py", line 43, in _wrapper
return bound_method(*args, **kwargs)
File ".../env/lib/python3.7/site-packages/django/utils/decorators.py", line 130, in _wrapped_view
response = view_func(request, *args, **kwargs)
File ".../env/lib/python3.7/site-packages/django/utils/decorators.py", line 43, in _wrapper
return bound_method(*args, **kwargs)
File ".../env/lib/python3.7/site-packages/django/views/decorators/cache.py", line 44, in _wrapped_view_func
response = view_func(request, *args, **kwargs)
File ".../env/lib/python3.7/site-packages/django/contrib/auth/views.py", line 63, in dispatch
return super().dispatch(request, *args, **kwargs)
File ".../env/lib/python3.7/site-packages/django/views/generic/base.py", line 97, in dispatch
return handler(request, *args, **kwargs)
File ".../env/lib/python3.7/site-packages/django/views/generic/edit.py", line 141, in post
if form.is_valid():
File ".../env/lib/python3.7/site-packages/django/forms/forms.py", line 180, in is_valid
return self.is_bound and not self.errors
File ".../env/lib/python3.7/site-packages/django/forms/forms.py", line 175, in errors
self.full_clean()
File ".../env/lib/python3.7/site-packages/django/forms/forms.py", line 377, in full_clean
self._clean_form()
File ".../env/lib/python3.7/site-packages/django/forms/forms.py", line 404, in _clean_form
cleaned_data = self.clean()
File ".../env/lib/python3.7/site-packages/django/contrib/auth/forms.py", line 214, in clean
self.user_cache = authenticate(self.request, username=username, password=password)
File ".../env/lib/python3.7/site-packages/django/contrib/auth/__init__.py", line 74, in authenticate
user = backend.authenticate(request, )
File ".../users/backends.py", line 12, in authenticate
username = request.data.get("username")
AttributeError: 'WSGIRequest' object has no attribute 'data'
I've temporarily fixed this by adding to the authenticate method;
def authenticate(request=None, **credentials):
"""
If the given credentials are valid, return a User object.
"""
for backend, backend_path in _get_backends(return_tuples=True):
try:
inspect.getcallargs(backend.authenticate, request, **credentials)
except TypeError:
# This backend doesn't accept these credentials as arguments. Try the next one.
continue
try:
user = backend.authenticate(request, **credentials)
except PermissionDenied:
# This backend says to stop in our tracks - this user should not be allowed in at all.
break
if user is None:
continue
# Annotate the user object with the path of the backend.
user.backend = backend_path
return user
# The credentials supplied are invalid to all backends, fire signal
user_login_failed.send(sender=__name__, credentials=_clean_credentials(credentials), request=request)
So now the user = backend.authenticate(request, **credentials) method takes the credentials, once logged into the admin panel I can remove this line but would ideally like to know why it's doing it still.

AttributeError at /notify/notify/ 'UserNotifications' object has no attribute 'user'

I am trying to make a notifications app. I have a middle that collects info about the action the user should be notified about and in the view that handles the action it automatically creates an instance in the UserNotification model. This is all working. Now, if a user's post gets liked by another user, that actions needs to be displayed on the notifications page. However, I obviously don't want any one use to be able to see every notification that is being created on the site, but rather only the notifications that are created by their posts.
I am running into an issue with the view and filtering the notifications based on the current user. More specifically, I am getting this error:
AttributeError at /notify/notify/
'UserNotifications' object has no attribute 'user'
With traceback:
Traceback (most recent call last):
File "/anaconda3/envs/dev/lib/python3.6/site-packages/django/core/handlers/exception.py", line 41, in inner
response = get_response(request)
File "/anaconda3/envs/dev/lib/python3.6/site-packages/django/core/handlers/base.py", line 187, in _get_response
response = self.process_exception_by_middleware(e, request)
File "/anaconda3/envs/dev/lib/python3.6/site-packages/django/core/handlers/base.py", line 185, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/anaconda3/envs/dev/lib/python3.6/site-packages/django/views/generic/base.py", line 68, in view
return self.dispatch(request, *args, **kwargs)
File "/anaconda3/envs/dev/lib/python3.6/site-packages/django/contrib/auth/mixins.py", line 56, in dispatch
return super(LoginRequiredMixin, self).dispatch(request, *args, **kwargs)
File "/anaconda3/envs/dev/lib/python3.6/site-packages/django/views/generic/base.py", line 88, in dispatch
return handler(request, *args, **kwargs)
File "/anaconda3/envs/dev/lib/python3.6/site-packages/django/views/generic/list.py", line 160, in get
self.object_list = self.get_queryset()
File "/Users/garrettlove/Desktop/evverest/notify/views.py", line 30, in get_queryset
return UserNotification.objects.filter(user=request.user)
Here is my view pertaining to this:
// Bunch of imports are all here
User = get_user_model()
class UserNotifications(LoginRequiredMixin,ListView):
login_url = 'account_login'
model = UserNotification
template_name = 'notify/usernotification_list.html'
context_object_name = 'notifies'
paginate_by = 25
def get_queryset(request):
return UserNotification.objects.filter(user=request.user)
Here is my UserNotification model:
from django.db import models
from django.contrib.auth import get_user_model
from django.db.models.signals import post_save
from django.dispatch import receiver
User = get_user_model()
# Create your models here.
class UserNotification(models.Model):
user = models.ForeignKey(User,related_name='user',null=True)
post = models.ForeignKey('feed.UserPost',related_name='post')
timestamp = models.DateTimeField(auto_now_add=True)
notify_type = models.CharField(max_length=6)
read = models.BooleanField(default=False)
def __str__(self):
return str(self.user)
def get_queryset(self):
return UserNotification.objects.filter(user=self.request.user)

Django Boolean Field used in view.py

I am trying to add a feature to where a new user needs to update his/her password on an initial login. I added a hidden BooleanField to my Profile model where default = True.
models.py
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
force_password_change = models.BooleanField(default=True)
However, when trying to use force_password_change in my views.py, it never returns the correct value that I set in django's admin page.
views.py
if request.method == 'POST':
...
user = authenticate(request, username=username, password=password)
changepass = UserProfile.objects.get(user=request.user)
if user:
if changepass.force_password_change == True:
changepass.force_password_change = False
changepass.save()
return HttpResponseRedirect('/login/register/')
elif changepass.force_password_change == False:
if user.is_active:
login(request, user)
return HttpResponseRedirect('/main/')
else:
return HttpResponse("Your account has been disabled.")
It is currently giving me this error
Traceback (most recent call last):
File "C:\Python34\lib\site-packages\django\core\handlers\exception.py", line
41, in inner
response = get_response(request)
File "C:\Python34\lib\site-packages\django\core\handlers\base.py", line 187,
in _get_response
response = self.process_exception_by_middleware(e, request)
File "C:\Python34\lib\site-packages\django\core\handlers\base.py", line 185,
in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "start\views.py", line 20, in user_login
changepass = UserProfile.objects.get(user=request.user)
File "C:\Python34\lib\site-packages\django\db\models\manager.py", line 85,
in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "C:\Python34\lib\site-packages\django\db\models\query.py", line 380, in
get
self.model._meta.object_name
start.models.DoesNotExist: UserProfile matching query does not exist.
I also added AUTH_PROFILE_MODULE = 'start.UserProfile' to my settings.py, so that does not seem to be the problem.
You are forgetting to create UserProfile with the respected user
from django.db.models.signals import post_save
from models import UserProfile
from django.contrib.auth.models import User
def register(request):
if request.method == 'POST':
uf = UserForm(request.POST, prefix='user')
upf = UserProfileForm(request.POST, prefix='userprofile')
if uf.is_valid() and upf.is_valid():
user = uf.save()
userprofile = upf.save(commit=False)
userprofile.user = user
userprofile.save() # Are you missing this line ??
return django.http.HttpResponseRedirect(…something…)
This has nothing to do with boolean fields. The error is telling you that your specific User does not have a related entry in the UserProfile table.

Where has cleaned_data vanished in Django 1.11?

I have created an inlineformset_factory as below :
formset = inlineformset_factory(Author, Book, form=BookForm,
formset=BaseBookFormSet,
can_order=False, can_delete=True,
extra=1, fields=('id', name)
)
BookForm is as below:
class BookForm(forms.ModelForm):
name = forms.Charfield(required=True)
def __init__(self, *args, **kwargs):
super(BookForm, self).__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.form_tag = False
self.helper.layout = Layout(
Div(
Field("id", type="hidden"),
Field("name"),
Field("DELETE")
)
)
class Meta:
model = Book
fields = ('id', 'name')
def clean_name(self):
book_name = self.cleaned_data['name']
try:
book = Book.objects.get(name=book_name)
return book
except:
return book_name
def clean(self):
cleaned_data = super(BookForm, self).clean()
... other operations on cleaned_data ...
def has_changed(self):
changed = super(BookForm, self).has_changed()
cleaned_data = self.clean()
... other code here ...
This is throwing an error on submitting the form :
Exception Type: AttributeError
Exception Value: 'BookForm' object has no attribute 'cleaned_data'
when formset.is_valid() is called in views.py. Traceback first shows the line in has_changed where the self.clean is being called, and then the line in clean() where the super clean is being called.
This used to work fine in django 1.10.
When I tried printing dir(self) in Django 1.10 it does show 'cleaned_data' as one of the attributes where as in Django 1.11 it does not.
Where has the 'cleaned_data' vanished in Django 1.11?
EDIT: Adding traceback:
Traceback (most recent call last):
File "/home/vagrant/venv/local/lib/python2.7/site-packages/django/core/handlers/exception.py", line 41, in inner
response = get_response(request)
File "/home/vagrant/venv/local/lib/python2.7/site-packages/django/core/handlers/base.py", line 249, in _legacy_get_response
response = self._get_response(request)
File "/home/vagrant/venv/local/lib/python2.7/site-packages/django/core/handlers/base.py", line 187, in _get_response
response = self.process_exception_by_middleware(e, request)
File "/home/vagrant/venv/local/lib/python2.7/site-packages/django/core/handlers/base.py", line 185, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/home/vagrant/venv/local/lib/python2.7/site-packages/django/views/generic/base.py", line 68, in view
return self.dispatch(request, *args, **kwargs)
File "/home/vagrant/venv/local/lib/python2.7/site-packages/django/views/generic/base.py", line 88, in dispatch
return handler(request, *args, **kwargs)
File "/vagrant/test_os/inventory/views.py", line 297, in post
if formset.is_valid():
File "/home/vagrant/venv/local/lib/python2.7/site-packages/django/forms/formsets.py", line 321, in is_valid
self.errors
File "/home/vagrant/venv/local/lib/python2.7/site-packages/django/forms/formsets.py", line 295, in errors
self.full_clean()
File "/home/vagrant/venv/local/lib/python2.7/site-packages/django/forms/formsets.py", line 345, in full_clean
if not form.has_changed():
File "/vagrant/test_os/inventory/forms.py", line 220, in has_changed
cleaned_data = self.clean()
File "/vagrant/test_os/inventory/forms.py", line 177, in clean
cleaned_data = super(BookForm, self).clean()
File "/home/vagrant/venv/local/lib/python2.7/site-packages/django/forms/models.py", line 344, in clean
return self.cleaned_data
AttributeError: 'BookForm' object has no attribute 'cleaned_data'
Formsets were fixed in 1.11 (in #26844) to ignore empty forms when validating the minimum number of forms. As a side-effect, formsets now call form.has_changed() on each form before validating the form. Django expects form.has_changed() to be safe to call before the form is validated, and the default implementation is indeed safe to call.
You have overridden form.has_changed() to call self.clean(), which now happens before the form is validated. Since form.clean() requires that the form is validated, this fails.
Since form.full_clean() actually calls self.has_changed(), you can't simply validate the form from within form.has_changed(). You don't show what you do in has_changed(), but it would most likely be a good idea to put this code elsewhere.

Categories