django_rest_framework, how to update user profile by token? - django

I have models user and profile(foreight key to user).
Can someone show me(or explain) example how in viewset, update user profile by token.
I send token in HTTP header that name is: "Authorization", and value: "Token " + (token_string).
class ProfileViewSet(viewsets.ModelViewSet):
queryset = Profile.objects.all()
serializer_class = Profileerializer
def update(self, request, pk=None):
# Get user by token and update profile

Based on what you said, I'll asume that you are using Django Rest Framework Token Authentication
If so,
The request.user property will typically be set to an instance of the contrib.auth package's User class.
The request.auth property is used for any additional authentication information, for example, it may be used to represent an authentication token that the request was signed with.
That way, you should be able to do something like:
def update(self, request, pk=None):
user = request.user
profile = user.profile
# Update with user here

Related

Can I provide automatically current user in Django rest API like this?

I have a Django rest api. In my model I have a user as a foreign key. When I do a post with the, I do not want that the user needs to provide his own user. But if the user does not provide his user credentials, the serializer won't be valid and then won't be saved. I have found that we can access to serialized dat before validation with initial_data so I am doing like this to save the user automatically from the token provided. The user need to provide everything except his own user. Is it ok or am I doing something not recommended ?
#api_view(['POST'])
#permission_classes([IsAuthenticated])
def add_mesure(request):
serializer = MesureSerializer(data=request.data)
serializer.initial_data['user'] = request.user.id
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
As you are already taking the token as a form of user verification, hence you can omit the user field from serializer (otherwise user might put someone else's id for example) and then pass the request object to serializer to get user from it during saving. Like this:
#serializer
class MesureSerializer(ModelSerializer):
class Meta:
exclude = ['user',]
...
def create(self, validated_data):
validated_data['user'] = self.context['request'].user
return super().create(validated_data)
Also, to pass the value of request, you can use context parameter of the serializer.
#view
serializer = MesureSerializer(data=request.data, context={'request':request})

Cannot assign "...'": "TestData.user" must be a "User" instance

Very new to the Django Rest Framework, so would appreciate some help with this one. I get the error in the title when I try and do a POST request in Postman with an appropriate auth token.
I've made a table that I want to send a POST request to, but having issues with getting a user FK to be accepted as one of the columns. Plz see model/serializer/view below:
Model
class TestData (models.Model):
TestSDG = models.DecimalField(decimal_places=0, max_digits=2, default=0)
user = models.ForeignKey("auth.User", related_name="testdata", on_delete=models.CASCADE)
Serializer
class TestDataSerializer(serializers.ModelSerializer):
class Meta:
model = TestData
fields = ('id', 'TestSDG')
View
#csrf_exempt
def testDataApi(request, id=0):
if request.method == 'GET':
testdata = TestData.objects.all()
testdata_serializer = TestDataSerializer(testdata,many=True)
return JsonResponse(testdata_serializer.data,safe=False)
elif request.method == 'POST':
testdata_data=JSONParser().parse(request)
testdata_serializer=TestDataSerializer(data=testdata_data)
if testdata_serializer.is_valid():
testdata_serializer.save(user=request.user)
return JsonResponse("Added Successfully", safe=False)
The POST request works fine if I don't use the user as a foreign key, and I change testdata_serializer.save(user=request.user) back to testdata_serializer.save(), but I want the table to require a user's id.
Appreciate any help, thank you.
You should be using a ModelViewset in your views.py file - then you can override the update method on your serializer:
views.py
from rest_framework.viewsets import ModelViewSet
class TestDataViewSet(ModelViewSet):
queryset = TestData.objects.all()
serializer_class = TestDataSerializer
serializers.py
class TestDataSerializer(serializers.ModelSerializer):
...
def update(self, instance, validated_data):
# get user id from validated data:
user_id = validated_data.pop('user_id')
# get user:
user = User.objects.get(id=user_id)
# set user on instance:
instance.user = user
instance.save()
# continue with update method:
super().update(instance, validated_data)
You mentioned that you are using an auth token. Try verifying in your view testDataApi if request.user was correctly set with an auth.User object. Try logging it with something like below to make sure that it is correctly set to the user for the provided token:
#csrf_exempt
def testDataApi(request, id=0):
print(type(request.user), request.user) # Should display the user for the provided token.
...
If it isn't set, then you have to configure how it would correctly map an auth.User object from a provided token. You might want to look at the following:
AuthenticationMiddleware - Sets the request.user object.
AUTHENTICATION_BACKENDS - Custom authentication of a token and then return the associated auth.User object
DEFAULT_AUTHENTICATION_CLASSES - Only if using djangorestframework. Sets the request.user object.
TokenAuthentication, JSONWebTokenAuthentication, etc. - Only if using djangorestframework. Some implementations that authenticates tokens. Perhaps they weren't configured correctly.

How to make self.request.user return the user attached to token?

I am using token authentication in Django Rest Framework, and am passing a token into the header of my request. This token is attached to a user. How would I make it so that when 'self.request.user' is called, the user attached to the token in the request is returned?
Failing this, more specifically I need some sort of way to change the following 'perform_create()' function in my view to instead set 'author' to the user attached to the token.
perform_create() function currently:
def perform_create(self, serializer):
serializer.save(author = self.request.user)
I need it so 'author' is set to the user attached to the token in the header.
Any help would be much appreciated.
Thanks
EDIT: I am unable to use session based authentication in this implementation
I use the exact same code (with type checking at runtime) to get the user model in a token authentication system and can confirm that it works.
def perform_create(self, serializer: ModelSerializer) -> None:
serializer.save(registrant=self.request.user)
registrant is the Foreign Key to the user model:
# models.py
from django.conf import settings
from django.db import models
class Model(models.Model):
# ...
registrant = models.ForeignKey(to=settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, blank=True, null=True)
# ...
EDIT: This is further confirmed in the documentation:
If successfully authenticated, TokenAuthentication provides the following credentials.
request.user will be a Django User instance.
request.auth will be a rest_framework.authtoken.models.Token instance.

User current authentication status check endpoint with django and django rest framework

How could I create an endpoint in django-rest-framework that would facilitate checking whether a given user was currently logged in?
The idea would be to supply the authentication token and user name, then get a response like {"Authenticated": True} or {"Authenticated": False"}.
You can try with this example:
models
class LoggedUser(models.Model):
user = models.ForeignKey('YourUserObject', primary_key=True)
def __unicode__(self):
return self.user
def login_user(sender, request, user, **kwargs):
LoggedUser(user=user).save()
def logout_user(sender, request, user, **kwargs):
try:
u = LoggedUser.objects.get(user=user)
u.delete()
except LoggedUser.DoesNotExist:
pass
user_logged_in.connect(login_user)
user_logged_out.connect(logout_user)
After this you can do serialize class to retrive current loged user.

Django Tastypie Import Error on resources

I have something strange going on that I can't seem to crack. I'm building an API with Tastypie and when I issue this call in my browser against localserver, it works fine: localserver/api/v1/userfavorite/?user__username=testowner
However, in my code, I'm getting an error: "int() argument must be a string or a number, not 'SimpleLazyObject'". I realize it has to do with the user being treated as a request.user object, but I can't figure out where/why. I'm very confused why it works when issuing the API call in the browser, but in the code it is not working.
Here is my code:
# views.py
#login_required
def favorites(request):
'''
display a list of posts that a user has marked as favorite
'''
user = request.user
favorites_url = settings.BASE_URL + "/api/v1/userfavorite/?user__username=" + user.username
favorites = get_json(favorites_url)
return render(request, "maincontent/favorites.html", {'favorites':favorites})
# resources.py
class UserFavoriteResource(ModelResource):
'''
manage post favorites by a user. Users can use a favorites list
to easily view posts that they have liked or deemed important.
'''
user = fields.ForeignKey(UserResource, 'user')
post = fields.ForeignKey('blog.api.resources.PostResource', 'post', full=True)
class Meta:
queryset = UserFavorite.objects.all()
allowed_methods = ['get', 'post', 'delete']
authentication = Authentication()
authorization = Authorization()
filtering = {
'user':ALL_WITH_RELATIONS
}
def hydrate_user(self, bundle):
# build the current user to save for the favorite instance
bundle.data['user'] = bundle.request.user
return bundle
def get_object_list(self, request):
# filter results to the current user
return super(UserFavoriteResource, self).get_object_list(request)\
.filter(user=request.user)
# utils.py
def get_json(url):
# return the raw json from a request without any extraction
data = requests.get(url).json()
return data
Some notes:
1. I have the post method working to create the UserFavorite item
2. I can verify that the favorites_url is being generated correctly
3. I have tried hardcoding the favorites_url as well, same error.
EDIT: 4. I am logged in while doing this, and have verified that request.user returns the user
This doesn't work because there is Anonymous user in your request.user. You are using Authentication it does not require user to be logged in. So if you perform requests call that request is not authenticated and request.user is AnonymousUser and that error occurs when you try to save Anonymous user to db. Tastypie documentation advices to not using browsers to testing things up, just curl instead. Browsers stores a lot of data and yours one probably remembered you have been logged to admin panel in localhost:8000 on another tab that's why it worked in browser.
I would prefer something like this:
def hydrate_user(self, bundle):
"""\
Currently logged user is default.
"""
if bundle.request.method in ['POST', 'PUT']:
if not bundle.request.user.is_authenticated():
raise ValidationError('Must be logged in')
bundle.obj.user = bundle.request.user
bundle.data['user'] = \
'/api/v1/userauth/user/{}'.format(bundle.request.user.pk)
return bundle