Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I create a Django migration for my ManyToMany relation that includes an on-delete cascade?

I'm using PostGres 10, Python 3.9, and Django 3.2. I have set up this model with the accompanying many-to-many relationship ...

class Account(models.Model):    
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    ...
    crypto_currencies = models.ManyToManyField(CryptoCurrency)

After generating and running Django migrations, the following table was created ...

\d cbapp_account_crypto_currencies;
                               Table "public.cbapp_account_crypto_currencies"
      Column       |  Type   |                                  Modifiers                                   
-------------------+---------+------------------------------------------------------------------------------
 id                | integer | not null default nextval('cbapp_account_crypto_currencies_id_seq'::regclass)
 account_id        | uuid    | not null
 cryptocurrency_id | uuid    | not null
Indexes:
    "cbapp_account_crypto_currencies_pkey" PRIMARY KEY, btree (id)
    "cbapp_account_crypto_cur_account_id_cryptocurrenc_38c41c43_uniq" UNIQUE CONSTRAINT, btree (account_id, cryptocurrency_id)
    "cbapp_account_crypto_currencies_account_id_611c9b45" btree (account_id)
    "cbapp_account_crypto_currencies_cryptocurrency_id_685fb811" btree (cryptocurrency_id)
Foreign-key constraints:
    "cbapp_account_crypto_account_id_611c9b45_fk_cbapp_acc" FOREIGN KEY (account_id) REFERENCES cbapp_account(id) DEFERRABLE INITIALLY DEFERRED
    "cbapp_account_crypto_cryptocurrency_id_685fb811_fk_cbapp_cry" FOREIGN KEY (cryptocurrency_id) REFERENCES cbapp_cryptocurrency(id) DEFERRABLE INITIALLY DEFERRED

How do I alter my field relation, or generate a migration, such that the cascade relationship is ON-DELETE CASCADE? That is, When I delete an account, I would like accompanying records in this table to also be deleted.

like image 829
Dave Avatar asked Nov 06 '22 00:11

Dave


1 Answers

Had a closer look on this. I tried to replicate your models and I also see that the intermediary table has no cascade. I have no answer on your main question on how to add the cascade, but it seems that django does the cascade behavior which already supports this:

When I delete an account, I would like accompanying records in this table to also be deleted.

To demonstrate:

a = Account.objects.create(name='test')
c1 = CryptoCurrency.objects.create(name='c1')
c2 = CryptoCurrency.objects.create(name='c2')
c3 = CryptoCurrency.objects.create(name='c3')
a.crypto_currencies.set([c1, c2, c3])

If you do:

a.delete()

Django runs the following SQL which simulates the cascade on the intermediary table:

[
    {
        'sql': 'DELETE FROM "myapp_account_crypto_currencies" WHERE "myapp_account_crypto_currencies"."account_id" IN (3)', 'time': '0.002'
    }, 
    {
        'sql': 'DELETE FROM "myapp_account" WHERE "myapp_account"."id" IN (3)', 'time': '0.001'
    }
]

I can't find in the documentation why it is done this way though. Even adding a custom intermediary like this results in the same behavior:

class Account(models.Model):
    name = models.CharField(max_length=100)
    crypto_currencies = models.ManyToManyField(CryptoCurrency, through='myapp.AccountCryptocurrencies')


class AccountCryptocurrencies(models.Model):
    account = models.ForeignKey(Account, on_delete=models.CASCADE)
    cryptocurrency = models.ForeignKey(CryptoCurrency, on_delete=models.CASCADE)
like image 129
Brian Destura Avatar answered Nov 12 '22 12:11

Brian Destura