How to put annotation in rest-auth user - python

I am trying to add some annotation in authenticated User using rest-auth
Here is my code in serializers.py
class CustomUserSerializer(UserDetailsSerializer):
test = serializers.IntegerField()
class Meta:
model=User
fields='__all__'
And here is my code in views.py
class CustomUserView(UserDetailsView):
queryset= User.objects.annotate(test=Sum('logs__work_hours'))
serializer_class = CustomUserSerializer
but I am having this error after running the system
**
Got AttributeError when attempting to get a value for field test on
serializer CustomUserSerializer. The serializer field might be named
incorrectly and not match any attribute or key on the User instance.
Original exception text was: 'User' object has no attribute 'test'.
**

In this context, queryset is ignored.
Why? In your program, you're subclassing UserDetailsView from django-rest-auth. That implements get_object() like so:
def get_object(self):
return self.request.user
With no reference to the queryset variable.
You need to override get_object() in CustomUserView, copying the above implementation, and setting a test attribute on the user.
def get_object(self):
user = self.request.user
user.test = ... # put query to get value of test here
return user

Related

Bookmarking function django/python

I'm looking to create a model for users to bookmark a recipe. I have the below:
models.py
class RecipeBookmark(models.Model):
recipe = models.ForeignKey(
Recipe, on_delete=models.PROTECT, related_name="bookmarks"
)
bookmarked_by = models.ForeignKey(User, on_delete=models.PROTECT)
bookmarked_at = models.DateTimeField(auto_now_add=True)
serializers.py
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = models.User
fields = ["username", "email", "date_joined"]
class RecipeBookmarkSerializer(serializers.ModelSerializer):
bookmarked_by = UserSerializer(read_only=True)
class Meta:
model = models.RecipeBookmark
fields = ["recipe", "bookmarked_by", "bookmarked_at"]
def create(self, validated_data):
request = self.context["request"]
ModelClass = self.Meta.model
instance = ModelClass.objects.create(
**validated_data, **{"bookmarked_by": request.user}
)
return instance
views.py
#permission_classes([IsAuthenticated])
class RecipeBookmarkView(generics.CreateAPIView):
queryset = models.RecipeBookmark.objects.all()
serializer_class = RecipeBookmarkSerializer
urls.py
path("recipes/bookmarks/", PublishedRecipeBookmarkView.as_view()),
I want to perform a lookup, given the recipe id through a POST request, to add the user to the bookmarks field, if the user already exists in the bookmarks field, to remove that user form the field (remove the bookmark). Many users can bookmark a given recipe.
Also, How can a lookup be performed to return recipes that a logged in user has bookmarked via an api endpoint?
Current error with get_or_create():
Error: Internal Server Error
Response body
Download
AttributeError at /api/recipes/bookmarks/
Got AttributeError when attempting to get a value for field recipe on serializer RecipeBookmarkSerializer.
The serializer field might be named incorrectly and not match any attribute or key on the tuple instance.
Original exception text was: 'tuple' object has no attribute 'recipe'.
If you want your serializer to ensure that only one bookmark is created per user per recipe, you can use get_or_create:
def create(self, validated_data):
request = self.context["request"]
ModelClass = self.Meta.model
instance = ModelClass.objects.get_or_create(
**validated_data, **{"bookmarked_by": request.user}
)
return instance
If the bookmark is already present, it will just grab it and return.
Also, How can a lookup be performed to return recipes that a logged in user has bookmarked via an api endpoint?
To support this, you can define ListCreateAPIView to your view and override the queryset like so:
class RecipeBookmarkView(generics.ListCreateAPIView):
def get_queryset(self):
queryset = super().get_queryset()
return queryset.filter(bookmarked_by=self.request.user)
This will then support getting all the RecipeBookmark that is owned by the current user via GET requests on recipes/bookmarks/

Why Django REST Framework nested serializer self.instance always returns None?

I have model,
class Profile(models.Model)
user = models.OneToOneField(User)
And my serializer classes are,
class UserSerializer(serializers.ModelSerializer):
def validate(self, attrs):
print(self.instance) # Always prints None
print(self.parent.instance.user) # Prints User instance
return attrs
class Meta:
model = User
class ProfileSerializer(serializer.ModelSerializer):
user = UserSerializer()
class Meta:
Model = Profile
And my view class,
class ProfileView(APIView):
def update(self, request):
profile = ProfileSerializer(request.user.profile, data=request.data, partial=True)
if profile.is_valid():
profile.save()
return Response(status=HTTP_204_NO_CONTENT)
return Response({'error': profile.errors}, status=status.HTTP_400_BAD_REQUEST)
Why self.instance inside validate() method in nested serializer always returns none?
When do you see that? On creation?
In that case self.instance is populated inside the save() method with the result of create() method that's called after `validate().
Here you can read
When passing an initial object or queryset to a serializer instance, the object will be made available as .instance. If no initial object is passed then the .instance attribute will be None.
When you are in a child serializer, you can access the instance using the parent field, instead the instance field, something like this:
if self.parent is not None and self.parent.instance is not None:
instance = getattr(self.parent.instance, self.field_name)
check_query = check_query.exclude(pk=user.pk)
Seem that you need to do that validation in the parent
https://www.django-rest-framework.org/api-guide/validators/#updating-nested-serializers
In the case of update operations on nested serializers there's no way of applying this exclusion, because the instance is not available.
Again, you'll probably want to explicitly remove the validator from the serializer class, and write the code the for the validation constraint explicitly, in a .validate() method, or in the view.

