How do I delete a collection in Django Rest Api? - python

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")

Related

How to pass data to the model field when saving the form? django form models save

get the form and process it in post. It is necessary to save the unique uuid of the record to the model, I do it like this: formOne.save(related_uuid=related_uuid)
but doesn't work, the error is - save() got an unexpected keyword argument 'related_uuid'
models
class Orders(models.Model):
device = models.CharField(max_length=150)
uuid = models.CharField(max_length=22, blank=True)
views
class OrderAddView(TemplateView):
template_name = 'orders/order_add.html'
def get(self, request, *args, **kwargs):
context = super().get_context_data(**kwargs)
... some work code
return self.render_to_response(context)
def post(self, request, *args, **kwargs):
formOne = SimpleOrderAddForm(self.request.POST, prefix='one_form')
if formOne.is_valid():
related_uuid = shortuuid.uuid()
formOne.save(related_uuid=related_uuid)
return HttpResponseRedirect('orders_home')
else:
print('NotValid')
return self.form_invalid(formOne, **kwargs)
def form_invalid(self, formOne,, **kwargs):
context = self.get_context_data()
... some work code
return self.render_to_response(context)
assuming that "shortuuid.uuid()" return correct uuid; try
def post(self, request, *args, **kwargs):
formOne = SimpleOrderAddForm(self.request.POST, prefix='one_form')
if formOne.is_valid():
a=formOne.save(commit=False)
a.related_uuid=shortuuid.uuid()
a.save()
return HttpResponseRedirect('orders_home')
else:
print('NotValid')
return self.form_invalid(formOne, **kwargs)

How to simplify the code and is it necessary?

I work on the API in the Django REST Framework. And now there is such a problem: there is a ModelViewSet and in its functions the same request to the database, the same check in the if block. Is it possible to somehow move this matter into a separate function and how to do it?
class LinkViewSet(ModelViewSet):
permission_classes = (IsAuthenticated,)
serializer_class = LinkSerializer
queryset = Link.objects.all()
def retrieve(self, request, *args, **kwargs):
instance = Link.objects.filter(Q(user_id=self.request.user.id) & Q(id=kwargs["pk"])).first()
if not instance:
return Response(data="Not found", status=status.HTTP_404_NOT_FOUND)
return super().retrieve(request, *args, **kwargs)
def partial_update(self, request, *args, **kwargs):
instance = Link.objects.filter(Q(user_id=self.request.user.id) & Q(id=kwargs["pk"])).first()
if not instance:
return Response(data="Not found", status=status.HTTP_404_NOT_FOUND)
return super().partial_update(request, *args, **kwargs)
If I understand the code correctly, the intention is to limit queryset to allow access only to links owned by currently logged in user. For that, you can just override get_queryset method and that is it. DRF will take care of getting object from the queryset by id and throwing 404 if the object is not found.
class LinkViewSet(ModelViewSet):
permission_classes = (IsAuthenticated,)
serializer_class = LinkSerializer
def get_queryset(self):
return Link.objects.filter(user_id=self.request.user.id)
You could do some of the implementation in a private method
def _link_objects_filter(self, pk):
return Link.objects.filter(Q(user_id=self.request.user.id)
& Q(pk)).first()
Or, taking it a step further, have a common implementation that uses getattr to decide which base implementation to use.
class LinkViewSet(ModelViewSet):
permission_classes = (IsAuthenticated,)
serializer_class = LinkSerializer
queryset = Link.objects.all()
def _retrieve_op(self, method, request, *args, **kwargs):
instance = self._link_objects_filter(kwargs["pk"])
if not instance:
return Response(data="Not found", status=status.HTTP_404_NOT_FOUND)
return getattr(super(), method)(request, *args, **kwargs)
def retrieve(self, request, *args, **kwargs):
return self._retrieve_op("retrieve", request, *args, **kw)
def partial_update(self, request, *args, **kwargs):
return self._retrieve_op("partial_update", request, *args, **kw)
def _link_objects_filter(self, pk):
return Link.objects.filter(Q(user_id=self.request.user.id)
& Q(pk)).first()
That could be further reduced with partial methods
import functools
class LinkViewSet(ModelViewSet):
permission_classes = (IsAuthenticated,)
serializer_class = LinkSerializer
queryset = Link.objects.all()
def _retrieve_op(self, request, method, *args, **kwargs):
instance = self._link_objects_filter(kwargs["pk"])
if not instance:
return Response(data="Not found", status=status.HTTP_404_NOT_FOUND)
return getattr(super(), method)(request, *args, **kwargs)
retrieve = functools.partialmethod(_retrieve_op, "retrieve")
partial_update = functools.partialmethod(_retrieve_op, "partial_update")
def _link_objects_filter(self, pk):
return Link.objects.filter(Q(user_id=self.request.user.id) & Q(pk)).first()
I'm not sure whether django meta programming will mess this up.

Django CreateView didn't return an HttpResponse object

Can't figure out why CreateView doesn't return HttpResponse. For now, I use this view just for posting (no GET). I thought that set self.success_url should be enough (as you can see in def post).
class TripCreationView(CreateView):
form_class = TripCreationForm
template_name = 'frontend/homepage.html'
def post(self, request, *args, **kwargs):
self.success_url = request.POST.get('success_url') or reverse('frontend:homepage')
super(TripCreationView, self).post(self, request, *args, **kwargs)
#
# def form_valid(self, form):
# trip = form.save(self.request)
# return HttpResponseRedirect(self.success_url)
def get_form_kwargs(self):
kwargs = super(TripCreationView, self).get_form_kwargs()
kwargs['user'] = self.request.user
return kwargs
Do you know what to do?
You forgot a return statement.
def post(self, request, *args, **kwargs):
self.success_url = request.POST.get('success_url') or reverse('frontend:homepage')
return super(TripCreationView, self).post(self, request, *args, **kwargs)

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 class based delete view and validation

My view:
class ModEmailDeleteView(DetailView):
model = EmailModel
template_name = "email_delete.html"
success_url = reverse_lazy('moderator_profile', request.user.id)
Here I want to check if the user of particular filed is request user then only he can delete. Like
if obj.user == request.user
then only he can delete or throw 404
Also what if I have multiple primary key in the url?? and want different validations using those primary keys
You can do it like this:
class ModEmailDeleteView(DeleteView):
model = EmailModel
template_name = "email_delete.html"
success_url = reverse_lazy('moderator_profile', request.user.id)
def delete(self, request, *args, **kwargs):
self.object = self.get_object()
if self.object.user == request.user:
self.object.delete()
return HttpResponseRedirect(self.get_success_url())
else:
raise Http404 #or return HttpResponse('404_url')
There is mixin for django Deleview , you just override the delete
function in your view,
class DeletionMixin(object):
"""
A mixin providing the ability to delete objects
"""
success_url = None
def delete(self, request, *args, **kwargs):
"""
Calls the delete() method on the fetched object and then
redirects to the success URL.
"""
if self.object.user = request.user:
self.object.delete()
success_url = self.get_success_url()
self.object.delete()
return HttpResponseRedirect(success_url)

Categories