GSOC 2023 Discussion and Feedback: Database-level Cascades

143 views
Skip to first unread message

Akash Sen

unread,
Mar 27, 2023, 9:57:08 AM3/27/23
to Django developers (Contributions to Django itself)

Hello everyone,
I’ve started this discussion to get feedback for my proposal for the project: Database-level Cascades Functionality to Django ORM. I have never contributed to any of the official Django projects earlier but I have experience using the framework for last 2 years. In this discussion I would like to propose a high level view of how this can be implemented, any kind of feedback and reference to resources for a more detailed and clear perspective about the project from your side would be very much appreciated,

Based on my study it seems quite straightforward and simple to implement.

  1. Conduct thorough research and gain an understanding of the existing discussions, pull requests, and issues associated with adding support for database-level cascading options in the Django web framework.
  2. Specify the requirements for the new feature, including its name and behavior, and determine whether it should be a new option (on_delete_db) or a modification of the existing one (on_delete).
  3. Develop a ForeignKey subclass that sets a flag indicating that the database should manage the cascading options.
  4. Modify the DatabaseSchemaEditor’s add_field() and sql_create_fk() methods to recognize the flag and generate SQL accordingly for the specific database backend.
  5. Ensure that the implementation performs as intended when tested for a single database backend. Then, generalize the implementation so that it works for all supported database backends, generating appropriate SQL for each.
  6. Integrate the implementation with the Django migrations framework to ensure proper handling of database-level cascading options during schema migrations.
  7. Write tests to verify that the new feature functions correctly and does not interfere with existing functionality.
  8. Submit one or more pull requests containing the changes, and collaborate with the Django community to address any feedback or issues that may arise.

Here is a link to my proposal : Database-level Cascades Proposal - GSoC '23 - Google Docs 5

Due to my beginner level understanding of the codebase there is a lot of scope room for improvement. Your suggestions will be of great help.

David Sanders

unread,
Mar 27, 2023, 12:16:37 PM3/27/23
to django-d...@googlegroups.com
Hi Akash,

Database-level cascading deletes is a topic that has been discussed often since, well probably the dawn of Django 😁  From recollection the main issue isn't the implementation, it's getting it to play nicely with Django's cascading emulation.

There are other tickets, but I believe this is the main ticket to refer to: https://code.djangoproject.com/ticket/21961  There are also plenty of threads on this group I'm sure you could dig up.

Note that with the introduction of constraints a while back, there's nothing stopping people from adding their own custom foreign keys that adds the necessary `ON DELETE` clauses. Here's a demonstration of that:  https://github.com/shangxiao/stupid-django-tricks/tree/master/abusing_constraints#database-level-cascading-deletes

The gist is:
  1. Set your fks to "do nothing" (I haven't tested with other options - seems like there could be some conflicts there though)
  2. Define your own fk by extending BaseConstraint and add the necessary ON DELETE/ON UPDATE clauses
  3. Add this new fk to your meta's constraints attribute
Check out the tests in that link above for confirmation (only tested on Postgres).

Anyway, best of luck!
David


--
You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-develop...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/bd82a0de-8f0a-47b5-b40d-1672ed05736fn%40googlegroups.com.

Carlton Gibson

unread,
Mar 29, 2023, 4:11:55 AM3/29/23
to Django developers (Contributions to Django itself)
Hey David. 

Nice example! 

I've done this, again just PostgreSQL, overriding the schema editor's sql_create_fk and sql_create_column_inline_fk to add to the necessary ON DELETE (for an FK subclass), but doing it with a constraint is a lovely touch. (I shall play with that 😜)

I didn't look at all at making it work for each backend (but it should no? 🤔)

My need-to-double-check-but… thought on #21961 was that a new kwarg (such as, say) db_on_delete, which would error if used with on_delete, and set that to DO_NOTHING, responsible for controlling the generated SQL would be the way forward here. 

That was all before constraints, though, so thoughts from Simon/Mariusz/... on best way forward would be good. 

For me, it would be **great** (and akin with various other changes in recent versions) to be able to push this responsibility into the DB in a recommended/supported way. 

Kind Regards,

Carlton

charettes

unread,
Mar 29, 2023, 7:30:10 PM3/29/23
to Django developers (Contributions to Django itself)
The difficulty of switching to database level constraint effectively resides in how your lose the great parts of cascade deletion emulations most notably signals post and pre-delete signals.

If you're willing to make this compromise then you must make sure that all cycle of model relationships in your app are also switched to not using post and pre-delete signals as `DB_CASCADE` and `CASCADE` don't play well together. That's easier said than done when using third party applications with limited support for swappable models or that require signals machinery

What I meant by that is that you can't have the following models

class Foo(models.Model):
   pass

class Bar(models.Model):
   foo = models.ForeignKey(Foo, on_delete=DB_CASCADE)

class Baz(models.Model):
   bar = models.ForeignKey(Bar, on_delete=CASCADE)

As nothing will trigger the Django cascade emulation deletion of Baz when a Bar row gets a database initiated cascade deletion on Foo deletion and you'll run into integrity errors. In the case of signals handling the situation is similar, deleting a Foo object would not trigger a deletion signals for receivers connected to Bar as a sender.

A lot of this work has already been done[1] to cover these issues so I consider this problem to be mostly a matter of pushing it through the finish lines and adding extra checks for deletion signal registration on models involved in `DB_CASCADE` chains.

While it's true that you can use a `ForeignKeyConstraint(BaseConstraint)` and `db_constraint=DO_NOTHING` to achieve the creation of database constraints at the database level you do loose safe rails that ensures you don't run into surprises in the medium term.

Cheers,
Simon

Akash Sen

unread,
Mar 30, 2023, 12:22:18 AM3/30/23
to Django developers (Contributions to Django itself)
Hi David,
Thank you for your suggestion and nice implementation example. I would try to include that approach too.

Regards,
Akash Kumar Sen

LinkedIn | GitHub


David Sanders

unread,
Mar 30, 2023, 1:29:39 AM3/30/23
to django-d...@googlegroups.com
Thank you for your suggestion and nice implementation example. I would try to include that approach too.

No, that was just an example of a workaround without any of the benefits of Django's emulation – the presence of a workaround often goes into determining whether it's worth working on a new feature that isn't trivial to add.

However, Simon's pointed out an existing pull request that has apparently done some work to getting db cascades working in tandem with Django. That sounds like the place where any effort should be put into.
Reply all
Reply to author
Forward
0 new messages