How to get user id from JWT token.
My JWT token has payload something like this:
{
"username": "Steve",
"is_admin": false,
"id": 1
}
How do I get access to user id?
I actually want to update certain fields in database as per the id, that are for a specific user.
Secondly after gaining the access how do I get update the fields?
models.py
class Profile(models.Model):
branch = models.CharField(max_length=20, null=True)
year = models.IntegerField(null=True)
image = models.ImageField(upload_to="accounts/images/", null=True, blank=True)
serializer.py
class ProfileSerializer(serializers.ModelSerializer):
class Meta:
model = Profile
fields = ('branch', 'year' ,'image',)
What will be the view to update these fields?
You should use the User object associated with the current request object. This assumes the cookie being present means that the user has a logged-in session when visiting the view in question,
def update_profile(request):
current_user = request.user
profile = Profile.objects.get(user=current_user.pk)
profile.update(field_a="value a", field_b="value b") # etc, example only
profile.save()
To make this possible, you also need to add the user relation as a OneToOne field within the Profile object:
from django.contrib.auth import User # assuming no customisation has been done to User model
# All your other imports and code
class Profile(models.Model):
branch = models.CharField(max_length=20, null=True)
year = models.IntegerField(null=True)
image = models.ImageField(upload_to="accounts/images/", null=True, blank=True)
user = models.OneToOneField(
User,
on_delete=models.CASCADE,
primary_key=False,
)
serializers.py
from django.contrib.auth import get_user_model
from rest_framework import serializers
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = get_user_model()
exclude = ()
views.py
import base64
import json
from django.contrib.auth import get_user_model
from rest_framework.generics import RetrieveUpdateAPIView
class MyUserViewset(RetrieveUpdateAPIView):
queryset = get_user_model().objects.all()
serializer_class = MyUserSerializer
pagination_class = None
def get_object(self):
request = self.request
token = http_auth = request.META.get('HTTP_AUTHORIZATION', None)
token = token.replace("Token ", "")
user_json = json.loads(base64.b64decode(token.split(".")[1]))
user_id = user_json['id']
User = get_user_model()
user_obj = User.objects.get(id=user_id)
return user_obj
Related
I have this serializer and I use it to get post detail of a post belonging to a user. The owner of the post is not the user that is currently logged in. I want to check if the post is bookmarked by the currently logged in user. The currently logged in user's id is passed in the request but I cannot find it in this context.
Here is the serializer:
class UserPostSerializer(serializers.ModelSerializer):
images = PostImageSerializer(many=True, read_only=True, required=False)
profile = serializers.SerializerMethodField()
bookmarked = serializers.SerializerMethodField()
class Meta:
model = Post
fields = [
"id",
"category",
"body",
"images",
"video",
"profile",
"published",
"bookmarked",
"created_at",
"updated_at",
]
depth=1
def get_profile(self, obj):
profile_obj = Profile.objects.get(id=obj.user.profile.id)
profile = ShortProfileSerializer(profile_obj)
return profile.data
def get_bookmarked(self, obj):
breakpoint()
bookmark = Bookmark.objects.filter(owner=obj.user.id, post=obj.id,marktype='post')
if bookmark:
return True
else:
return False
The problem is obj.user.id is the owner of the post. I need the logged in user whose id is passed in the url. Here is the model for the bookmark:
class Bookmark(models.Model):
marktype = models.CharField(max_length=50)
post = models.OneToOneField(Post, on_delete=models.CASCADE, null=True, blank=True)
owner = models.ForeignKey(User, on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True, verbose_name="created at")
updated_at = models.DateTimeField(auto_now=True, verbose_name="updated at")
class Meta:
verbose_name = "bookmark"
verbose_name_plural = "bookmarks"
ordering = ["created_at"]
db_table = "bookmarks"
def __str__(self):
return "{}'s bookmark".format(self.owner.username)
and here is the URL:
path("posts/<int:user>/home/", HomeView.as_view(), name="home"),
This self.context['request'].user returns the owner of the post and not the logged in user.
How do I get the id of the currently logged in user or the user whose id I pass in the URL please?
Maybe do you can use filters to the Viewset:
urls.py
path("posts/home/", HomeView.as_view(), name="home")
viewsets.py
from rest_framework import viewsets
from .models import Post
from .serializers import, UserPostSerializer
from .filters import OwnerFilter
class HomeView(viewsets.ModelViewSet):
queryset = Post.objects.all()
serializer_class = UserPostSerializer
filter_backends = (OwnerFilter,)
filters.py
from rest_framework.filters import BaseFilterBackend
class OwnerFilter(BaseFilterBackend):
def filter_queryset(self, request, queryset, view):
owner = request.query_params.get('owner', None)
if not owner:
return queryset.all()
else:
try:
return queryset.filter(bookmarked__owner__id=owner)
except Exception:
return queryset.none()
Running
Then access the URL:
/posts/home/?owner=OWNER_ID_HERE
Solved it and you can get any kwargs from the view that handles the request. In my case adding the following to the get_bookmarked function gives me the id I send in the URL:
loggeduser = self.context.get('view').kwargs.get('user')
The flow of what I want to do is the following:
I have two tables, namely Event and Result. The Event table is connected with ForeignKey with a user and the Result table is connected with OneToOne relationship with Event. In my views.py I have one POST and one GET. In POST, I take some data and save it in the table Event. In GET, I solve an optimization problem and I want to save the solution into Result.
The models.py is as follows:
from django.db import models
from django.contrib.postgres.fields import ArrayField
from django.contrib.auth import get_user_model
CustomUser = get_user_model()
class Event(models.Model):
user_id_event = models.ForeignKey(CustomUser, on_delete=models.CASCADE, null=True)
dr_notice_period = models.IntegerField(blank=True, null=True)
dr_duration = models.IntegerField(blank=True, null=True)
dr_request = models.FloatField(blank=True, null=True)
class Result(models.Model):
event_id_result = models.OneToOneField(Event, on_delete=models.CASCADE, null=True)
HVAC_flex = ArrayField(models.FloatField(blank=True, null=True))
DHW_flex = ArrayField(models.FloatField(blank=True, null=True))
lights_flex = ArrayField(models.FloatField(blank=True, null=True))
The serializers.py is as follows:
from rest_framework import serializers
from vpp_optimization.models import Event, Result
class EventSerializer(serializers.ModelSerializer):
class Meta:
model = Event
fields = ('__all__')
class ResultSerializer(serializers.ModelSerializer):
HVAC_flex = serializers.ListField(child=serializers.FloatField())
DHW_flex = serializers.ListField(child=serializers.FloatField())
lights_flex = serializers.ListField(child=serializers.FloatField())
class Meta:
model = Result
fields = ('__all__')
The views.py is as follows:
from rest_framework.response import Response
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import IsAuthenticated
from rest_framework import status
from vpp_optimization.importer import DR_event_import_data
from vpp_optimization.utils import optimization_solution, convert_dict_for_serializer
from vpp_optimization.serializers import EventSerializer, ResultSerializer
from vpp_optimization.models import Event, Result
#api_view(['POST'])
#permission_classes([IsAuthenticated,])
def event(request):
serializer = EventSerializer(data=request.data)
if serializer.is_valid():
serializer.save(user_id_event=request.user)
return Response({"status": "success", "data": serializer.data}, status=status.HTTP_200_OK)
else:
return Response({"status": "error", "data": serializer.errors}, status=status.HTTP_400_BAD_REQUEST)
#api_view(['GET'])
def optimization(request):
last_event = Event.objects.last()
if not last_event:
return Response({"res": "Object Event does not exists"}, status=status.HTTP_400_BAD_REQUEST)
serializer = EventSerializer(last_event)
response_dict = {}
DR_event_data = DR_event_import_data(serializer.data)
response_dict = optimization_solution(DR_event_data)
response_dict_final = convert_dict_for_serializer(response_dict)
serializer_result = ResultSerializer(data=response_dict_final)
if serializer_result.is_valid():
serializer_result.save(event_id_result=last_event.id)
return Response(serializer_result.data, status=status.HTTP_200_OK)
However, I am getting the following error:
ValueError: Cannot assign "2": "Result.event_id_result" must be a "Event" instance.
The error is due to the way that I am trying to save with the OneToOne relationship, namely in this line of the views.py:
event_id_result=last_event.id
Apparently, this is not the correct way to connect the two databases. Does anyone can help me find the correct way?
Change:
event_id_result=last_event.id
To:
event_id_result=last_event
I would like to create my own endpoint for POST request to two related tables. I have two tables User and Userattribute.
models.py
class User(models.Model):
email = models.CharField(unique=True, max_length=180)
roles = models.JSONField(default=dict)
password = models.CharField(max_length=255, blank=True, null=True)
name = models.CharField(max_length=255, blank=True, null=True)
firebase_id = models.CharField(max_length=255, blank=True, null=True)
created_at = models.DateTimeField(default=now)
progress_sub_step = models.IntegerField(blank=True, null=True)
step_available_date = models.DateTimeField(blank=True, null=True)
progress_step = models.IntegerField(blank=True, null=True)
active = models.IntegerField(default=1)
last_login_at = models.DateTimeField(blank=True, null=True)
class Meta:
managed = False
db_table = 'user'
class Userattribute(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True, related_name = 'attribute')
attribute = models.ForeignKey(Attribute, on_delete=models.CASCADE)
The table Userattribute contains the field user which is OnetoOne to Id primary key from User table.
I tried to implement POST to two tables in serializers.py In the commented section there is a create definition which works perfectly for me. However, I wouldlike to move it to views.py as register_in_course endpoint
serializers.py
class FilmSerializer(serializers.ModelSerializer):
class Meta:
model = Film
fields = ['tytul', 'opis', 'po_premierze']
class UserattributeSerializer(serializers.ModelSerializer):
class Meta:
model = Userattribute
fields = ['user', 'attribute']
class UASerializer(serializers.ModelSerializer):
class Meta:
model = Userattribute
fields = ['attribute']
class UserSerializer(serializers.ModelSerializer):
attribute = UASerializer(many = False)
class Meta:
model = User
fields = ['email', 'name', 'firebase_id', 'attribute']
# This is what workks perfectly for me, and I want to move it to views.py
# VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
# def create(self, validated_data):
# attribute_data = validated_data.pop('attribute')
# user = User.objects.create(**validated_data)
# Userattribute.objects.create(user=user, **attribute_data)
# return user
Current views.py:
class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
#action(detail = False, methods = ['post'])
def register_in_course(self, request, **kwargs):
data = self.get_object()
user = User.objects.create(email=request.data['email'],
name=request.data['name'],
firebase_id=request.data['firebase_id'])
user_id = User.objects.filter(firebase_id = request.data['firebase_id'])['id']
attribute = Userattribute.objects.create(user = user_id, attribute = request.data['attribute']['attribute'])
user = user.attribute.add(attribute)
serializer = UserSerializer(user, many = false)
return Response(serializer.data)
Using endpoint register_in_course to POST I get following error:
Expected view UserViewSet to be called with a URL keyword argument named "pk". Fix your URL conf, or set the .lookup_field attribute on the view correctly.
urls.py
from django.urls import include, path
from django.conf.urls import url
from rest_framework import routers
from api import views
router = routers.DefaultRouter()
router.register(r'users', views.UserViewSet)
router.register(r'userattribute', views.UserattributeViewSet)
urlpatterns = [
url('', include(router.urls))
]
i removed one line user_id variable and changed attribute variable. please check, maybe it should solve your problem, because you have already have Assigned variable as a User object..
class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
#action(detail = False, methods = ['post'])
def register_in_course(self, request, **kwargs):
data = self.get_object()
user = User.objects.create(email=request.data['email'],
name=request.data['name'],
firebase_id=request.data['firebase_id'])
attribute = Userattribute.objects.create(user = user, attribute = request.data['attribute']['attribute']) # changed this line
user = user.attribute.add(attribute)
serializer = UserSerializer(user, many = false)
return Response(serializer.data)
This issue is caused by calling get_object in a view that is defined with detail=False:
#action(detail = False, methods = ['post'])
def register_in_course(self, request, **kwargs):
data = self.get_object() # The problem is caused by this line
It seems you don't need this data, as you are using request.data.
So you can define your view like this:
#action(detail = False, methods = ['post'])
def register_in_course(self, request, **kwargs):
user = User.objects.create(
email=request.data['email'],
name=request.data['name'],
firebase_id=request.data['firebase_id']
)
Userattribute.objects.create(
user=user,
attribute = request.data.get('attribute', {}).get('attribute', {})
)
return Response(UserSerializer(user).data)
I am using the Django Rest Framework. I have two models as shown below:
class Following(models.Model):
target = models.ForeignKey('User', related_name='followers', on_delete=models.CASCADE, null=True)
follower = models.ForeignKey('User', related_name='targets', on_delete=models.CASCADE, null=True)
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return '{} is followed by {}'.format(self.target, self.follower)
class User(AbstractBaseUser):
username = models.CharField(max_length=15, unique=True)
email = models.EmailField(max_length=100, unique=True)
What I'd like to have an API that will return all the followers the user has. However, I don't want it to be returned in the Following model format, I'd like for the followers to be returned as users in this format:
[
{
"username": Bob,
"email": example#example.com
},
{
"username": Charlie,
"email": example#example.com
}
]
Right now, I have something like this:
class FollowingAPIView(ListAPIView):
serializer_class = FollowingSerializer
def get_queryset(self):
return Following.objects.filter(target=3)
class FollowingSerializer(serializers.ModelSerializer):
class Meta:
model = Following
fields = ('follower', 'target')
This only shows the follower and target I don't want this. I want the actual data from User Also, I put target=3 as a placeholder just to test.
you should use a serializer for the User not following:
class UserSerializer(serializers.ModelSerializer):
is_following = serializer.IntegerField()
class Meta:
model = User
fields = ('username', 'email', 'is_following')
also, change your queryset in view as below:
from django.db import models
from rest_framework.generics import get_object_or_404
class FollowingAPIView(ListAPIView):
serializer_class = FollowingSerializer
### so add this method to get the requested user based on the username in the url
def get_requested_user(self):
##get the user based on the user name in url
filter_kwargs = {'username': self.kwargs['username']}
obj = get_object_or_404(User.objects.all(), **filter_kwargs)
return obj
def get_queryset(self):
requested_user = self.get_requested_user()
return User.objects.filter(targets__target=requested_user)\
.annotate(is_following=models.Count('followers', filter=models.Q(followers__follower=requested_user), distinct=True))
if you are using Django<2.0, your get_queryset should be like:
def get_queryset(self):
requested_user = self.get_requested_user()
return User.objects.filter(targets__target=requested_user)\
.annotate(is_following=models.Count(models.Case(models.When(models.Q(followers__follower=requested_user), 1))))
because you want to return a list of users, not Following instances. use following only to filter( targets__ in the filter above) the users that their target in Following is the currently authenticated user(at least in one of its targets).
updated
also, change your url to something like this:
path('/api/followers/<username>/', FollowingAPIView.as_view(), name='get_user_followers')
I have a simple model where a User can take part in multiple Game and a Game can be played by multiple User. Each User has a score field in a Game.
To achieve this, I have followed the example provided in the Django documentation to implement such a ManyToMany relationship with an additional field by creating a third model Membership to link the Game table and the User one.
I have the following models.py:
from django.contrib.auth.models import AbstractUser
from django.db.models.signals import post_save
from django.dispatch import receiver
from rest_framework.authtoken.models import Token
from django.db import models
class User(AbstractUser):
pass
# triggered as soon as a new user is saved in the db
#receiver(post_save, sender=User)
def create_auth_token(sender, instance=None, created=False, **kwargs):
if created:
Token.objects.create(user=instance)
class Game(models.Model):
users = models.ManyToManyField(User, through='Membership')
class Membership(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
game = models.ForeignKey(Game, on_delete=models.CASCADE)
score = models.IntegerField()
Then I have written serializers.py:
from rest_framework import serializers
from .models import User, Membership, Game
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
# unique email
model._meta.get_field('email').__dict__['_unique'] = True
fields = ('id', 'username', 'password', 'email')
def create(self, validated_data):
user = super().create(validated_data)
if 'password' in validated_data:
user.set_password(validated_data['password'])
user.save()
return user
class GameSerializer(serializers.ModelSerializer):
users = UserSerializer(many=True)
class Meta:
model = Game
fields = ('users',)
class MembershipSerializer(serializers.HyperlinkedModelSerializer):
id = serializers.ReadOnlyField(source='game.id')
class Meta:
model = Membership
fields = ('id', 'score')
My goal is to be able to save a new Game by posting something like:
{
{user_id = 1,
score = 25},
{user_id = 2,
score = 10}
}
I am thus wondering how to achieve this.
To achieve this you can use Django generic views where you can have CreateAPI view ,where after each game you can create an membership object.
But you have to use a ModelSerializer instead of HyperlinkedModelSerializer.
Do this manually as:
serializers.py
class MembershipSerializer(serializers.ModelSerializer):
class Meta:
model = Membership
fields = ('user ', 'game', 'score')
views.py
class GameViewSet(ModelViewSet):
queryset = Game.objects.all()
serializer_class = GameSerializer
permission_classes = (IsAuthenticated,)
#detail_route(methods=['POST'])
def bulk_create(self, request, pk):
game = self.get_object()
datas = request.data.getlist('data')
import ast
for _data in datas:
data = ast.literal_eval(_data)
data['game'] = game.id
serializer = MembershipSerializer(data=data)
if serializer.is_valid()
serializer.save()
else:
pass
return Response('success')
the data you post is something like {'data':[{user_id = 1,score = 25}]}
the post url is /game/your_game_id/bulk_create/,
not test code,your may get some error,but you can achieve like this.