Thanks in advance for looking.
The goal:
In short: Update django user object and custom user profile object only if there is a change from a single view.
The problem:
For starters, this is my first time trying to do anything like this, so it may be something really simple and I am just overlooking it.
It seems to be failing on validation steps and I am getting an HTTP 400 error saying 'username must be unique', even when I am not sending a change that would be changing the current users username. Now I could probably use the view that is built into django-rest-auth to update just the user portion, then create just a custom view that only updates the profile. But that seems hacky and silly, but if it is the way to go then I will do it.
Things I have tried:
request.data
before validation if it is the same, but that gave another error saying it is required. Serializers:
class UserSerializer(ModelSerializer):
class Meta(UserDetailsSerializer.Meta):
model = User
fields = ('username', 'email', 'first_name', 'last_name')
read_only_fields = ('email', )
class UserProfileSerializer(ModelSerializer):
user = UserSerializer(required=True, many=False)
games = UserGameProfileSerializer(required=False, many=True)
class Meta:
model = UserProfile
fields = ('premium', 'user', 'games')
View:
class UserProfileUpdateView(generics.UpdateAPIView):
# authentication_classes = (authentication.TokenAuthentication,)
# permission_classes = (permissions.IsAuthenticated,)
serializer_class = UserProfileSerializer
def get_queryset(self):
return UserProfile.objects.filter(user__username__exact=self.request.user).all()
def get_object(self):
return UserProfile.objects.filter(user__username__exact=self.request.user).get()
Disclaimer
I was finally able to figure it out and I am only answering for future reference. I am not sure if this is best practice or the easiest way to accomplish the task. However, this is what I was able to come up with.
I changed the view to be simpler instead of that nasty looking filter query I found I could do a get object and just say user=self.request.user
and that would get what I needed.
View
class UserProfileUpdateView(generics.UpdateAPIView):
authentication_classes = (authentication.TokenAuthentication,)
permission_classes = (permissions.IsAuthenticated,)
serializer_class = UserProfileSerializer
def get_object(self):
return UserProfile.objects.get(user=self.request.user)
Then in the serializer I figured out how to update nested objects which is exactly what needed to be done. Now I realize that currently I am only really updating the built in django object. But soon I will be adding more fields to the user profile and will need to update those and if there are changes to the user object I wanted to update them in the same request.
In the update function you can access the request data with self.data
and in there I was able to access the dict containing the user information. With that I was able to query for the user object, then using the UserSerializer I was able to validate the data and call update passing the user I queried for and the validated data from the serializer.
Serializer
class UserProfileSerializer(ModelSerializer):
user = UserSerializer(required=True, many=False)
games = UserGameProfileSerializer(required=False, many=True)
class Meta:
model = UserProfile
fields = ('premium', 'user', 'games')
read_only_fields = ('premium', )
def update(self, instance, validated_data):
user_data = validated_data.pop('user')
game_data = validated_data.pop('games')
username = self.data['user']['username']
user = User.objects.get(username=username)
print user
user_serializer = UserSerializer(data=user_data)
if user_serializer.is_valid():
user_serializer.update(user, user_data)
instance.save()
return instance