Django rest framework self.get_object() crashes my application - python

#detail_route(methods=['POST', 'DELETE'], permission_classes=[BubbleIsMember])
#parser_classes((FormParser, MultiPartParser,))
def rsvp(self, request, *args, **kwargs):
response_data = {'message' : 'Error'}
try:
post_data = request.data
except:
response_data['message'] = 'Malformed json. We received:' + json.dumps(request.data)
return Response(response_data, status=HTTP_400_BAD_REQUEST)
if 'meeting' not in request.data:
response_data['message'] = "'meeting' field is required"
return Response(response_data, status=HTTP_400_BAD_REQUEST)
try:
meeting = Meeting.objects.get(pk=post_data['meeting'], bubble=self.get_object())
print("self", self)
rsvp, created = MeetingRSVP.objects.get_or_create(user=request.user, meeting=meeting)
self.get_object() after that line; code doesn't get processed.
Below is what my only 'self' looks like, I'm trying to get bubble object from it.
<arrowapi.views.bubble.BubbleViewSet object at 0x1067728d0>
My queryset within that View looks like this:
def get_queryset(self):
if self.request.user.is_superuser:
return Bubble.objects.all()
elif self.request.user.is_authenticated:
memberships = BubbleMembership.objects.filter(user=self.request.user).values_list('bubble', flat=True)
return Bubble.objects.filter(pk__in=memberships)
else:
return Bubble.objects.none()

Related

How can a delete request be redirected to a specific url in django rest framework?

Currently, I have made a "Like" model and have implemented "Like" and "Unlike" by post and delete requests, respectively. So after implementing Like, I want to implement Unlike, and I know that in order to implement it, I have to select the pk of that Like object, map it to url, and then send a delete request to that url. However, this method requires both url called "/post_id/like/like_id" and "/post_id/like_id", which I do not do, but try to redirect from views to "/post_id/like/like_id" when a delete request is sent to url called "/post_id/like/like". How can I make logic to proceed with the code as I think? Here's my code.
views.py
class CreateReadLikeView (ModelViewSet) :
serializer_class = LikeSerializer
permission_classes = [IsAuthenticated]
queryset = Like.objects.all()
is_saved = False
def get_queryset (self) :
return super().get_queryset().filter(post=self.kwargs.get('post_id'))
def perform_create (self, serializer) :
postId = self.kwargs.get('post_id')
post = Post.objects.get(pk=postId)
try :
like = self.queryset.get(post=post, liked_people=self.request.user)
except Like.DoesNotExist :
serializer.save(liked_people=self.request.user, post=post)
self.is_saved = True
def create (self, request, *args, **kwargs) :
super().create(request, *args, **kwargs)
if self.is_saved is True :
self.is_saved = False
return Response({'success': '해당 게시물을 좋아요 했습니다.'}, status=200)
return Response({'message': ['이미 해당 게시물을 좋아요 하였습니다.']}, status=400)
def list (self, request, *args, **kwargs) :
postId = self.kwargs.get('post_id')
post = Post.objects.get(pk=postId)
try :
like = self.queryset.get(post=post, liked_people=self.request.user)
except Like.DoesNotExist :
return Response({'message': ['좋아요 하지 않음.']}, status=400)
return Response({'success': '좋아요함.'}, status=200)
class DeleteLikeView (ModelViewSet) :
serializer_class = LikeSerializer
permission_classes = [IsAuthenticated, IsLiker]
queryset = Like.objects.all()
def get_queryset (self) :
return super().get_queryset().filter(post=self.kwargs.get('post_id'))
def destroy (self, request, *args, **kwargs) :
super().destroy(request, *args, **kwargs)
return Response({'success': '해당 게시물의 좋아요를 취소했습니다.'}, status=200)
urls.py
path('post/<int:post_id>/like', CreateReadLikeView.as_view({'post': 'create', 'get': 'list', 'delete': 'destroy'})), # If a delete request is sent to this url.
path('post/<int:post_id>/like/<int:pk>', DeleteLikeView.as_view({'delete': 'destroy'})), # I want to redirect this url.

How to update a model in the Database with Django Rest Framwork Serializer fails?

