this is my
views.py
class UserAPI(generics.RetrieveAPIView):
permission_classes = [permissions.IsAuthenticated,]
serializer_class = UserSerializer
def get_object(self):
return self.request.user
and this is my url.py
path('V1/api/users/', UserAPI.as_view(), name='user'),
when i enter id,mail,username and go to
localhost/v1/api/users/1 want to open user's which id is 1.
what is best solutions ?
Your problem comes from your url settings your should add primary key to the url. Change this
path('V1/api/users/', UserAPI.as_view(), name='user')
To this
path('V1/api/users/<pk>/', UserAPI.as_view(), name='user'),
path('V1/api/users/<int:user_id>', UserAPI.as_view(), name='user'),
class UserApi(generics.RetrieveAPIView):
permission_classes = [permissions.IsAuthenticated,]
serializer_class = UserSerializer
def get(self, request, user_id, format=None):
print(user_id) # do whatever you want with the user id
Related
I don't want to apply my permission_classes for get request. I tried #permission_classes([AllowAny]) but didn't work.
Here is my my code:
class BlogViewSet(viewsets.ModelViewSet):
queryset = Blog.objects.all()
serializer_class = BlogSerializer
pagination_class = BlogPagination
lookup_field = 'blog_slug'
permission_classes = [IsOwnerOrReadOnly & IsAuthorGroup]
#permission_classes([AllowAny])
def list(self, request):
if request.method == "GET":
blog = Blog.objects.all().order_by("id")
serializer = BlogSerializer(blog, many=True)
return Response(serializer.data)
else:
return Response(status=status.HTTP_404_NOT_FOUND)
I also tried this and getting local variable 'permission_classes' referenced before assignment for post put patch and delete request
class BlogViewSet(viewsets.ModelViewSet):
queryset = Blog.objects.all()
serializer_class = BlogSerializer
pagination_class = BlogPagination
lookup_field = 'blog_slug'
permission_classes = [IsOwnerOrReadOnly & IsAuthorGroup]
def get_permissions(self):
if self.action == "list":
permission_classes = [
AllowAny,
]
return [permission() for permission in permission_classes]
you can simply pass a permission class like this.
from rest_framework.permissions import IsAuthenticated, IsAuthenticatedOrReadOnly, AllowAny, IsAdminUser
class BlogViewSet(viewsets.ModelViewSet):
permission_classes = [IsAuthenticatedOrReadOnly,IsAuthenticated ]
queryset = Blog.objects.all()
serializer_class = BlogSerializer
pagination_class = BlogPagination
lookup_field = 'blog_slug'
And you can write your own permission classes to pass it. and user will access this view only if they will have all permissions.
Hope this will help you :)
I have the following two classes and I want two merge EventInvitationCreateView into EventInvitationViewSet.
However, I am struggling to bring perform_create into create_invitation as I still need to access serializer. Do you have any input on how to achieve that?
class EventInvitationCreateView(CreateAPIView):
serializer_class = InvitationSerializer
permission_classes = [RetoolPermission]
queryset = Invitation.objects.none()
def perform_create(self, serializer):
email = serializer.validated_data["email"]
event = self.request.event
invitation_exists = Invitation.objects.filter(
email__iexact=email, event=event
).exists()
if invitation_exists:
raise ValidationError("Email already exists")
serializer.save(event=event)
class EventInvitationViewSet(
mixins.CreateModelMixin, mixins.ListModelMixin, viewsets.GenericViewSet
):
permission_classes = [RetoolPermission]
serializer_class = InvitationSerializer
filter_backends = [filters.SearchFilter]
search_fields = ["email"]
queryset = Invitation.objects.none()
def get_queryset(self) -> QuerySet:
return self.request.event.invitations.all()
#action(detail=True, methods=["post"])
def create_invitation(self, request, pk=None):
[...perform_create]
the action is still a standard view's method, so you can use self.get_serializer()
for instance
#action(detail=True, methods=["post"])
def create_invitation(self, request, pk=None):
s = self.get_serializer(data=request.data)
....
If you need to use a "action specific serializer" you can specify the serializer class in the decorator
#action(detail=True, methods=["post"], serializer_class=MyOtherSerializer)
def create_invitation(self, request, pk=None):
s = self.get_serializer(data=request.data) # <-- instance of MyOtherSerializer
....
I have a small messaging API built with DRF which sends messages between users in the system.
My messages view contains several extra actions:
class MessagesViewSet(ModelViewSet):
"""
A simple ViewSet for viewing and editing the messages
associated with the user.
"""
authentication_classes = [TokenAuthentication, ]
permission_classes = [IsAuthenticated]
serializer_class = MessageSerializer
filter_backends = [DjangoFilterBackend]
filterset_fields = [MessageFields.MARK_READ]
def get_user(self):
user = self.request.user
return user
def get_queryset(self):
return Message.objects.filter(sent_to=self.get_user())
#action(detail=True)
def sent_messages(self, request, pk):
"""
Return all messages sent by the user.
"""
queryset = Message.objects.filter(sender=self.get_user())
serialized_data = MessageSerializer(queryset, many=True)
return Response(serialized_data.data, status=HTTP_200_OK)
#action(detail=True)
def last_50_messages(self, request, pk):
"""
Return the user's 50 last messages
"""
queryset = Message.objects.filter(sent_to=self.get_user())
serialized_data = MessageSerializer(queryset, many=True)
return Response(serialized_data.data, status=HTTP_200_OK)
Urls file:
from .views import MessagesViewSet
messages_router = DefaultRouter()
messages_router.register(r'messages', MessagesViewSet, basename='messages')
urlpatterns = [
url('', include(messages_router.urls))
]
Right now the only way to access the two custom methods is opening one of the message instances and then add it to the URL line and it'll work.
How can format the url for each method so it will be via the username?
right now:
http://127.0.0.1:8000/api/messages/1/sent_messages/
I looking for something like:
http://127.0.0.1:8000/api/messages/#request.user.username/sent_messages/
You have to change lookup_field value in ModelViewSet like this:
class MessagesViewSet(ModelViewSet):
...
lookup_field = "username"
...
But be careful, API like retrieve will be work with username lookup too, not pk.
To use both (username, lookup) check hook here:
class MultipleFieldLookupORMixin(object):
"""
Actual code http://www.django-rest-framework.org/api-guide/generic-views/#creating-custom-mixins
Apply this mixin to any view or viewset to get multiple field filtering
based on a `lookup_fields` attribute, instead of the default single field filtering.
"""
def get_object(self):
queryset = self.get_queryset() # Get the base queryset
queryset = self.filter_queryset(queryset) # Apply any filter backends
filter = {}
for field in self.lookup_fields:
try: # Get the result with one or more fields.
filter[field] = self.kwargs[field]
except Exception:
pass
return get_object_or_404(queryset, **filter) # Lookup the object
class RetrieveUserView(MultipleFieldLookupORMixin, generics.RetrieveAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
lookup_fields = ('account', 'username')
Using Django 1.11 & djangorestframework==3.7.7, I want to return Videos where is_thumbnail=True on a GET call. However, all of my testing with filters have been returning all Videos objects.
Model:
class Videos(models.Model):
"""This class represents the Videos model."""
uid = models.UUIDField(
primary_key=True, default=uuid.uuid4, editable=False)
is_thumbnail = models.BooleanField(default=False)
file_name = models.CharField(unique=True, max_length=64)
file_path = models.CharField(unique=True, max_length=256)
file_created_time = models.DateTimeField()
owner = models.ForeignKey('auth.User',
related_name='videos',
on_delete=models.CASCADE)
created_time = models.DateTimeField(auto_now_add=True)
def __str__(self):
"""Return a human readable representation of the model instance."""
return "{}".format(self.file_name)
view:
class DetailsView(generics.RetrieveUpdateDestroyAPIView):
"""This class handles the http GET, PUT and DELETE requests."""
serializer_class = VideosSerializer
permission_classes = (permissions.IsAuthenticated, IsOwner)
lookup_field = 'uid'
def get_queryset(self):
return Videos.objects.filter(is_thumbnail=True)
If I put a print statement inside of the get_queryset function, I don't see that statement in the log. So it seems like the function isn't being called.
api/urls.py
urlpatterns = {
url(r'^auth/', include('rest_framework.urls',
namespace='rest_framework')),
url(r'^api/videos/$', CreateView.as_view(), name="create"),
url(r'^api/videos/(?P<uid>[0-9a-f-]+)/$',
DetailsView.as_view(), name="details"),
url(r'^get-token/', obtain_auth_token),
}
securedash_project/urls.py
urlpatterns = format_suffix_patterns(urlpatterns)
urlpatterns = [
url(r'', include('secureDash.dash.urls')),
url(r'^dash/', include('secureDash.dash.urls')),
url(r'^admin/', admin.site.urls),
url(r'^', include('secureDash.api.urls')),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
Ok, you want to replace the value of the "get_queryset" method of the generic view "generics.RetrieveUpdateDestroyAPIView", which accesses the objects using the "uid" field setting like lookup_field to make the modification later, so I recommend that when you overwrite it the "get_queryset" method replaces them with the following:
def get_queryset(self):
return self.get_queryset().filter(is_thumbnail=True)
The issue that I was having was that I had a CreateView class that implemented generics.ListCreateAPIView. This view has r/w endpoints so my GET calls were never getting to my DetailsView. I need to adjust my views, but for now this works to only show is_thumbnail=True Videos.
class CreateView(generics.ListCreateAPIView):
"""This class defines the (GET & POST) behavior of the rest api."""
serializer_class = VideosSerializer
permission_classes = (permissions.IsAuthenticated, )
def perform_create(self, serializer):
"""Save the post data when creating a new Videos object."""
serializer.save(owner=self.request.user)
def get_queryset(self):
queryset = Videos.objects.all()
return queryset.filter(is_thumbnail=True)
class DetailsView(generics.RetrieveUpdateDestroyAPIView):
"""This class handles the http GET, PUT and DELETE requests."""
queryset = Videos.objects.all()
serializer_class = VideosSerializer
permission_classes = (permissions.IsAuthenticated, IsOwner)
lookup_field = 'uid'
I am having a go at the django-rest-framework. It was all going fine until I got to the Relationships & Hyperlinked API part of the tutorial. The error I am getting now after messing with it for a bit is:
ImproperlyConfigured at /api/users/ "^\.(?P<format>[a-z0-9]+)\.(?P<format>[a-z0-9]+)$" is not a valid regular expression: redefinition of group name u'format' as group2; was group 1
I tried doing some research into this but can't seem to find anything and more I mess with it the more that goes wrong
Heres my code:
modules.py
class Home(models.Model):
user = models.ForeignKey(User)
#address ect
serializers.py
class UserSerializer(serializers.HyperlinkedModelSerializer):
username = serializers.HyperlinkedRelatedField(many=True, read_only=True, view_name='home-detail')
class Meta:
model = User
fields = ('url', 'username', 'home')
class HomeSerializer(serializers.HyperlinkedModelSerializer):
owner = serializers.Field(source='owner.username')
highlight = serializers.HyperlinkedIdentityField(view_name='home-highlight', read_only=True, format='html')
class Meta:
model = Home
fields = ('url', 'owner', 'postcode')
api.py
#api_view(('GET',))
def api_root(request, format=None):
return Response({
'users': reverse('user-list', request=request, format=format),
'homes': reverse('home-list', request=request, format=format)
})
class UserList(generics.ListCreateAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
class UserDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
class HomeList(generics.ListCreateAPIView):
queryset = Home.objects.all()
serializer_class = HomeSerializer
class HomeDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = Home.objects.all()
serializer_class = HomeSerializer
class HomeHighlight(generics.GenericAPIView):
queryset = Home.objects.all()
renderer_classes = (renderers.StaticHTMLRenderer,)
def get(self, request, *args, **kwargs):
snippet = self.get_object()
return Response(snippet.highlighted)
urls.py
urlpatterns = format_suffix_patterns([
url(r'^$', api.api_root),
url(r'^users/$',
api.UserList.as_view(),
name='user-list'),
url(r'^users/(?P<pk>[0-9]+)/$',
api.UserDetail.as_view(),
name='user-detail'),
url(r'^home/$',
api.HomeList.as_view(),
name='home-list'),
url(r'^home/(?P<pk>[0-9]+)/$',
api.HomeDetail.as_view(),
name='home-detail'),
url(r'^home/(?P<pk>[0-9]+)/highlight/$',
api.HomeHighlight.as_view(),
name='home-highlight')
])
urlpatterns += [
url(r'^api-auth/', include('rest_framework.urls',
namespace='rest_framework')),
]
urlpatterns = format_suffix_patterns(urlpatterns)
You are calling format_suffix_patterns twice, so Django has no idea how to parse the URL because there are two format groups.
You shouldn't need the first call, as the second call takes care of it for you (and allows for TokenAuthentication to still have the suffixes).
Atleast change router.DefaultRouter() to router.SimpleRouter() in urls.py file