Django API: get authenticated user from request - django

The user is authenticated using allauth. I want to create a profile and set the authenticated user as the owner of the profile. How can I get the user?
Model class:
from django.db import models
from allauth.utils import get_user_model
from courses.models import Course
class Profile(models.Model):
owner = models.OneToOneField(get_user_model(), on_delete=models.CASCADE)
courses = models.ManyToManyField(Course, blank=True)
def get_courses_items(self):
return self.courses.all()
def __str__(self):
return self.owner.username
Views:
from rest_framework.generics import CreateAPIView
from profiles.models import Profile
from .serializers import ProfileSerializer
class ProfileCreateView(CreateAPIView):
queryset = Profile.objects.all()
serializer_class = ProfileSerializer

You can get the user from the request with request.user. Then probably you should override the def create method of the CreateAPIView to use that user and create the object.

set your user model in the settings file (base.py) and import it
AUTH_USER_MODEL = 'users.User' #(format is module.user model name)
from django.conf import settings
user = models. OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
method 2
Override the get_create method of the ProfileView. Every authenticated request has a request.user object in it which represents the user making the request. To get the user's id with this you just run request.user.id
class ProfileCreateView(CreateAPIView):
queryset = Profile.objects.all()
serializer_class = ProfileSerializer
def create(self, request, *args, **kwargs):
user = User.objects.get(id=request.user.id)
# create the profile and save it
...
in your serializers you can also get the current user this way
from rest_framework.serializers import CurrentUserDefault, PrimaryKeyRelatedField
class ProfileModelSerializer(ModelSerializer):
user = PrimaryKeyRelatedField(read_only=True, default=CurrentUserDefault())
class Meta:
...
I don't know how the remainder of your setup is but any or a combination of these works

Related

How to implement registration and login logics as an API using ViewSet instead of generic views in Django Rest Framework

I am new to viewset when using Django Rest Framework to create registration and login logics as an API using ViewSet instead of generic views, and exposing resources to a React standalone frontend app on a diffrent port. In a previous project where I had the possibility to use django template as frontend inside the django project, I simply used django Views to implement the registration and login logics and template by doing this:
// MyOldMethod.py
#login_required
def index(request):
return render(request,'customers/index.html')
def signup(request):
context = {}
form = UserCreationForm(request.POST or None)
if request.method == "POST":
if form.is_valid():
user = form.save()
login(request,user)
return render(request,'customers/index.html')
context['form']=form
return render(request,'registration/signup.html',context)
And by this mean, the basic login authentication were set.
Now for this case, I need to use viewset and serializer and at the end, connect the React frontend app to the django API using axios. So far I implemented, the models.py, serializer.py and api.py and the urls.py as follow in the customers app.
// models.py inside customers App
from django.db import models
from django.core.validators import RegexValidator
class Customer(models.Model):
name = models.CharField(max_length=100)
phone_regex = RegexValidator(regex=r'^\+?1?\d{9,15}$', message="Phone number must be entered in the format: '+999999999'. Up to 15 digits allowed.")
phone = models.CharField(validators=[phone_regex], max_length=17, blank=True) # validators should be a list
email = models.EmailField()
activated = models.BooleanField(default=False)
message = models.CharField(max_length=300)
created_at = models.DateTimeField(auto_now_add=True)
def _str_(self):
return self.name
// serializers.py inside customers App
from rest_framework import serializers
from .models import Customer
class CustomerSerializer(serializers.ModelSerializer):
class Meta:
model = Customer
fields = '__all__'
// serializers.py inside customers App
from rest_framework.decorators import permission_classes
from Customer.models import Customer
from rest_framework import viewsets, permissions
from .serializers import CustomerSerializer
class CustomerViewSet(viewsets.ModelViewSet):
queryset = Customer.objects.all()
permission_classes = [
permissions.AllowAny
]
serializer_class = CustomerSerializer
// urls.py inside customers App
from rest_framework import routers, urlpatterns
from .api import CustomerViewSet
router = routers.DefaultRouter()
router.register('api/customer', CustomerViewSet, 'customer')
urlpatterns = router.urls
The problem with this implementation which is based on my limited understanding of viewset is that I don't know how to write the registration and login logics with viewset as I did in MyOldMethod.py .
I will really appreciate any help to acheive this purpose and get me more familiar with the arcana of viewset, because among it's predefined actions (list, create, retreive, update, partial_update, destroy), I saw none that helps implement registration and login authentication and logics as I did before with generic views.
Thank you in advance.
You can get much information about ModelViewSet here.
When it comes to your question , there are different ways to solve it.
You can override create() in CustomerSerializer:
class Customererializer(serializers.ModelSerializer):
# ....
def create(self, validated_data):
customer = Customer.objects.create(**validated_data)
return customer
Another solution is that you can write your own create method in your viewset class:
class CustomerViewSet(viewsets.ModelViewSet):
def create(self, request, format=None):
# create user here

