Create postgresql command based on DELETE REST call within Django - django

So I have roughly the following:
class exampleSerializer(serializers.ModelSerializer):
def delete(self, request, *args, **kwargs):
//Custom code
The goal is to access the data of the row that the delete function is gonna delete. Based on this information I need to make some extra PostgreSQL commands before the functions finishes. How can I access this data?

Are you using a ModelViewset?
It’s best to execute your code there.
Something like this:
class YourViewSet(ModelViewSet):
def perform_destroy(self, instance):
# your code here
super().perform_destroy(instance)

Related

How and where to call a method in a Class based view Django

As part of a News Years resolution, I have promised to myself that I would learn to write Class Based Views, but as it turns out, I need some help..
What I am trying to do is call a method that generates a random number and then sends an email before the page loads, which I comfortable doing (I'll probably use celery to send the mail in the background).
What I don't understand is how and where to call the methods random_code() and send_email() (see below)?
Do I do this by overriding setup(), dispatch() or get() etc?
Can someone please give me a basic example of what to do?
The class is going to look something like this:
class VerifyCode(FormView):
template_name = "account/verify.html"
form_class = VerifyForm
def random_code(self):
#random_code generator
return random_code
def send_email(self):
#code to send email
Many thanks in advance.
It depends on which REST method do you want to call it. If you are using simple GET, then call it in get() like this:
class VerifyCode(FormView):
template_name = "account/verify.html"
form_class = VerifyForm
def random_code(self):
#random_code generator
return random_code
def send_email(self):
#code to send email
def get(self, request, *args, **kwargs):
...
self.random_code()
self.send_email()
return super().get(request, *args, **kwargs)
In similar way in post() for POST method.
Another thing is you can send emails directly with Django. I do that and it's pretty simple. Check this DOCS. You can post another question about that if you have something.

Django rest framework bulk: Correct URL syntax for bulk operations?

I'm attempting to carry out bulk DELETEs/PUTs on my Django API, mymodel inherits from MultipleDBModelViewSet which in turn inherits from the BulkModelViewSet
The bulk destroy method is as follows
class MultipleDBModelViewSet(BulkModelViewSet):
...
...
def bulk_destroy(self, request, *args, **kwargs):
ids = json.loads(request.query_params.get("ids"))
if not ids:
return super().destroy(request, *args, pk=kwargs.pop("pk"), **kwargs)
else:
return super().bulk_destroy(request, *args, **kwargs)
In my urls.py file I define the URL used to interact with my model:
router.register(r"v1/mymodels", mymodels_views_v1.MyModelViewSet)
this allows me to GET, POST, PUT and DELETE on the URL (works perfectly at present):
www.my-api.com/v1/mymodels/{{mymodel_id}}
Can I use this same URL for bulk operations? If so, what is the correct syntax?
eg: www.my-api.com/v1/mymodels/?ids=[{{mymodel_id1}},{{mymodel_id2}}]
If not, what changes should I make?
Thanks
There are two things they are saying at their documentation.
Most API urls have two URL levels for each resource:
url(r'foo/', ...)
url(r'foo/(?P<pk>\d+)/', ...)
The second url however is not applicable for bulk operations because
the url directly maps to a single resource. Therefore all bulk
generic views only apply to the first url.
That means it won't take url kwarg parameter.
The only exception to this is bulk delete. Consider a DELETE request
to the first url. That can potentially delete all resources without
any special confirmation. To try to account for this, bulk delete
mixin allows to implement a hook to determine if the bulk delete
request should be allowed:
class FooView(BulkDestroyAPIView):
def allow_bulk_destroy(self, qs, filtered):
# custom logic here
# default checks if the qs was filtered
# qs comes from self.get_queryset()
# filtered comes from self.filter_queryset(qs)
return qs is not filtered
Solution:-
You could do like this
class SimpleViewSet(generics.BulkModelViewSet):
def filter_queryset(self, queryset):
ids = self.request.query_params.get('ids')
if ids:
return queryset.filter(id__in=ids.split(',')
# returns normal query set if no param
return queryset

Move POST parameters to query parameters before processing request

I need to move the request.POST parameters to the request.query_params QueryDict.
Is there an accepted way of doing this?
Background
I am using datatables, with a DRF backend, which is working fine. I am moving the application to integration and ... it stops working. Why? Request URL too big (on the 7000 characters range) - which was not a problem in my dev host ...
So, I am looking for a solution to that problem. The first solution is to use POST instead of GET. That works, but the library integrating DRF with datatables is not processing the form parameters of the POST request. Because of that, filtering, pagination and so on have stopped working.
The easiest thing to solve this would be to put the form parameters into the query parameters, and let the backend process the request as if it was a normal GET request.
This is what I am doing at the moment:
class DataViewSet(viewsets.ModelViewSet):
queryset = Data.objects.all()
serializer_class = DataSerializer
def create(self, request, *args, **kwargs):
# DataTable uses a lot of parameters which do not fit into a normal URL. To get the data we need to do POST,
# so that the parameters are sent in the body
# We hijack the create method to list the data
return self.list(request, *args, **kwargs)
I'm not aware of any accepted ways of doing this. But let me offer you an idea. It is probably on the opposite side of what accepted means.
The rest_framework.request.Request.query_params look like this:
#property
def query_params(self):
return self._request.GET
Im thinking about substituting the self._request.GET with self._request.POST
class DataViewSet(viewsets.ModelViewSet):
queryset = Data.objects.all()
serializer_class = DataSerializer
def create(self, request, *args, **kwargs):
# DataTable uses a lot of parameters which do not fit into a normal URL. To get the data we need to do POST,
# so that the parameters are sent in the body
# We hijack the create method to list the data
request._request.GET = request._request.POST
return self.list(request, *args, **kwargs)
This should work for POST data. Sending files to this endpoint is probably bad idea.
NOTE: This is very fishy and could introduce bugs in the future. Without look into your code i cannot predict the side effects.

Best way to process different POST requests in a single Class Based View?

Developing my first application here and im using a class based view(django.views.generic.base.View) to handle requests from a webpage.
On the webpage I have different forms that send out POST requests, for example, there is text posting form, comment form, vote button, etc. and Im checking POST.has_key() to see which form has been posted and processing according to that.
Whats a better way to do it? And is it possible to define method names such as post_text, post_comment etc and configure dispatch() to run the method accordingly?
I would do it like this:
class AwesomeView(View):
def post(self, request, *args, **kwargs):
# This code is basically the same as in dispatch
# only not overriding dispatch ensures the request method check stays in place.
# Implement something here that works out the name of the
# method to call, without the post_ prefix
# or returns a default method name when key is not found.
# For example: key = self.request.POST.get('form_name', 'invalid_request')
# In this example, I expect that value to be in the 'key' variable
handler = getattr(
self, # Lookup the function in this class
"post_{0}".format(key), # Method name
self.post_operation_not_supported # Error response method
)
return handler(request, *args, **kwargs)
def post_comment(self, request, *args, **kwargs):
return HttpResponse("OK") # Just an example response

At what point does django write an object to the database?

I am overriding the save method on one of my Models like so:
class Foo(models.Model):
...
def save(self, *args, **kwargs):
request = kwargs.pop('request', None)
super(Foo, self).save(*args, **kwargs)
some_stuff()
some_stuff() performs some queries which expect that the new/modified Foo object has been saved to the database (which I why I've put it after the super() call). However, I'm finding when some_stuff() runs the newly created/modified object is not present in the DB.
Is my understanding of when things are written to the DB incorrect? How else might I do this (I've considered signals, but all of this is within the same app, so that seems overkill)?
UPDATE: I've tried putting a signal receiver to see if that makes any difference; in fact it gets called before the super() call finishes, so the DB state is no different whether I override save() use a signal.
maybe you need call some_stuff() like this: self.some_stuff(). after Super(...), the self would be the object present in DB. And you can do some with self in your method.