Estoy usando PostGres 10, Python 3.9 y Django 3.2. He configurado este modelo con la relación de muchos a muchos que lo acompaña...
class Account(models.Model): id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) ... crypto_currencies = models.ManyToManyField(CryptoCurrency)Después de generar y ejecutar las migraciones de Django, se creó la siguiente tabla...
\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¿Cómo modifico mi relación de campo, o genero una migración, de modo que la relación en cascada sea ON-DELETE CASCADE? Es decir, cuando elimino una cuenta, me gustaría que también se eliminen los registros que la acompañan en esta tabla.
Eché un vistazo más de cerca a esto. Intenté replicar tus modelos y también veo que la mesa intermediaria no tiene cascada. No tengo respuesta a su pregunta principal sobre cómo agregar la cascada, pero parece que Django tiene el comportamiento en cascada que ya admite esto:
Cuando elimino una cuenta, me gustaría que también se eliminen los registros que la acompañan en esta tabla.
Demostrar:
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])Si lo haces:
a.delete()Django ejecuta el siguiente SQL que simula la cascada en la tabla intermedia:
[ { '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' } ]Sin embargo, no puedo encontrar en la documentación por qué se hace de esta manera. Incluso agregar un intermediario personalizado como este da como resultado el mismo comportamiento:
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)Cuando usas ManyToManyField , Django crea una tabla intermedia para ti, en este caso llamada cbapp_account_crypto_currencies . Lo que desea hacer en el futuro es crear siempre de forma explícita el modelo intermediario, AccountCryptoCurrencies , luego establecer el atributo through de ManyToManyField . Esto le permitirá agregar más campos en el futuro al modelo intermediario. Vea más aquí: https://docs.djangoproject.com/en/3.2/ref/models/fields/#django.db.models.ManyToManyField.through .
Lo que ahora deberá hacer es crear esta tabla intermedia:
class AccountCryptoCurrencies(models.Model): account = models.ForeignKey(Account) cryptocurrency = models.ForeignKey(CryptoCurrency) class Meta: db_table = 'cbapp_account_crypto_currencies' class Account(models.Model): id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) ... crypto_currencies = models.ManyToManyField(CryptoCurrency, through=AccountCryptoCurrencies) Ahora necesita generar una migración, ¡pero no la aplique todavía! Modifique la migración envolviéndola en un SeparateDatabaseAndState . No he creado su archivo de migración porque no tengo el modelo completo, pero puede ver aquí cómo hacerlo: Cómo agregar la opción a través de ManyToManyField existente con migraciones y datos en django
Ahora puede aplicar la migración y ahora debería tener una tabla intermedia explícita sin perder datos. Ahora también puede agregar campos adicionales a la tabla intermedia y cambiar los campos existentes. Puede agregar on_delete=models.CASCADE al campo de la account y migrar el cambio.