I am a bit new to Djoser and what i am wanting to do is when an authenticated user naviates to the users/me API endpoint it returns with the user id email and name. I would like for it to also return custom information how would I do that?
While this might only answer half of your question, if you use a custom user, then you would add a REQUIRED_FIELDS = ['field_you_want_included']
E.g this is how one of my custom user profiles look like.
class CustomUser(AbstractUser):
username = None
user_id = models.UUIDField(default=uuid4, primary_key=True, editable=False)
email = models.EmailField(_('email address'), unique=True)
receive_news = models.BooleanField(null=True, blank=True, default=False)
birth_date = models.DateField(null=True, blank=True)
is_premium = models.BooleanField(default=True)
USERNAME_FIELD = 'email'
# FIELDS HERE WILL BE ADDED TO USERS/ME ENDPOINT
REQUIRED_FIELDS = ['is_premium']
objects = UserAccountManager()
There is plenty if info on making custom users with djoser, so what matters here is the required_fields list. Now, when making a get to users/me it will also include 'is_premium'.
However, for more complex inclusions I would attempt to override the view & serializer. Have not tried that myself but I will edit this post if I do.
Djoser is just a Django App.
Just override Djoser's classes with your own and point your auth URLs to those instead of those of the package.
I had to that to, this is sample of what I did.
from djoser.views import TokenDestroyView as DjoserTokenDestroyView
from djoser.views import UserViewSet
class CustomUserViewSet(UserViewSet):
"""
Overriding djoser's Users view
"""
#extend_schema(summary="Me", responses={200: LoginSerializer, 404: UserNotFoundResponse, 401: FailedLogin})
#action(["get", "put"], detail=False)
def me(self, request, *args, **kwargs):
"""
get the current User's data and KPIs settings
"""
if request.method == MethodsNames.GET.upper():
user = User.objects.filter(email=self.get_instance()).select_related(ACCOUNT).prefetch_related(
RelatedNames.AUTH_TOKEN,
'account__bundles', 'account__bundles__bundle_kpis',
RelatedNames.USER_SELECTED_KPIS)[0]
user_data = LoginSerializer(user, many=False)
return Response(user_data.data)
# some more overriding here...
then my urls file look like:
from django.conf.urls import url
from django.urls import include, path
from rest_framework.routers import DefaultRouter
from users.views import TokenCreateView, CustomUserViewSet, TokenDestroyView
users = DefaultRouter()
users.register("users", CustomUserViewSet, basename='users')
login = DefaultRouter()
login.register('token', TokenCreateView, basename='login')
urlpatterns = [
path('', include(login.urls)),
path('', include(users.urls)),
url(r"^token/logout/?$", TokenDestroyView.as_view(), name="logout"),
]
instead of (from Djoser docs):
urlpatterns = [
(...),
url(r'^auth/', include('djoser.urls')),
]
in your setting files add this
DJOSER = {
#
'SERIALIZERS': {
'user_create': 'customuser.serializer.UserSerializerCreate',
'user' : 'customuser.serializer.UserSerializer',
},
}
Related
class Admin(models.Model):
username = models.CharField(primary_key=True, max_length=30)
password = models.CharField(max_length=255)
email = models.EmailField(unique=True)
created_on = models.DateTimeField(auto_now=True)
django_user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='admin')
class AdminAPIViewSet(viewsets.ModelViewSet):
queryset = Admin.objects.all()
serializer_class = AdminSerializer
permission_classes = [permissions.IsAdminUser]
def get_queryset(self):
if self.request.user.is_authenticated:
return Admin.objects.filter(username=self.request.user.admin.username)
else:
return []
def create(self, request, *args, **kwargs):
serializer = AdminSerializer(data=request.data)
if serializer.is_valid():
email = serializer.data['email']
username = serializer.data['email']
password = serializer.data['password']
with transaction.atomic():
django_user = User.objects.create_user(username, email, password)
admin = Admin.objects.create(**serializer.data, django_user=django_user)
#User.objects.filter(pk=1001).update(is_superuser=True, is_staff=True)
return Response(admin.pk)
return Response('/error')
class ClientFullAccessAPIViewSet(viewsets.ModelViewSet):
queryset = Client.objects.all()
serializer_class = ClientSerializer
permission_classes = [permissions.IsAdminUser]
def create(self, request, *args, **kwargs):
serializer = ClientSerializer(data=request.data)
if serializer.is_valid():
email = serializer.data['email']
username = serializer.data['email']
password = serializer.data['password']
with transaction.atomic():
django_user = User.objects.create_user(username, email, password)
client = Client.objects.create(**serializer.data, django_user=django_user)
return Response(client.username)
return Response('/error')
`Here am trying to make the admin see the all the clients and the client see his data only ,... but I couldn't find why the i cant see the all the list clients as an admin, I am keep getting not authorized to access this endpoint..
`
urls.py
from django.contrib import admin
from django.urls import path, include
from rest_framework import routers
import user_management.views
router = routers.DefaultRouter()
router.register(r'clients', user_management.views.ClientReadOnlyAPIViewSet)
router.register(r'clientslist', user_management.views.ClientFullAccessAPIViewSet)
router.register(r'admin', user_management.views.AdminAPIViewSet)
urlpatterns = [
path('admin/', admin.site.urls),
path('api-auth/', include('rest_framework.urls')),
path('api/v1/', include(router.urls)),
#path('clients/', user_management.views.ClientAPIViewSet.as_view(), name="clients"),
]
`Here am trying to make the admin see the all the clients and the client see his data only ,... but I couldn't find why the i cant see the all the list clients as an admin, I am keep getting not authorized to access this endpoint..any help please?
The problem is that you defined your Admin model from a regular Django model so Django cannot find the user permissions associated to it.
You should inherit from a Django authentication user model (AbstractUser or AbstractBaseUser) as indicated in the documentation.
For instance, you can do:
from django.contrib.auth.models import AbstractUser
class CustomAdminUser(AbstractUser):
# Here you normally only want to
# define the fields not defined in
# the base model AbstractUser
pass
Then, to create your admin:
CustomAdminUser.objects.create_superuser(...)
Last but not least, two important things (mentioned in the above Django documentation's link):
Don’t forget to point the AUTH_USER_MODEL to your custom user model. Do this before creating any migrations or running manage.py migrate for the first time.
Register the model in the app’s admin.py.
Hello I am a newbie and have a task to do,I have tried simple social authentication that is working but below is bit complicated:
Create a social authentication functionality with google and add user in a
database. After adding user in a database, customer should also be created
using django signals.
Note:- Customer is one to one related with user?
My models.py :
class Buddy(models.Model):
user_name=models.CharField(max_length=200,blank=True,null=True)
def __str__(self):
return str(self.user_name)
class Customer(models.Model):
customer_name=models.OneToOneField(Buddy,
on_delete = models.CASCADE,
blank=True,null=True)
def __str__(self):
return str(self.customer_name)
My settings.py includes the following lines:
SOCIAL_AUTH_GOOGLE_OAUTH2_KEY = '2377[...].apps.googleusercontent.com'
SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET = '[...]'
SOCIAL_AUTH_GOOGLE_OAUTH2_SCOPE = ['email']
INSTALLED_APPS = [ ... # oauth
'oauth2_provider',
'social_django',
'rest_framework_social_oauth2' ]
AUTHENTICATION_BACKENDS = ( # Google OAuth2
'social_core.backends.google.GoogleOAuth2',
# django-rest-framework-social-oauth2
'rest_framework_social_oauth2.backends.DjangoOAuth2', # Django
'django.contrib.auth.backends.ModelBackend', )
You have to use Django's post_save signal.
In your models.py have:
class Buddy(models.Model):
user_name=models.CharField(max_length=200, blank=True, null=True)
def __str__(self):
return str(self.user_name)
class Customer(models.Model):
# This translates into buddy_id when you migrate
buddy=models.OneToOneField(Buddy,on_delete = models.CASCADE,
blank=True, null=True)
customer_name = models.CharField(max_length=200, blank=True, null=True)
def __str__(self):
return str(self.customer_name)
In your views.py make sure you have
from django.shortcuts import render
from django.db.models.signals import post_save
from .models import Buddy
from .callbacks import save_customer
# You'll customize this view to read any parameters and provide user_name
def custom_view(request):
Buddy.objects.create(user_name="SomeUsername")
# Any of your other logic comes here, specify in the dict
return render(request, 'yourpage.html', {})
# This should be at the bottom of your views.py:
post_save.connect(save_customer, sender=Buddy)
Then create a new file in the same location called callbacks.py and there include:
from .models import Buddy
from django.db.models.signals import post_save
from django.dispatch import receiver
#receiver(post_save, sender=Buddy)
def save_customer(sender, instance, **kwargs):
# Customize your OneOnOne model on a meaningful way so it will be useful
customer = Customer.objects.create(customer_name=instance.user_name)
instance.customer = customer
instance.customer.save()
Read more about Django signals here.
I have created a user and want to add him to groups by default viewer but only when he has verified his email id.
I have used djoser to create the APIs to create user. On post email is verified . Now I cant understand how to implement adding to group when email is verified.
this is model.py
from django.db import models
from django.contrib.auth.models import AbstractUser, Group
class User(AbstractUser):
# GROUP_CHOICES = (
#('admin','ADMIN'),
#('creator', 'CREATOR'),
#('reader','READER')
#)
#group = models.CharField(max_length=10, choices=GROUP_CHOICES, default='CREATOR')
email = models.EmailField(verbose_name='email',max_length=233,unique=True)
phone = models.CharField(null=True,max_length=255)
is_active=models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
REQUIRED_FIELDS=['username','phone','first_name', 'last_name']
USERNAME_FIELD = 'email'
def get_username(self):
return self.email
#def add_group(self):
# user= User.OneToOneField(User)
# group = Group.objects.get(name='Creator')
# my_group.user_set.add(your_user)
serializer.py
class UserCreateSerializer(UserCreateSerializer):
class Meta(UserCreateSerializer.Meta):
model= User
fields = ('id' ,'email', 'username' ,'password', 'first_name', 'last_name', 'phone')
urls.py in the app
urlpatterns = [
path('', include('djoser.urls')),
path('', include('djoser.urls.authtoken')),
]
I have refereed to
stack overflow link
but cant relate it to my code or how to add it, if its the right way.
One possible way by overriding djoser.serializers.ActivationSerializer would be as follows -
from django.contrib.auth.models import Group
from djoser.serializers import ActivationSerializer
class MyActivationSerializer(ActivationSerializer):
def validate(self, attrs):
attrs = super(MyActivationSerializer, self).validate(attrs)
group = Group.objects.get(name='your_group_name')
self.user.groups.add(group)
return attrs
Then in your settings.py update the following -
DJOSER = {
# other djoser settings
'SERIALIZERS': {
#other serializers
'activation': 'your_app_name.serializers.MyActivationSerializer',
#other serializers
}
}
I try to create a new user (django user) via POST with
serializers.py
from rest_framework import serializers
from .models import *
from django.contrib.auth.models import User
class UsuarioSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('email',
'password')
views.py:
class Registrar(mixins.CreateModelMixin, viewsets.GenericViewSet):
serializer_class = UsuarioSerializer
urls.py:
from django.urls import path, include
from . import views
from rest_framework import routers
router = routers.DefaultRouter()
router.register('usuarios', views.UsuarioViewSet)
router.register('tecnicos', views.TecnicoViewSet)
router.register('pedidos', views.PedidoViewSet)
router.register('mispedidos', views.PedidoMiUsuarioSet)
router.register('registrar', views.Registrar, base_name = 'registro')
urlpatterns = [
path('', include(router.urls))
]
When i make a post i get this error:
UNIQUE constraint failed: auth_user.username
This works if i change the model User to Usuario...
Models.py:
class Usuario(models.Model):
email = models.EmailField(max_length=70, blank=True, null=True, unique=True)
password = models.TextField()
def __str__(self):
return self.email
But i need to use the User model from django
The username field in the user model is required.
This is why you must use this field in create operations.
Email address is not mandatory by default.
It happens on Django create user via a unique user username.
I am using djoser for auth purposes. I want to customize the create user end point of djoser. I have a User app. Here is my User model
from django.db import models
class User(models.Model):
email = models.CharField(max_length=100, blank=False)
name = models.CharField(max_length=100, blank=False)
last_name = models.CharField(max_length=100, blank=False)
account_address = models.CharField(max_length=30, blank=False)
password = models.CharField(max_length=100, blank=False)
and here is my serializer
from rest_framework import serializers
from User.models import User
class UserSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = User
fields = ('url', 'id', 'email', 'name', 'last_name', 'account_address', 'password')
and my User.urls.py looks like following
from django.conf.urls import url, include
from rest_framework.routers import DefaultRouter
from .views import UserViewSet
router = DefaultRouter()
urlpatterns = [
url(r'^', include(router.urls)),
url(r'^account/', include('djoser.urls')),
]
and project's url.py is follwing
from django.contrib import admin
from django.urls import path
from django.conf.urls import include, url
urlpatterns = [
path('admin/', admin.site.urls),
url(r'^users/', include('User.urls')),
url(r'^advertisements', include('advertisements.urls')),
url(r'^account', include('wallet.urls')),
]
but i am unable to create user with customized model instead when i go to user/account/create i see djoser's default create user view. Anybody please tell where I am doing wrong. Thanks :)
Having in mind that you have set the AUTH_USER_MODEL to your User model.
Just import the Djoser User Registration Serializer And override it.
from djoser.serializers import UserCreateSerializer as BaseUserRegistrationSerializer
class UserRegistrationSerializer(BaseUserRegistrationSerializer):
class Meta(BaseUserRegistrationSerializer.Meta):
fields = ('url', 'id', 'email', 'name', 'last_name', 'account_address', 'password', )
You can also override other things in the serializer like create and update methods in case if you want to customize it.
And in settings.py
DJOSER = {
...
'SERIALIZERS': {
'user_create': 'yourapp.serializer.UserRegistrationSerializer'
}
...
}
For me, I wanted to write a custom create method and it worked when I override user_create_password_retype and used mine since this is internally using the UserCreateSerializer from djoser
DJOSER = {
...
"SERIALIZERS": {
"user_create": "account.serializers.user_serializer.CustomUserCreateSerializer",
"user": "account.serializers.user_serializer.CustomUserSerializer",
"user_create_password_retype": "account.serializers.user_serializer.UserCreatePasswordRetypeSerializer",
}
...
}
Other settings -
AUTH_USER_MODEL to your custom User model.