Tuesday, April 26, 2016

Re: Django apparently can't handle that error.

The right is just Account.objects.last().delete() to delete everything related to account.
My project has many models related to account, and everything has log, is unfeasible be deleting the rows of each model to the end delete the account.
Django needs to handle it.

Em terça-feira, 26 de abril de 2016 00:58:31 UTC-3, Stephen Butler escreveu:
Damn. It did work once, but now I can't reproduce it. But turning on SQL logging it's clear that what's happening isn't what I said it was.

I get a sequence essentially like this at acct.delete():

-- Django selecting all the things it needs to cascade/update b/c of m2m

SELECT * FROM "myapp_car" WHERE "myapp_car"."account_id" IN (1);

SELECT * FROM "myapp_carlog" INNER JOIN "myapp_log" ON ("myapp_carlog"."log_ptr_id" = "myapp_log"."id") WHERE "myapp_carlog"."car_id" IN (1);

SELECT * FROM "myapp_log" WHERE "myapp_log"."account_id" IN (1);


-- Django doing the m2m DELETEs and UPDATEs

DELETE FROM "myapp_carlog" WHERE "myapp_carlog"."log_ptr_id" IN (1);

UPDATE "myapp_carlog" SET "car_id" = NULL WHERE "myapp_carlog"."log_ptr_id" IN (1);

DELETE FROM "myapp_car" WHERE "myapp_car"."id" IN (1);


-- This is the signal firing for Car delete

SAVEPOINT "s140735184359424_x3";

SELECT "myapp_account"."id" FROM "myapp_account" WHERE "myapp_account"."id" = 1;

INSERT INTO "myapp_log" ("account_id") VALUES (1) RETURNING "myapp_log"."id";

INSERT INTO "myapp_carlog" ("log_ptr_id", "car_id") VALUES (4, NULL);

RELEASE SAVEPOINT "s140735184359424_x3";


-- Outside the signal, more cascades

DELETE FROM "myapp_log" WHERE "myapp_log"."id" IN (1);

-- Finally, delete the account, where we blow up

DELETE FROM "myapp_account" WHERE "myapp_account"."id" IN (1);


So as you can see, the reason the signal Exception isn't caught is because it isn't thrown! The problem is that Django builds a list of every DELETE/UPDATE it needs to make on CarLog and you modify CarLog afterwards.

One way to break this race condition is to call Car.objects.filter(account=acct).delete() first, then acct.delete(). I think that should work, even if it is a little more verbose. Probably will want to wrap that in a transaction.atomic().


On Mon, Apr 25, 2016 at 12:46 PM, Neto <paulosou...@gmail.com> wrote:
This works for you? Not for me! This error continues to ignore the exception.
Even using exception continues to show django.db.utils.IntegrityError

Em domingo, 24 de abril de 2016 00:52:46 UTC-3, Stephen Butler escreveu:
Ahh, Postgres is the problem. When your exception is thrown then Postgres aborts the rest of the transaction. That's how its transaction handling works. Even though you ignore the exception in the myapp code, it will still cause the transaction to abort when Django tries to call commit(). When I was testing I was using sqlite, which behaves differently.


This works for me:

@receiver(post_delete, sender=Car)
def create_car_log(sender, instance, **kwargs):
    sid = transaction.savepoint()
    try:
        CarLog.objects.create(
            account=instance.account,
        )
        transaction.savepoint_commit(sid)
    except:
        transaction.savepoint_rollback(sid)

What I don't get is that using a "with transaction.atomic()" inside the try block should do the same thing. But it's not. Maybe someone else knows?

On Sat, Apr 23, 2016 at 10:19 PM, Neto <paulosou...@gmail.com> wrote:
Stephen, I am using Django 1.9.5, PostgreSQL 9.3
I do not know, maybe the order of the apps may be interfering in the way Django sorts the commands to be sent to the postgresql.

INSTALLED_APPS = [
'core', # here: Account, Log
'myapp', # here: Car, CarLog

What is happening is that post_delete is trying to create a log for an account that does not exist. The exception doesn't works.
This seems to be a bug.

Em sábado, 23 de abril de 2016 18:28:08 UTC-3, Stephen Butler escreveu:
Sorry, I did miss that.

I created a quick test project in 1.9 and ran your sample. It works fine for me. The delete() returns that it deleted 4 objects: the Account, Car, Log, and CarLog. There's something else in your project that is causing the error.

On Sat, Apr 23, 2016 at 3:42 PM, Neto <paulosou...@gmail.com> wrote:
Stephen, CarLog is inheriting Log.


Em sábado, 23 de abril de 2016 17:14:57 UTC-3, Stephen Butler escreveu:
Look a little closer at the error message:

Error:
insert or update on table "myapp_log" violates foreign key constraint "myapp_log_account_id_6ea8d7a6_fk_myapp_account_id"  DETAIL:  Key (account_id)=(11) is not present in table "myapp_account".
It's happening this error rather than the exception.

The table is myapp_log, not myapp_carlog. The error isn't in the post_delete signal you're showing up. Do you have a post_delete for Account objects?

--
You received this message because you are subscribed to the Google Groups "Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-users...@googlegroups.com.
To post to this group, send email to django...@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-users/92e72312-5678-428b-ad7f-360ad911ceaa%40googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-users...@googlegroups.com.
To post to this group, send email to django...@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-users/02b1ab5b-d7e3-4df2-9738-9c1636e931c5%40googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-users...@googlegroups.com.
To post to this group, send email to django...@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-users/9b6ded86-c084-4842-ab41-4f40624df0a6%40googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-users+unsubscribe@googlegroups.com.
To post to this group, send email to django-users@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-users/b3f48ab7-00af-4314-a4d7-56a2de080324%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

No comments:

Post a Comment