New to Django and Django Rest here.
I have the following structure :
class MyUsers(AbstractUser):
email = models.EmailField(unique=True)
USERNAME_FIELD = 'email'
class roles(models.Model):
id = models.AutoField(primary_key=True)
label = models.CharField(max_length=80)
class user_roles(models.Model):
id_user = models.ForeignKey(MyUsers,on_delete=models.CASCADE)
id_role = models.ForeignKey(roles,on_delete=models.CASCADE)
I'm trying to create a custom permission, to allow users with a specific role to access some endpoints.
class IsAuthenticatedAndLeader(BasePermission):
def has_permission(self, request, view):
id_role=models.roles_users.objects.filter(id_user=request.user.id).values_list('id_role',flat=True)
if "Leader" in models.roles.objects.filter(id=id_role).values_list('label',flat=True):
return request.user and request.user.is_authenticated
def has_object_permission(self, request, view, obj):
return True
When I try to access to the endpoint, I have the following error:
TypeError: argument of type 'QuerySet' is not iterable
However if I try in views.py something simple like the following it works :
if "Leader" in models.roles.objects.filter(id=3).values_list('label',flat=True):
print("Yes")
So I'm not sure why I'm getting this error when trying to apply it to permissions.py
I think your problem its
id_role=models.roles_users.objects.filter(id_user=request.user.id).values_list('id_role',flat=True)
if "Leader" in models.roles.objects.filter(id=id_role).values_list('label',flat=True):
id_role is a list and you can get roles where id=(ids....)
then it not works, try with:
if "Leader" in models.roles.objects.filter(id__in=id_role).values_list('label',flat=True):
Related
I'm trying to obtain a user instance for the profile page in django app but I'm finding some difficulties implementing that functionality. I have the following blocks of code:
models.py
class Profile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, primary_key=True, on_delete=models.CASCADE, default="")
image = models.ImageField(upload_to="images/user_profile_pics/", default="images/default_profile_pics/default.jpg")
firstname = models.CharField(max_length=50)
lastname = models.CharField(max_length=50)
def __str__(self):
return f'{self.lastname} profile'
serializers.py
class user_profile_serializer(serializers.ModelSerializer):
class Meta:
model = Profile
fields = '__all__'
views.py
class user_profile(generics.GenericAPIView):
serializer_class = user_profile_serializer
def get(self, request, *args, **kwargs):
user = self.get_serializer(request.user).data
if request.user.is_authenticated:
return Response(user, status=status.HTTP_200_OK)
else:
pass
urls.py
urlpatterns = [
path('profile/', user_profile.as_view(), name="user-profile"),
]
When ever I assess the profile url, I get an error message 'AnonymousUser' object has no attribute 'data' I have tried a couple of approaches but none worked. Please, how do I obtain a specific user from the database?
request.user is AnonymousUser when the user is not logged in. In that case that object does not have data attribute. Hence the error you get. One thing you can do is check request.user.is_authenticated and if the user is not authenticated, return some other value / or None. And try logging in before trying to access the user.data value.
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/
I want a custom authentication which will authenticate the token in my model.I have a model called User_Auth where there is a field called 'secret_token'. I want the Django Rest Framework to Authenticate token through that model.
I had followed the docs on django rest framework website but didnt work for me.
Please help me to solve this issue.
models.py
class User_Auth(models.Model):
id = models.AutoField(primary_key=True)
user = models.ForeignKey(User_Master, on_delete=models.CASCADE)
secret_token = models.CharField(max_length=2000, null=True, blank=True)
authentication.py
class UserAuthentication(authentication.TokenAuthentication):
def authenticate(self, request):
secret_token = request.META.get('Authorization')
if not secret_token:
return None
try:
ua = User_Auth.objects.get(secret_token=secret_token)
except User_Auth.DoesNotExist:
raise exceptions.AuthenticationFailed('Unauthorized')
return (ua, None)
views.py
class User(viewsets.ModelViewSet):
authentication_classes = (UserAuthentication,)
permission_classes = (IsAuthenticated,)
I am passing the token through the Header.
Authorization: 'a7c14fc808b58533e4d1651cd2375c3b41a38ef5d120254a1cb4bbd90b3be1534215516b023818e4'
Its Returning this error
'User_Auth' object has no attribute 'is_authenticated'
Please help me.
You are missing is_authenticated property in User_Auth model. This is a read only attribute and always return True for a valid user. Django's User class has this attribute and internally it has been used for authentication.
So to resolve the error add this attribute in User_Auth class like following.
class User_Auth(models.Model):
id = models.AutoField(primary_key=True)
user = models.ForeignKey(User_Master, on_delete=models.CASCADE)
secret_token = models.CharField(max_length=2000, null=True, blank=True)
#property
def is_authenticated(self):
"""
Always return True. This is a way to tell if the user has been
authenticated in templates.
"""
return True
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.
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)