Create a serializer for custom user model in django-rest-auth? - django-rest-framework

I've installed django-rest-framework. Also i've installed django allauth.
Now i want to use django-rest-auth based on previous two, for serializing data
and sending it in json format as answer on my submit form method (for registration/login etc).
I look up into documentation is provided for django-rest-auth
but it feels for me strange, as i inherit(and must do so) from the AbstractBaseUser and not simply do OneToOneField on existing User model.
At the moment the model i assign to the AUTH_USER_MODEL in my settings.py is:
class Account(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(unique=True, db_index=True, verbose_name='Account Email')
is_admin = models.BooleanField(default=False)
is_staff = models.BooleanField(default=False)
is_employer = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
created_at = models.DateTimeField(auto_now_add=True)
objects = AccountManager()
USERNAME_FIELD = 'email'
The question is: how can i use serializing in rest-auth the same way, but using my model instead of provided UserProfile model example ?

Yes you may inherit it, and use serializers the way you are saying. It should work. Please state where the error arises when you are using serializers for this.

Related

drf-spectacular: how to show the primary key in examples section of Swagger

I'm trying to show the primary key in the examples section of Swagger, I'm using drf-spectacular and my code looks like:
Serializers.py
class SerializerExample(serializers.ModelSerializer):
class Meta:
model = Book
fields = ('id','name')
Views.py
class BooksBulkUpdate(APIView):
#extend_schema(
request=SerializerExample(many=True),
responses={200:''},
)
def put(self, request, format=None):
with transaction.atomic():
for data in request.data:
book = Book.objects.get(pk=data['id'])
serializer = SerializerExample(book, data=data, partial=True)
if serializer.is_valid():
serializer.save()
else:
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
return Response()
Only the name field is showing:
The only solution that I found was using an inline serializer which is not the ideal solution because if I update my book serializer I'd have to remember to update also this inline serializer. I wonder if there is a better way of doing this.
AFAIK swagger shows input request schema.
For example, you want to add new person and your model is
class Person(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
name = models.CharField(max_length=30)
So you allowed to set only name parameter
Even if you post
{
"id": "someUUID",
"name": "NAME",
}
id will be ignored and Django create it automatically by own logic (because it is read only)
But you can set id field writeable:
class SerializerExample(serializers.ModelSerializer):
id = serializers.UUIDField(write_only=True)
name = serializers.CharField(write_only=True)
class Meta:
model = Person
fields = ('id','name')
write_only=True means that field will be active when you saving new data and receiving id from request json.
In opposite read_only=True will print id field at response (if you trying get data) but ignore it when you saving new data.
So you try to describe API for data adding, and of course that is not allow to set id field in request json.
Not sure if this theory applicable to your case, but hope that will be helpful.

DRF : CreateAPIView - UNIQUE constraint failed

I am using Django Rest Framework with React for the front.
I want to post Note linked to a ForeignKey User.
models.Note
class Note(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
content = models.TextField(blank=True, default='')
serializers.NoteSerializer
class NoteSerializer(serializers.ModelSerializer):
user = serializers.PrimaryKeyRelatedField(queryset=User.objects.all())
class Meta:
model = Note
fields = ('user', 'content')
When I post {user: 1, content: "test"}, I get the following error message:
UNIQUE constraint failed: app_note.user_id
How can I link the new Note to an existing user, posting the user.id?
I think my current code is trying to create a new User Instance...
You are using OneToOneField in Note model. That means a user can have only one note.
use ForeignKey instead to have many notes for single user.

Attach author to POST request to create an object

It's probably very basic, but I am starting to learn Django REST Framework. So far I've succeeded with read-only operations. And now I got stuck on this problem.
I have a model:
class PersonComment(AbstractComment):
person = models.ForeignKey(Person, on_delete=models.PROTECT)
author = models.ForeignKey('auth.User')
body = models.TextField(default='', blank=False)
(Here author is the author of the comment and person is a person this comment relates to; it's a genealogical site.) And a related serialiser:
class PersonCommentSerialiser(serializers.HyperlinkedModelSerializer):
class Meta:
model = PersonComment
fields = ('url', 'body', 'person', 'author')
In my HTML page, I expect a user to submit a comment by providing "body", the rest should be auto-filled. What is the best practice for filling in the "author"? In my pre-DRF Django exercises, I was doing something like this in the view:
comment = PersonComment.objects.create(
author=request.user,
body=new_comment_body,
person=person
)
But if I understand everything I've read so far, this is not the way in DRF. Any help is much appreciated.
I would do this using the default attribute in serializer fields.
class PersonCommentSerialiser(serializers.HyperlinkedModelSerializer):
author = serializers.PrimaryKeyRelatedField(read_only=True, default=CurrentUserDefault())
class Meta:
model = PersonComment
fields = ('url', 'body', 'person', 'author')
CurrentUserDefault is a class predefined in Django REST framework for exactly this purpose. This way you don't have to overwrite create in your own serializer.
I was not sure what is the difference between person and author. But you should be able to do something similar I suppose.

Django rest framework - Raising exception / Handling empty results while filtering

I have a user profile class and am checking if a user exists and if not want to create that user.
Am using the filter class for userprofile so that the client can call :
http://localhost:8000/users/?email=a#b.com
and if the result is empty will create a user with the email address.
Is there a way to intercept the query result and raise an exception when its empty and handle that to create the user.
If there is a better way would like to be corrected as well.
class UserQueryFilter(django_filters.rest_framework.FilterSet):
email = django_filters.CharFilter(name="user__email")
username = django_filters.CharFilter(name="user__username")
class Meta:
model = UserProfile
fields = ['email', 'username']
class UserViewSet(viewsets.ReadOnlyModelViewSet):
queryset = UserProfile.objects.all()
serializer_class = UserSerializer
filter_class = UserQueryFilter
Any help is appreciated.
Thanks
Anand
Django Rest Framework provide a functionality that is disabled by default. Maybe it could give you another approach to resolve your problem: PUT as create
In other hand, if you really need to create the user through a GET request with a querystring, you can use a MethodFilter from django-filters, for example:
class UserFilters(FilterSet):
user = MethodFilter(action='filter_user')
class Meta:
model = User
fields = ['user']
def filter_user(self, queryset, value):
if not value:
# Here Raise Exception
else:
# Check if the user exists, if not create it
users = queryset.filter(Q(username=value) | Q(email=value))
if not users.exists:
user = User.objects.create(...)
return queryset.filter(pk=user.id)
else:
return users
Hope this can help you. I'm not pretty sure about it works in that exact way but it's the idea.
Personally, I recommend you that try to execute that tasks through a more appropriate request like POST or PUT and manage in the corresponding method.

How do I serialize indirect relationships with querysets?

I have built a Django REST application to serve as backend API For an iOS project. In my object model I use 'Subscription' to join 'User' objects with 'Workspace' objects. Here's a part of my models.py simplified:
class User(models.Model):
# some property fields
class Workspace(models.Model):
# some property fields
class Subscription(models.Model):
# some property fields
user = models.ForeignKey(
User,
on_delete=models.CASCADE,
related_name='subscriptions')
workspace = models.ForeignKey(
Workspace,
on_delete=models.CASCADE,
related_name='subscriptions')
I have built class-based views for the objects so I can get a list of workspace objects with http GET from my iOS front end. For convenience reasons I want to include more than just the model fields, for example in the list of workspaces i want to include a list of subscribed users for every workspace object. I was advised to use SerializerMethodField() and querysets for serializing the field, but I don't know how to construct the queries. I've got this far:
class WorkspaceSerializer(serializers.ModelSerializer):
subscribed_users = serializers.SerializerMethodField()
class Meta:
model = Workspace
fields = ('id', 'subscribed_users')
def get_users(self, workspace):
users = User.objects.filter(???)
serializer = UserSerializer(instance=users, many=True)
return serializer.data
Getting subscriptions related to the workspace is easy because they're directly related, but how do I get users that are subscribed to the workspace in question?
The syntax I was looking for was double underscore, called spanning in DRF. For example:
def get_users(self, workspace):
users = User.objects.filter(subscription_set__workspace=workspace)
serializer = UserSerializer(instance=users, many=True)
return serializer.data

Resources