Django 2.2 and Rest Framework 3.11 - partial updating model "owner" field (ForeignKey) with owner's username string instead of pk

Django 2.2 and Rest Framework 3.11
I have an Alarm model. Every alarm instance can optionally have an owner (the standard django User model).
I want to be able to partially update (PATCH) an alarm by setting its owner just using his/her username (string) instead of the pk.
Right now, I can update an alarm's owner only by using his/her pk.
I tried various things, like:
override the update() method in the AlarmSerializer class but whenever I use the owner's username string instead of the pk in the PATCH call, I get back:
{
"owner": [
"Incorrect type. Expected pk value, received str."
]
}
play with nested serializers and lookup_field but no luck so far.
The api call (PATCH) should look like this:
url: /api/alarms/{alarm_id}/
Payload:
{
"owner": "owner_username"
}
How can I do that? Thanks
models.py
from django.db import models
from django.conf import settings
class Alarm(models.Model):
"""
this class is meant to represent a network alarm (a.k.a. event or ticket)
coming from some monitoring system (Zabbix, Nagios, etc.)
"""
customer = models.CharField(max_length=50)
owner = models.ForeignKey(
settings.AUTH_USER_MODEL,
models.SET_NULL,
blank=True,
null=True,
)
managed = models.BooleanField(default=False, blank=False, verbose_name="Managed ?")
device_type = models.CharField(max_length=150)
...
serializers.py
from django.contrib.auth.models import User
from rest_framework import serializers
from .models import Alarm
class AlarmSerializer(serializers.ModelSerializer):
class Meta:
model = Alarm
fields = [
"customer",
"owner",
"device_type",
"device_name",
"ip_address",
"date",
]
views.py
from rest_framework import viewsets
from .models import Alarm
from .serializers import AlarmSerializer
# Create your views here.
class AlarmViewSet(viewsets.ModelViewSet):
queryset = Alarm.objects.all()
serializer_class = AlarmSerializer
I found a solution: convert the owner username string in pk inside the ModelViewSet.
You need to override the partial_update() method inside the ModelViewSet in views.py.
This view gets hit by the api PATCH call before serialization validation kicks in; hence this is the correct place to swap the username string with the username pk.
views.py
from django.contrib.auth.models import User
from django.shortcuts import get_object_or_404
from rest_framework import viewsets
from rest_framework.response import Response
from .models import Alarm
from .serializers import AlarmSerializer
class AlarmViewSet(viewsets.ModelViewSet):
queryset = Alarm.objects.all()
serializer_class = AlarmSerializer
def partial_update(self, request, *args, **kwargs):
instance = self.get_object()
# if the owner field is not a string, it should be
# a legit pk, so we don't do anything.
if isinstance(request.data["owner"], str):
owner_username = request.data.pop("owner")
owner = get_object_or_404(User, username=owner_username)
request.data["owner"] = owner.pk
serializer = self.serializer_class(instance, data=request.data, partial=True)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data)

Displaying data owned by the current logged in users