Attribute error when attempting to get a value for field

I'm working with the django rest framework and the serializer I'm trying to use is creating errors. I'm trying to do something like https://gist.github.com/anonymous/7463dce5b0bfcf9b6767 but I still get the error. the models are
class Visitor(models.Model):
user = models.OneToOneField(User)
check_ins = models.IntegerField(default=0)
#classmethod
def create(cls, username, email, password):
user = User.objects.create_user(username, email, password)
visitor = cls(user=user)
visitor.save()
return visitor
def __str__(self):
return self.user.username
and the default user class and the serializers are
class UserSerializer(serializers.ModelSerializer):
class Meta:
model=User
fields = ('username')
class VisitorSerializer(serializers.ModelSerializer):
user = UserSerializer()
class Meta:
model=Visitor
fields = ('id','check_ins','user')
I get this error
Got AttributeError when attempting to get a value for field user on serializer VisitorSerializer.
The serializer field might be named incorrectly and not match any attribute or key on the QuerySet instance.
Original exception text was: 'QuerySet' object has no attribute 'user'.
The issue is that you are passing a queryset into your serializer without setting the many flag. The error is telling you that the serializer is trying to access queryset.user when it should be accessing visitor.user, so you need to tell the serializer that there are multiple objects (instead of a single one) by passing many=True.

Serializing NotificationQuerySet from django-notifications-hq not working

So, i'm trying to add to my API made with DRF (Django REST Framework) the notifications Model, but i'm getting this error:
AttributeError: 'NotificationQuerySet' object has no attribute 'recipient'
I'm trying to serialize a django app model, Notification. It's from this app:
https://github.com/django-notifications/django-notifications
My ViewSet class is this:
class NotificationsViewSet(viewsets.ViewSet):
serializer_class = NotificationsSerializer
def list(self, request):
queryset = Notification.objects.all()
return Response(NotificationsSerializer(queryset).data)
And here my serializer:
class NotificationsSerializer(serializers.ModelSerializer):
class Meta:
model = Notification
fields = ('recipient','description')
depth = 0
So, when data pass to serializer, it becomes "Void" or without any data.
Doing something like into the list method:
print queryset[0] returns a Notification object normaly. But when passing this queryset to the serializer, seems to be null, and the AttributeError comes.
Also, tried this with the console:
notifications = Notification.objects.all()
That returns a NotificationQuerySet object (iterable). Then I can:
for noti in notifications:
print noti
That would output all the unicode methods of every notification.
With every Notification instance, i can also access to Model propierties:
for noti in notifications:
print noti.recipient
And works very well.
Why is not working when passing this to the serializer? Its weird...
You need to pass many=True when initializing a serializer with a queryset. DRF will assume you are passing a single object and try to get the fields directly from it if you do not tell it that you are passing in multiple objects.
Heres a full implementation where the readme leaves off for drf
urls.py
...
import notifications.urls
urlpatterns = [
...
path("inbox/notifications/", views.NotificationViewSet.as_view({'get': 'list'}), name='notifications'),
]
serializers.py
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = get_user_model()
class NotificationSerializer(serializers.Serializer):
recipient = UserSerializer(read_only=True)
unread = serializers.BooleanField(read_only=True)
target = GenericNotificationRelatedField(read_only=True)
verb = serializers.CharField()
views.py
from notifications.models import Notification
from .serializers import NotificationSerializer
NotificationViewSet(viewsets.ViewSet):
serializer_class = NotificationSerializer
def list(self, request):
queryset = Notification.objects.all()
return Response(NotificationSerializer(queryset, many=True).data)

What is wrong with the custom method in DetailView

I am trying to compare the PK in the URL with the request.user.id so that no one can view other's profile. This might not be the conventional way to do it, but I'd still like to know what is wrong with my code. I'm a new learner so bear with me.
views.py
class UserDetail(DetailView):
queryset = Profile.objects.all()
template_name = 'details.html'
def get_queryset(self):
if self.request.user.id != self.kwargs['pk']:
queryset = Profile.objects.first()
return queryset
else:
return self.queryset
models.py
class Profile(AbstractUser):
type = models.CharField(max_length=50)
urls.py
url(r'^details/(?P<pk>\d+)/$', login_required(views.UserDetail.as_view())),
When I go to the URL:
ERROR
Exception Type: AttributeError
Exception Value: 'Profile' object has no attribute 'filter'
A Profile instance is not a queryset.
You shouldn't be overriding get_queryset, you should be overriding get_object, which returns the specific object you want to display.

Categories