If I run my code at the first time, it works successfully. Data are stored in the database and the http code is 200. If I change some data on the client side and try to save the model again, I reach the following error.
I read on the django doc, hat i can use Save as "create" and "update" as well.
error message
heating mapping with this zone already exists
views.py
from heatingControll.models import HeatingMapping as HeatingMappingModel
# ... some code ...
#detail_route(methods="post")
def save(self, request):
zone = request.data.get('zone')
data = json.loads(zone)
serializer = HeatingMappingSerializer(data=data)
valid = serializer.is_valid(raise_exception=True)
if(valid):
result = serializer.save()
self.response = {"result": True, "data":HeatingMappingSerializer(result).data, "message": "Erfolgreich gespeichert"}
return JsonResponse(self.response, safe=False)
SOLUTION supported by zaidfazil
#detail_route(methods="post")
def save(self, request):
zone = request.data.get('zone')
data = json.loads(zone)
if 'zone' in data:
obj = HeatingMappingModel.objects.get(id=data.get('id'))
serializer = HeatingMappingSerializer(data=data, instance=obj)
else:
serializer = HeatingMappingSerializer(data=data)
valid = serializer.is_valid(raise_exception=True)
if(valid):
result = serializer.save()
self.response = {"result": True, "data":HeatingMappingSerializer(result).data, "message": "Erfolgreich gespeichert"}
return JsonResponse(self.response, safe=False)
Try editing your view maybe like this,
#detail_route(methods="post")
def save(self, request, pk):
zone = request.data.get('zone')
data = json.loads(zone)
obj = HeatingMapping.objects.get(pk=pk)
serializer = HeatingMappingSerializer(data=data, instance=obj)
valid = serializer.is_valid(raise_exception=True)
if(valid):
result = serializer.save()
self.response = {"result": True, "data":HeatingMappingSerializer(result).data, "message": "Erfolgreich gespeichert"}
return JsonResponse(self.response, safe=False)

Django UpdateView create new object

My problem:
UpdateView create new object instead of updating previous, i think its happens because in class definition of my view i override get_object method like this:
def get_object(self, queryset=None):
try:
object_get = self.model.objects.get(pk=self.kwargs['pk'])
except ObjectDoesNotExist:
raise Http404("No object found matching this query")
if self.request.user.is_authenticated():
if object_get.owner == self.request.user:
return object_get
And so if current user is not owner of the object - this method return nothing - its what i wanted, but my form class instead create new object:
class ClientCreation(forms.ModelForm):
class Meta:
model = Client
fields = ('name', 'loyal')
I think this is happened because form doesn't receive a self.instance and create new instead - what should i do in this situation? I don't want new object to be created, in case when owner of object is not the current user i want nothing to happend then sending such a post request. How should i correctly implement this?
UPDATE views.py:
class Distinct(generic.UpdateView):
def get_object(self, queryset=None):
try:
object_get = self.model.objects.get(pk=self.kwargs['pk'])
except ObjectDoesNotExist:
raise Http404("No object found matching this query")
if self.request.user.is_authenticated():
if object_get.owner == self.request.user:
return object_get
def get_form_kwargs(self):
kwargs = super(Distinct, self).get_form_kwargs()
if self.request.user.is_authenticated():
kwargs.update({'user': self.request.user})
return kwargs
def post(self, request, *args, **kwargs):
if request.POST.get('action', '') == 'Delete':
object_get = self.get_object()
request.session['deleted_data'] = str(object_get)
object_get.delete()
return redirect(reverse('crm:main'))
else:
return super(Distinct, self).post(request, *args, **kwargs)
def get_success_url(self):
return reverse('crm:{}'.format(self.distinct_template), kwargs={'pk': self.kwargs['pk']})
class DistinctClient(Distinct):
form_class = ClientCreation
model = Client
template_name = 'crm/client_detail.html'
all_template = 'clients'
distinct_template = 'client'
def get_form_kwargs(self):
return generic.UpdateView.get_form_kwargs(self)
In UpdateView, if get_object returns None django will create a new object.So instead of return None do whatever you want.
def get_object(self, queryset=None):
try:
object_get = self.model.objects.get(pk=self.kwargs['pk'])
except ObjectDoesNotExist:
raise Http404("No object found matching this query")
if self.request.user.is_authenticated():
if object_get.owner == self.request.user:
return object_get
raise My #do something here.
UPDATE
class My(Exception):
pass
class DistinctClient(Distinct):
form_class = ClientCreation
model = Client
template_name = 'crm/client_detail.html'
all_template = 'clients'
distinct_template = 'client'
def dispatch(self, *args, **kwargs):
try:
return super(DistinctClient, self).dispatch(*args, **kwargs)
except My:
return redirect #to do or (return render(self.request, 'mytemplate.html', {}))

django rest framework url arguments with patch not working