While creating API'S I'm using queryset on my model and trying to get only the data owned by the logged in users, but I'm getting some errors.
Console Log
from . import views
File "F:\coding and stuff\finMSG\chatbot\chatbotapi\views.py", line 8, in <module>
class queryViewSet(viewsets.ModelViewSet):
File "F:\coding and stuff\finMSG\chatbot\chatbotapi\views.py", line 10, in queryViewSet
queryset = query.objects.filter(user=self.request.user)
NameError: name 'self' is not defined
Models.py
# Create your models here.
# models.py
from django.db import models
from django.contrib.auth.models import User
class query(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
referencetoken = models.CharField(max_length=60)
question = models.CharField(max_length=60)
def __str__(self):
return self.referencetoken
Views.py
from rest_framework import viewsets
from .serializers import querySerializer, BotSocialConfigSerializer, SkillsSerializer, BotsSerializer
from .models import query, BotSocialConfig, Intents, Skills, Bots
from rest_framework.permissions import IsAuthenticated
# Create your views here.
class queryViewSet(viewsets.ModelViewSet):
permission_classes = (IsAuthenticated,)
queryset = query.objects.filter(user=self.request.user)
serializer_class = querySerializer
How can I get data only for user that is currently logged in.
Remove the query-set attribute and overwrite the get_queryset method
def get_queryset(self):
queryset = query.objects.filter(user=self.request.user)
return queryset

How can I make sure that the data is from the login user in Django?

I'm trying to save the data I've received from Arduino in the DB. We have succeeded in receiving and storing temperature and humidity data, but failed to link this data with logged-in users. Can you help me?
Here is my code.
views.py
from .models import arduino
from .serializers import arduinoSerializers
from rest_framework.viewsets import ViewSet
from rest_framework.response import Response
from rest_framework.generics import CreateAPIView
class arduinoToAndroidViewSet (ViewSet) :
def dataSend (self, request) :
user = self.request.user
queryset = arduino.objects.filter(name = user)
serializer = arduinoSerializers(queryset, many=True)
return Response(serializer.data)
class arduinoToDatabaseViewSet (CreateAPIView) :
serializer_class = arduinoSerializers
def get_queryset(self) :
user = self.request.user
return arduino.objects.filter(name = user)
def dataReceive(self, request) :
queryset = get_queryset()
serializer = arduinoSerializers(queryset, many=True)
if serializer.is_valid() :
serializer.save()
return Response(serializer.data)
serializers.py
from rest_framework import serializers
from .models import arduino
class arduinoSerializers (serializers.ModelSerializer) :
name = serializers.CharField(source='name.username', read_only=True)
class Meta :
model = arduino
fields = ('name', 'temp', 'humi')
If you post it like this,
I want you to know that this is root's data.
I log in to the test account, put the data in, and press the post button.
This will not Migrate to the 'test' account. I want to migrate this data in conjunction with the 'test' account.
you could use permissions to limit access
and for linking user to your data, add perform_create function (i assume name field is FK to user)
from rest_framework.permissions import IsAuthenticated
from rest_framework.generics import CreateAPIView
class arduinoToDatabaseViewSet(CreateAPIView):
permission_classes = [IsAuthenticated] # only logged in users has access to this view
def perform_create(self, serializer):
serializer.save(name=self.request.user)

Use autocomplete_fields with Proxy model

I want to implement autocomplete_fields feature but it doesn't work. I assume it happens because of Proxy model.
So I have Customer Proxy model and PromoCode model. PromoCode has FK to Customer model. And I need to have search field for customers in PromoCode change form. Here are models and admin classes:
class User(AbstractUser):
# bunch of fields
class Customer(User):
class Meta:
proxy = True
class CustomerAdmin(admin.ModelAdmin):
search_fields = ['email',]
admin.site.register(Customer, CustomerAdmin)
class PromoCode(TimeStampedModel):
customer = models.ForeignKey(User, on_delete=PROTECT, null=True, blank=True)
class PromoCodeAdmin(admin.ModelAdmin):
autocomplete_fields = ('customer',)
admin.site.register(PromoCode, PromoCodeAdmin)
This code gives error:
: (admin.E039) An admin for model "User" has to be registered to be referenced by PromoCodeAdmin.autocomplete_fields.
But I can't change model in customer field to Customer, becase when I run migration it breaks with following error:
ValueError: The field coupons.PromoCode.customer was declared with a lazy reference to 'users.customer', but app 'users' doesn't provide model 'customer'
Also I can't register User as admin class, because I don't need it to be registered. I register Customer model.
What can I do to solve such case?
It is not possible (see: https://code.djangoproject.com/ticket/30666). I got around this by registering the User admin, but making it redirect to my custom admin model. I also removed all of the actions on the user admin:
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from django.contrib.auth.models import User
from django.http import HttpResponseRedirect
from django.urls import reverse
admin.site.unregister(User)
#admin.register(User)
class UserAdmin(BaseUserAdmin):
preserve_filters = False
def get_actions(self, request):
actions = super().get_actions(request)
if "delete_selected" in actions:
del actions["delete_selected"]
return actions
def has_delete_permission(self, request, obj=None):
return False
def has_add_permission(self, request):
return False
def has_change_permission(self, request, obj=None):
return False
def changelist_view(self, *args, **kwargs):
return HttpResponseRedirect(reverse("admin:core_domainuser_changelist"))