In an existing Django project I experience critical performance issues when objects of a certain model are deleted. Actually the whole infrastructure breaks down.
I'm pretty that this is caused by a foreign key field to another model with many and large entries.
After several hours of googling I found a possible solution: Implementing on delete constraints on database level.
I also found a long lasting discussion in a Django PR https://github.com/django/django/pull/8661 which would enable this feature. But I seems like it never reached 100% and will not be merged in the near future.
Another way to solve my issue is mentioned in Django Docs https://docs.djangoproject.com/en/3.1/ref/models/fields/#django.db.models.DO_NOTHING
DO_NOTHING
Take no action. If your database backend enforces referential integrity, this will cause an IntegrityError unless you manually add an SQL ON DELETE constraint to the database field.
I'm using MariaDB. And I want to add a SET_NULL constraint to only one foreign key field of one model on database level.
How can I do that in Django? I can perfectly live with hard coded ugly solutions, if they solve my problem and don't introduce new ones.
Related
We have a potential race condition where multiple users can try to create or update a record. Wondering if there's a way to create a column, than when set (to say true), then an exception will be thrown, preventing the update.
The underlying database is postgres, but since we're using django to wrap it, we would like to limit ourselves to something django offers, and not mess with very specific database settings. Thanks!
There were some questions in the past about this but as Django grows, there are many new database functions.
I'm looking for a way to prevent model to be deleted from anywhere by anyone.
I have a model Product and I don't want product to be deleted from database ever.
I understand that overriding delete is sometimes a good way but I would like to do it on database level so there is no chance to delete it from shell_plus or any other source.
In Postgres, I think, there is a way:
CREATE RULE product_del_protect AS ON DELETE TO product DO INSTEAD NOTHING;
But I would like to do it through Django so every migrated database will be affected.
There may be a way to do that in model or custom migration.
And better would be to raise an error.
I am currently developing a server using Flask/SqlAlchemy. It occurs that when an ORM model is not present as a table in the database, it is created by default by SqlAlchemy.
However when an ORM class is changed with for instance an extra column is added, these changes do not get saved in the database. So the extra column will be missing, every time I query. I have to adjust my DB manually every time there is a change in the models that I use.
Is there a better way to apply changes in the models during development? I hardly think manual MySql manipulation is the best solution.
you can proceed as the following:
new_column = Column('new_column', String, default='some_default_value')
new_column.create(my_table, populate_default=True)
you can find more details about sqlalchemy migration in: https://sqlalchemy-migrate.readthedocs.org/en/latest/changeset.html
I have seen several posts on this site, and on others, stating that the problem is usually caused by the order in which the tables are added to the Configuration of the SyncAgent on the client side, or the SyncAdapter on the provider side. I believe I have my ordering of the tables correctly in both these places (I have an N-Tier architecture - a web service that is providing sync functionality).
Does anyone know of any other potential cause for this behavior?
Also: Sycning works for all tables, except one. For some reason, that table is created on the client but, no records are transferred...even on the initial sync, when the database is created on the client. Any ideas?
Any help would really be appreciated. (getting this sync functionality to work, and then the data entities for the client to use based on the synced data, is turning into a life mission. Don't you just love working with (massive) Frameworks?)
Thanks very much for whatever you can suggest.
[UPDATE: I have found the problem that caused the records for one table to be omitted from the sync, while the records from all the other tables were synced. The InsertId column for the table in question was full of NULL values, and UniqueIdentifier data can't be compared to NULL. The other tables don't have an InsertId column, because they are for download only. Still, the main problem of no Foreign Key relationships persists]
OK, I found this statement:
By default, the following constraints are not copied to the client: FOREIGN KEY constraints, UNIQUE constraints, and DEFAULT constraints
in this document: http://msdn.microsoft.com/en-us/library/bb726037.aspx
So, it appears I have to "manually" create the relationships, once the schema is created on the client.
It is crucial that you add the adapters to the server side provider in the correct order. You also need to make sure that you avoid all multi-table circular references or you will need to write some complicated multi-pass synchronization logic to sync first the tables without the foreign keys and then the foreign keys after the fact. Perhaps a circular reference is why you are losing just the one table. Good discussion of the issue here http://www.8bit.rs/blog/2009/12/replicating-self-referencing-tables-and-circular-foreign-keys-with-microsoft-sync-framework/.
When I was working on this same problem last month, I found that using the INFORMATION_SCHEMA, you can write a pretty good stored procedure to dynamically determine the relationship hierarchy for use in setting up a generic synchronization provider. Let me know if you are interested in something like this...
One workaround for syncing Foreign Key Relationships is explained in my answer here Sync Framework 2.1 Foreign key constraints
I just need a confirmation for my understanding on Django's implementation of ON DELETE CASCADE from you Django experts.
According to the official Django documentation:
When Django deletes an object, by default it emulates the behavior of
the SQL constraint ON DELETE CASCADE -- in other words, any objects
which had foreign keys pointing at the object to be deleted will be
deleted along with it.
Does the word "emulate" imply that the ON DELETE CASCADE logic is actually implemented in Django instead of at the database level? (I looked into my database and all the tables that contains foreign keys have ON DELETE NO ACTION in their definitions.)
If my understanding is correct, is there any way that I can relocate the ON DELETE CASCADE logic from the app layer to the database layer? I am more looking for a proper way, not an hack, of doing this. (Note: I am using PostgreSQL as my backend.)
If you are asking where the relevant code is implemented: You can find it here.
Implementing the CASCADE-DELETE logic in the application/ORM layer makes sense as this enables the app to get informed when deletion happens (eg. Django's delete signals are fired for the deleted instances), furthermore it is a sane way to enable this feature across different types of databases.
If you are worried about the integrity of your data: Django still sets foreign key constraints if your database supports this (eg. check Postgresql). So your database won't let you delete any rows a foreign key is pointing to.
Try it yourself:
> DELETE FROM accounts_publisher WHERE id=5;
ERROR: update or delete on table "accounts_publisher" violates foreign key constraint "accounts_publisher_id_411559b18a178e73_fk_accounts_publisher_id" on table "accounts_membership"
DETAIL: Key (id)=(5) is still referenced from table "accounts_membership".
FYI, this has been configurable since django 1.3:
https://docs.djangoproject.com/en/1.6/ref/models/fields/#django.db.models.ForeignKey.on_delete
Basically you need to set on_delete to DO_NOTHING and add the cascade logic to the DB yourself:
DO_NOTHING: Take no action. If your database backend enforces referential integrity, this will cause an IntegrityError unless you manually add a SQL ON DELETE constraint to the database field (perhaps using initial sql).