I want to make sure the request.user can only issue a POST request to create a forum topic in which they are the auther. With PUT and DELETE I'm able to achieve that by using the has_object_permission but with POST I'm not able to do that, I'm guessing because the object hasn't been created yet.
class TopicPermission(IsAuthenticatedOrReadOnly):
"""
Any user should be able to read topics but only authenticated
users should be able to create new topics. An owner or moderator
should be able to update a discussion or delete.
"""
def has_object_permission(self, request, view, obj):
if request.method in SAFE_METHODS:
return True
# Instance must have an attribute named `author` or moderator
return obj.author == request.user or request.user.forum_moderator
How would I go about verifying request.user == obj.author in POST requests?
I ended up doing the validation in the viewset instead of the serializer:
class TopicViewSet(viewsets.ModelViewSet):
permission_classes = (TopicPermission, )
queryset = Topic.objects.all()
serializer_class = TopicSerializer
def create(self, request, *args, **kwargs):
"""
verify that the POST has the request user as the obj.author
"""
if request.data["author"] == str(request.user.id):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
self.perform_create(serializer)
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=201, headers=headers)
else:
return Response(status=403)
Related
Creating a custom permission to ensure only the user who owns an instance of the user object can update it like so
class UserUpdatePermission(BasePermission):
message = 'only users can edit their profile'
def has_permission(self, request, view):
return request.user.is_authenticated
def has_object_permission(self, request, view, obj):
if request.method in SAFE_METHODS:
return True
request.user == User.objects.get(username=view.kwargs['username'])
#api_view(['POST'])
#permission_classes([UserUpdatePermission])
#parser_classes([FormParser, MultiPartParser])
def UpdateUserProfile(request, username):
user = User.objects.get(username=username)
serializer = UpdateUserSerializer(instance=user, data=request.data)
if serializer.is_valid(raise_exception=True):
serializer.save()
return Response(serializer.data)
From inserting print statements around the code, i noticed the has_permission function in the class is being called but not the has_object_permission function. So, the object level permission isn't working. What am i getting wrong here?
I have a model of uploads and i want to associate the uploaded images to the user so that later each user can only view his objects so so i m trying to save the created objects to the authenticated user, but it's not working and i keep getting owner =null on my model
#api_view(['GET', 'POST'])
def Upload_list(request):
if request.method == 'GET':
queryset = Uploads.objects.all()
uploads=queryset.filter(owner=request.user)
serializer = UploadSerializer(uploads, many=True)
return Response(serializer.data)
elif request.method == 'POST':
serializer = UploadSerializer(data=request.data)
if serializer.is_valid():
serializer.save(owner=request.user)
respFile=list(File.objects.filter(id=str(File.objects.latest('created_at'))))
return Response(respFile)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
Edit : i think the problem is in the Post request itself it is not overriding the default method therefore the changes i apply do not work any idea how to change the post method ?
try this
class IsOwnerFilterBackend(filters.BaseFilterBackend):
def filter_queryset(self, request, queryset, view):
queryset=Uploads.objects.all()
return queryset.filter(owner=request.user)
class UploadView(viewsets.ModelViewSet):
queryset=Uploads.objects.all()
serializer_class=UploadSerializer
filter_backends = (IsOwnerFilterBackend,)
#api_view(['GET', 'POST'])
def methodes(self,request,*args,**kwargs):
if request.method=='POST':
serializer=UploadSerializer(data=request.data)
if serializer.is_valid():
serializer.save(owner=request.user)
return Response("test_token success", status=status.HTTP_200_OK)
return HttpResponse({'message':'error'},status=400)
elif request.method=='GET':
images=Uploads.objects.filter(owner=request.user)
serializers=UploadSerializer(images[0],many=False)
return JsonResponse(serializers.data,safe=False)
So I have this view, I passed the request through the context to the serializer so I can use it to get the user
def create(self, request, *args, **kwargs):
""" Handle member creation from invitation code. """
serializer = AddMemberSerializer(
data=request.data,
context={'circle': self.circle, 'request': request}
)
serializer.is_valid(raise_exception=True)
member = serializer.save()
data = self.get_serializer(member).data
return Response(data, status=status.HTTP_201_CREATED)
In the serializer I did this but it does not work,I get "KeyError: 'user'", I ran a debugger and when I tried to call the get_user method it says "TypeError: get_user() missing 1 required positional argument: 'obj'"
user = serializers.SerializerMethodField()
def get_user(self, obj):
request = self.context.get('request', None)
if request:
return request.user
So what am I missing? I looked up other implementations of this field and none of them seem very different of mine, so I would really apreciate it if someone explains to me why it is not working.
Also if there is a more efective way to get the user into a field (Need it to run a user_validate method on it)
Try:
user = serializers.SerializerMethodField()
def get_user(self, obj):
return obj.user_id
I'm new to django rest framework, and I'm trying to learn drf. I didn't know how to achieve this features. I want some things like(Extra Actions) as shown in screenshot to navigate all the endpoint.
Here is an example from official DRF documentation:
class UserViewSet(viewsets.ModelViewSet):
"""
A viewset that provides the standard actions
"""
queryset = User.objects.all()
serializer_class = UserSerializer
#action(detail=True, methods=['post'])
def set_password(self, request, pk=None):
user = self.get_object()
serializer = PasswordSerializer(data=request.data)
if serializer.is_valid():
user.set_password(serializer.data['password'])
user.save()
return Response({'status': 'password set'})
else:
return Response(serializer.errors,
status=status.HTTP_400_BAD_REQUEST)
#action(detail=False)
def recent_users(self, request):
recent_users = User.objects.all().order_by('-last_login')
page = self.paginate_queryset(recent_users)
if page is not None:
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
serializer = self.get_serializer(recent_users, many=True)
return Response(serializer.data)
For more, please visit: Viewset actions
I'm using the DjangoRestFramework. I have a UserSerialzer in my serializers.py file:
from django.contrib.auth.models import User
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('username', 'password', 'email', )
This is my urls.py file:
urlpatterns = [
url(r'^$', views.HomePageView.as_view()),
url(r'^users$', views.user_list.as_view()),
url(r'^users/(?P<pk>[0-9]+)$', views.user_detail.as_view()),
]
and this is my views.py file:
class HomePageView(TemplateView):
template_name = "home.html"
def get_context_data(self, **kwargs):
context = super(HomePageView, self).get_context_data(**kwargs)
# context['users'] = User.objects.all()
return context
class user_list(APIView):
"""
List all users, or create a new user.
"""
serializer_class = UserSerializer
def get(self, request):
users = User.objects.all()
serializer = UserSerializer(users, many=True)
return Response(serializer.data)
def post(self, request):
serializer = UserSerializer(data=request.DATA)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
class user_detail(APIView):
"""
Get, update or delete a specific user.
"""
serializer_class = UserSerializer
def get_object(self, pk):
try:
return User.objects.get(pk=pk)
except User.DoesNotExist:
return Response(status=status.HTTP_404_NOT_FOUND)
def get(self, request, pk):
user = self.get_object(pk)
serializer = UserSerializer(user)
return Response(serializer.data)
def put(self, request, pk):
user = self.get_object(pk)
serializer = UserSerializer(user, data=request.DATA)
if serialzier.is_valid():
serializier.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def delete(self, request, pk):
user = self.get_object(pk)
user.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
When I go to 127.0.0.1:8000/users, DjangoRestFramework has the API page which shows a list of users (JSON objects) and it also has a form which has "username", "password" and "email". This form seems to be validating correctly (checks if the email is a real email, and checks if username is unique and less than 30 characters). Is there a way for me to pass this form to the frontend when a user goes to 127.0.0.1:8000 (calling HomePageView)?
I'm in the process of using AngularJS on the frontend (not sure if this information helps or not).
Well here are a few things I think we might need to point out. Django forms are normally what you would use to create a new user, with a post request just like you are trying to do through DRF. Now you can do this through DRF, but thats not really what it is for, django forms would be more appropriate for what you are doing. Unless of course you are building an API that you want API users to be able to use to create new users on your platform, in which case continue onward. I am linking a tutorial I used when I first started using DRF with Angular, maybe you will find it helpful.
http://blog.kevinastone.com/getting-started-with-django-rest-framework-and-angularjs.html