I am trying to use transaction.atomic with django without any luck I know I am doing something wrong but I dont know what.
class SnapshotView(BaseViewSet):
serializer_class = SnapshotSerializer
#transaction.atomic
def perform_create(self, serializer):
# this will call serializer.save()
snapshot = snapshot = super().perform_create(serializer)
# this will run some code can raise an exception
SnapshotServices.create_snapshot(snapshot=snapshot,
data=serializer.initial_data)
the first method that creates a new snapshot will pass the second will raise but still I can see my snapshot instance in the db, why is that?
I am in transaction block and something fails, is django not suppose to do a rollback?
the second method will throw a custom exception
I read the doc and it seems that I am doing everything right.
I figure it out.
my problem was that django uses default DB when using in atomic is None. Because I am using different DB, I just added using to my decorator
transaction.atomic(using=MYDB)
and that's fix my problem.
Related
What exactly I want to do
On rollback, I want to run a do_something function.
Is it possible to do so?
Right now, transaction.atomic does its job perfectly, but it only takes care of database. On rollback, I want to take care of a few other things using that do_something function I mentioned before.
My use cases for transaction.atomic are pretty simple and there's not much to say about, I just use it on typical views which are creating and updating objects.
*Updated
Example View
#transaction.atomic
def create(self, request, *args, **kwargs):
serializer = ConvertSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
instance = ConvertModel.objects.create(
request.user, request.converter, serializer.validated_data
)
# I have some code here which create a json file on the disk based on that instance
create_json(request.user, request.converter)
return Response(ConvertSerializer.data, status=HTTP_201_CREATED)
Example on_rollback function
This function simply removes the JSON file which was created by the view.
def remove_json(file_path):
os.remove(file_path)
The example is not what exactly I do now, but it's a pretty similar case. After the rollback, the database is okay, but I have that invalid JSON file on the disk which can make huge problems for me.
Hi I've been wondering how to rollback a saved object on a following method when one method failed.
forms.py
# somewhere class forms
def handle(self, view, request, *args, **kwargs):
# assuming i get an object successfully.
application = models.Application.objects.first()
# do something in its attrs and save
application.name = 'test'
application.save()
# application is fix and send via django.core.mail EmailMessage
self.send_mail(application)
return True
now when I had a good connection everything will work fine. But when it does not it will save the application but will not send the email. Resend is not an option since its a one time send supposedly. Now my idea to rollback the application and throw exception something like "Action Failed. Maybe poor connection. Please try again".
try:
application.save()
self.send_mail(application)
except ConnectionError?:
# rollback ?
raise Exception(msg) ?
Any help and better way to handle it? Thanks for the help and sorry for the trouble.
I have a CreateView for a ModelForm with a form_valid() method, which calls form.save() quite early on (so that I can get the object's ID), then goes on to do some other stuff (create some related objects, and send some emails).
def form_valid(self, form):
context = self.get_context_data()
preferences_formset = context['preferences_formset']
if preferences_formset.is_valid():
student = form.save()
...
send_email_one()
send_email_two()
send_email_three()
return HttpResponseRedirect(self.get_success_url())
I recently discovered that some of the later processing had some errors resulting in an unhandled exception in some cases when send_email_three is called. I can see from my logs that send_email_one and send_email_two are being called, and the exception occurs in send_email_three. However, when this has occurred, I can't find the objects in the DB. I was under the impression that form.save() should create and save the object in the DB - is this the case or does it roll back the save if the form_valid function errors out at a later point?
I'm using django 1.8.17
PS: Yes, I know I should have the emails in a deferred task; that will be implemented later.
That depends on the ATOMIC_REQUESTS setting. Setting it to True will trigger the behaviour described in the docs:
Before calling a view function, Django starts a transaction. If the response is produced without problems, Django commits the transaction. If the view produces an exception, Django rolls back the transaction.
You can use #transaction.atomic decorator
https://docs.djangoproject.com/en/1.10/topics/db/transactions/#controlling-transactions-explicitly
I'm playing around with tastypie, and is pretty much a newbie ;)
I have a FieldResource and want to call a EventLogResource every time there is field is created or updated ..
I think I have to use the obj_create method to call to EventLogResource this is my bad attempt..:
class FieldResource(ModelResource):
def obj_create(self, bundle, **kwargs):
bundle = super(FieldResource, self).obj_create(bundle,**kwargs)
# what to do here??
EventLogResource.create_obj(user=bundle.request.user, comment="test").save()
...
Anyone know how to do this the best way?
Why resource? Create and save model.
EventLog(user=bundle.request.user, comment="test").save()
As it stands, I have a deserialiser that can import any model I throw at it and put it into my database. unfortunately it hits the database with every single model and I want to stop this.
Is there any way for me to lump lots of short saves into one big one?
Example code:
def deserialise(xml):
for x in model_list:
do work to make instance...
instance.save()
return True
is there any way to move the saving of instance out of the for loop?
You can use transaction.commit_manually().
from django.db import transaction
#transaction.commit_manually
def deserialise(xml):
for x in model_list:
# do work to make instance...
instance.save()
transaction.commit()
return True
Or transaction.commit_on_success() which will automatically commit the saves when and if the function returns successfully.
from django.db import transaction
#transaction.commit_on_success
def deserialise(xml):
for x in model_list:
# do work to make instance...
instance.save()
return True
Alternatively, in django 1.4 there's also bulk_create(), but do note the caveats listed in documentation.