Edit
I suspect the whole problem with my UpdateApiView is with the url. No matter how I change it, will return 404.
url(r'verify-phone/(?P<phone_id>^\d+)$', view.VerifyPhone.as_view(), name='verify-phone'),
it returns
{
"detail": "Not found."
}
[18/Apr/2016 01:39:02] "PATCH /api/verify-phone/phone_id=00980 HTTP/1.1" 404 4941
Why?
views.py
class VerifyPhone(generics.UpdateAPIView):
permission_classes = (AllowAny,)
serializer_class = serializers.VerifyPhoneSerializer
allowed_methods = ['PATCH']
lookup_field = 'phone_id'
def get_queryset(self):
phone_id = self.request.query_params.get('phone_id', None)
queryset = User.objects.filter(phone_id=phone_id)
return queryset
def update(self, request, *args, **kwargs):
print('inside update')
print(request.data)
partial = kwargs.pop('partial', False)
instance = self.get_object()
print(instance)
serializer = self.get_serializer(instance, data=request.data, partial=partial)
print(serializer)
serializer.is_valid(raise_exception=True)
self.perform_update(serializer)
print('done perform update')
return Response(serializer.data)
serializers.py
class VerifyPhoneSerializer(serializers.ModelSerializer):
regex = r'\d+'
verification_code = serializers.RegexField(regex, max_length=7, min_length=7, allow_blank=False)
phone_id = serializers.HyperlinkedRelatedField(view_name='verify-phone', lookup_field='phone_id', read_only=True)
class Meta:
model = User
fields = ('verification_code', 'phone_id')
def validate(self, data):
verification = api.tokens.verify(data['phone_id'], data['verification_code'])
if verification.response.status_code != 200:
raise serializers.ValidationError("Invalid verification code.")
return data
def update(self, instance, validated_data):
instance.phone_number_validated = True
instance.save()
return instance
Second question Is this correct to get phone_id from the views?
phone_id = serializers.HyperlinkedRelatedField(view_name='verify-phone', lookup_field='phone_id', read_only=True)
Looking at your api url def, I think you should call:
/api/verify-phone/00980
instead of
/api/verify-phone/phone_id=00980
I also think something is wrong with the url def itself (the ^ before \d):
url(r'verify-phone/(?P<phone_id>^\d+)$', view.VerifyPhone.as_view(), name='verify-phone')
should be
url(r'verify-phone/(?P<phone_id>\d+)$', view.VerifyPhone.as_view(), name='verify-phone')
or
url(r'verify-phone/(?P<phone_id>\d{5})$', view.VerifyPhone.as_view(), name='verify-phone')

How do I delete a collection in Django Rest Api?

I've been trying for a while now to get 'DELETE' to work when reading a collection in Django Api View. I've been using 'ListCreateAPIView' and that only provides get and post method handlers. Does anyone know how to fix this?
My view:
class NotepadDetail(generics.ListCreateAPIView):
model = Session
serializer_class = SessionSerializer
def get_queryset(self):
user=self.request.user
notepad = self.kwargs['notepad_pk']
return Session.objects.filter(user=user, notepad=notepad)
def pre_save(self, obj):
obj.user = self.request.user
obj.notepad = get_object_or_404(Notepad, user=self.request.user, pk=self.kwargs['notepad_pk'])
Solved it by adding:
def get_object(self, notepad_pk):
try:
return Notepad.objects.get(user=self.request.user, pk=notepad_pk)
except Notepad.DoesNotExist:
raise Http404
def delete(self, request, notepad_pk, format=None):
object = self.get_object(notepad_pk)
object.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
You can use a DestroyModelMixin:
class NotepadDetail(generics.DestroyModelMixin,
generics.ListCreateAPIView):
model = Session
serializer_class = SessionSerializer
def get_queryset(self):
user=self.request.user
notepad = self.kwargs['notepad_pk']
return Session.objects.filter(user=user, notepad=notepad)
def pre_save(self, obj):
obj.user = self.request.user
obj.notepad = get_object_or_404(Notepad, user=self.request.user, pk=self.kwargs['notepad_pk'])
def delete(self, request, *args, **kwargs):
return self.destroy(request, *args, **kwargs)
The self.destroy method provided by the DestroyModelMixin will handle the object deletion, will correctly raise the pre_delete and post_delete signals, and will return the 204 NO CONTENT status.
def delete(self, request, pk, format=None):
event = self.get_object(pk)
event.delete()
return Response("Object Deleted")

Categories