I perform request http://167.71.57.114/api/users/list-exercises
And receive error
User matching query does not exist.
How can I fix the error?
Found out that reason of the error is that request didn't have any data
But you can see that I am sendig the "user_id"
My code
class WorkoutUserProgramListViewAPI(GenericAPIView):
permission_classes = (IsAuthenticated,)
serializer_class = WorkoutUserProgramListSerializer
def get(self, request):
response = {}
user = request.data.get("user_id") # user is None
user = User.objects.get(pk=user) # Error User matching query does not exist.
Like #Klaus D said in the comments, you would rather put a user-id as a parameter. If you're sending user_id=29, I would add that as a parameter, which should change the URL to be something like
http://167.71.57.114/api/users/list-exercises?user_id=29
That error occurs when the objects.get method does not find any result.
If you use filter and verify that the result is not None you avoid that error in the case that the id passed by parameter does not belong to any user.
class WorkoutUserProgramListViewAPI(GenericAPIView):
permission_classes = (IsAuthenticated,)
serializer_class = WorkoutUserProgramListSerializer
def get(self, request):
response = {}
user_id = request.data.get("user_id")
user = User.objects.filter(pk=user_id).first()
if user is not None:
# code
else:
# code
Listen what Klaus D. tells you, too.
Related
I've been trying to create a drf app and wanted to achieve a sign in view that does two things:
set's the cookies automatically
returns the url and the username of the user
the issue is specifically in the validate function inside the serializer code
views.py:
class CookieTokenObtainPairView(TokenObtainPairView):
def finalize_response(self, request, response, *args, **kwargs):
if response.data.get("refresh"):
# the cookie part works well
# the part that doesn't is in the serializer below
user = UserLoginSerializer(data=request.data)
user = user.validate(data=request.data) if user.is_valid()
response.data["user"] = user.data if user.is_valid() else user.errors
return super().finalize_response(request, response, *args, **kwargs)
serializers.py
class UserLoginSerializer(serializers.HyperlinkedModelSerializer):
password = serializers.CharField(style={"input type": "password"}, write_only=True)
#
class Meta:
model = User
fields = (
"id",
"url",
"username",
"password",
)
# read_only_fields = ("id")
def validate(self, data):
data["username"] = self["username"]
data["password"] = self["url"]
return super().validate(data)
so as you can see the validate option is trying to get the username and the url data to return it, but instead it's trying to create a new account. so maybe the validate option was not right. I researched on the drf docs but there seem to be an entirely other function called create. so I don't know how validate is not working. maybe I'm supposed to type in another function
In your validate function, you cannot access self['username'] – you can only access user data through self.instance; but, otherwise, you only can access the instance if you passed it to the serializer in a construct like:
user_serializer = UserLoginSerializer(data=request.data, instance=user_obj)
What do you need is after user login, so I recommend to you this post: Login and Register User Django Rest Framewrok; I am pretty sure you can get what you need there.
I have a view that I want to use to pull Model data + get data from an external API. Using the same URL path to get database data + external API data, as they are both relatively connected in terms of business logic.
This is how I tried implementing it:
class BucketList(generics.ListAPIView):
permission_classes = [IsAuthenticated]
serializer_class = BucketListSerializer
filter_backends = [OwnerOrUserFilterBackend]
queryset = Bucket.objects.all()
# I use a field in my model as part of my GET request
def get(self, request, *args, **kwargs):
bucket_symbols = Bucket.objects.only('stock_list')
symbols_unicode = (','.join(map(str, bucket_symbols)))
postgrest_urls = f"http://localhost:3000/rpc/bucketreturn?p_stocks=%7B{symbols_unicode}%7D"
response = requests.get(postgrest_urls, headers={'Content-Type': 'application/json'}).json()
return Response(response, status=status.HTTP_200_OK)
The idea of def get(), is to extract every stock_list field in objects, and feed that into my other API on localhost. To clarify, I want every stock_list in object passed into my get requests and returned, for each object.
However I keep getting undefined errors in my JSON response.
How can I properly implement a two-in-one view solution for my view, I still want to keep my original queryset = Bucket.objects.all() in my view.
I am using drf-nested-router something like the following in my url.py
router = SimpleRouter()
profile_router = routers.NestedSimpleRouter(router, r'profile', lookup='user')
profile_router.register(r'comments', UserCommentViewSet, basename='profile-comments')
The viewset is
class UserCommentViewSet(CommentViewSet):
def get_queryset(self):
return Comment.objects.filter(owner=self.request.user)
So the URL is something like,
mydomain.com/profile/{profile_id}/comments/
it gives me right results. But the following URL is also giving me right results,
mydomain.com/profile/{anything}/comments/
because I am using the session user info to filter the data. Is it possible to make the URL like
mydomain.com/profile/comments/
Based on your code:
router = SimpleRouter()
# router.register('users', UserViewSet, 'user')
profile_router = routers.NestedSimpleRouter(router, r'profile', lookup='user')
profile_router.register(r'comments', UserCommentViewSet, basename='profile-comments')
You are interpreting this in a wrong way. Here's how you can use NestedSimpleRouter
mydomain.com/profile/ # list all the users.
mydomain.com/profile/{profile_id} # retrieve particular user based on profile_id/user_id/pk.
mydomain.com/profile/{profile_id}/comments/ # list all the comments belong to a particular user (not the current session user) based on profile_id/user_id.
mydomain.com/profile/{profile_id}/comments/{comment_id} # retrieve particular comment based on comment_id.
This url:
mydomain.com/profile/{anything}/comments/
is working because you are filtering by owner = request.user.
And this url:
mydomain.com/profile/{profile_id}/comments/
is supposed to give list of all comments by taking profile_id in UserCommentViewSet. So your view will be like:
class UserCommentViewSet(CommentViewSet):
def get_queryset(self):
return Comment.objects.filter(owner__id=profile_id)
In simple words you can use NestedSimpleRouter to get all users, user detail, all comments posted by single user and comment detail.
Solution:
If you need only current (session) user comments (since you dont need all comments by all users), you need something like:
router = SimpleRouter()
router.register(r'profile/comments', UserCommentViewSet, basename='profile-comments')
and the UserCommentViewSet is:
class UserCommentViewSet(CommentViewSet):
def get_queryset(self):
return Comment.objects.filter(owner=self.request.user)
Then, this url:
mydomain.com/profile/comments/
will give all comments as required.
I'm working on an API and have this ViewSet:
class ProjectViewSet(viewsets.ModelViewSet):
# API endpoint that allows projects to be viewed or edited.
queryset = Project.objects.all()
serializer_class = ProjectSerializer
authentication_classes = used_authentication_classes
permission_classes = (IsOwner,)
#detail_route(methods=['get'])
def functions(self, request, pk=None):
project = self.get_object()
if project is None:
return Response({'detail': 'Missing project id'}, status=404)
return Response([FunctionSerializer(x).data for x in Function.objects.filter(project=project)])
A permission system is attached to this API. The permissions work fine for a single resource. But when I call api/projects which should return all of the projects the user has access to, it does in fact return all of the projects, regardless whether the user should be able to GET a certain project in the list or not.
So I overwrote the get_queryset method to only return the projects the user has access to:
def get_queryset(self):
if self.request.user.is_superuser or self.request.user.is_staff:
return Project.objects.all()
else:
return Project.objects.filter(user=self.request.user.user)
This works, but now the API returns a 404 instead of a 403 when I ask for a specific resource I don't have access to.
I understand why, because the PK from the resource I try to get is undefined since I only return projects the user has access to. What I don't understand is how to fix this.
Does anyone know how I can make it return a 403, or maybe an idea towards where I should look?
as #Alasdair say the 404 is a deliberate choice, but if you still want to get 403 you can try:
def get_queryset(self):
user = self.request.user
allow_all = user.is_superuser or user.is_staff
if self.action == 'list' and not allow_all:
return Project.objects.filter(user=user)
return Project.objects.all()
I am using Django REST Framework to create an endpoint that will produce a PDF document. The PDF document will have information that corresponds to a particular Department. I have two desired functionalities -- to be able to download a PDF document, and to be able to preview the document within the browser.
Since the PDF document changes over time based on data that is added to the app, the document needs to be generated in real time when it is requested. As a first step, I'm trying to have the document be generated in a remote file storage location when the following endpoint is hit by a GET request:
departments/<department_pk>/result/preview
Since my endpoint should only take GET requests, I am using a ListAPIView. I'm trying to override the list method so that my custom document generation logic is executed, but it looks like the method is never called. How can I have some custom document generation logic be inserted into my endpoint, so that it is executed when the endpoint is hit by a GET request?
api/urls.py
url(r'^departments/(?P<department_pk>[0-9]+)/result/preview',
include(result_document_urls.result_document_preview_router.urls,
document_app/urls.py
result_document_preview_router = routers.DefaultRouter()
result_document_preview_router.register(r'^', ResultDocumentDetailView.as_view(),
base_name='Department')
document_app/views.py
class ResultDocumentDetailView(generics.ListAPIView):
queryset = Department.objects.all()
lookup_field = 'department_pk'
lookup_url_kwarg = 'department_pk'
def list(self, request, department_pk):
queryset = self.get_queryset()
import ipdb; ipdb.set_trace() # this break point is never hit
department = get_object_or_404(queryset, department_pk=department_pk)
...generate document logic...
return Response(status=status.HTTP_200_OK)
replace list method with below code, I think it will work
class ResultDocumentDetailView(generics.ListAPIView):
queryset = Department.objects.all()
lookup_field = 'department_pk'
lookup_url_kwarg = 'department_pk'
def list(self, request, *args, **kwargs):
queryset = self.get_queryset()
import ipdb; ipdb.set_trace() # this break point is never hit
department = get_object_or_404(
queryset, department_pk=kwargs.get('department_pk')
)
...generate document logic...
return Response(status=status.HTTP_200_OK)
for more reference see the overrinding method "list"
https://github.com/tomchristie/django-rest-framework/blob/master/rest_framework/mixins.py#L35
In your document_app/urls.py, you are incorrectly passing ResultDocumentDetailView as an argument instead of a viewset.
Router while registering accepts a ViewSet instead of an APIView.
There are two mandatory arguments to the register() method:
prefix - The URL prefix to use for this set of routes.
viewset - The viewset class.
Also, since you are only interested in the retrieve method, you can just create a ResultDocumentRetrieveView and add its corresponding url to your urls.py without the need of creating a ResultDocument router. (Routers are generally used when you want to handle both list and detail requests.)
class ResultDocumentRetrieveView(generics.RetrieveAPIView):
queryset = Department.objects.all()
lookup_field = 'department_pk'
lookup_url_kwarg = 'department_pk'
def retrieve(self, request, department_pk):
department = self.get_object()
...generate document logic...
return Response(status=status.HTTP_200_OK)
urls.py
url(r'^departments/(?P<department_pk>[0-9]+)/result/preview', ResultDocumentRetrieveView.as_view())