Django 2.1/PostgreSQL - can I prevent deleting model objects? - django

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.

Related

How to add manually on delete SQL constraints in Django?

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.

Change django model from one app to another, but on makemigrations, new model is added

I have two this model, which I want to move to another app.
After running this migration, I successfully could see the model under the required app.
But when I added another field, It was adding the entire model to the new migrations in new_app.
According to most tutorials, it should have added just the field.
I don't wanna fake the migrations, as it can cause issues.
Please point out my mistake.
Problem: On adding a new field in new_app model, the migrations has "CreateModel". How to avoid this?
Please help.
Migrations are persisted on your db, there's a dedicated table that keeps the track of your changes. You shouldn't modify migrations directly.
My suggest:
for development purpose you can delete your migration's files and migration's table.
Try to create your migration once you moved your model If you can't delete anything,
then you should have something like.
users/0001_mymodel.py
users/0002_mymodel_deleted.py
otherapp/0001_mymodel_added.py
otherapp/0002_adding_field.py

Adding new field in Django model

I am currently working on a Django project with around 30 models and there are lots of relations(For example, foreign key relations) between the models.
My doubt is "After 6 months, let's say I want to add a new field(s) in one of the model/table(s) in models.py, and make migrations, the new migration files will get created without affecting the initial migration files which were created 6 months ago."
Will the relations be maintained after adding new columns in different tables? (or) do I have to go to pgadmin console and tweak them accordingly?
One way is to erase all the migrations and start fresh, but this is not recommended often especially if there is production data (or) there are frequent changes in the database schema.
#Mahesh, You may use --fake-initial to avoid the existing tables error at the time of new migrations(When you want to add new column).
Relation will be maintained since you already declared it and unless you change it in a new migration.
How to add a new field to a model with new Django migrations?
And in Docs: https://docs.djangoproject.com/en/3.0/ref/django-admin/#cmdoption-migrate-fake-initial
If you don't change Django version, adding new fields on models will not create any problem, even after many years. But, there are some situations this might create problems. For example, if Django is updated and you have installed the latest version.

How to revert changes, specifically deletions, with django-simple-history

We have django-simple-history set up for our models. Recently a whole bunch of models were mysteriously deleted. This was noticed a few days after the fact, so it would be nice to avoid a full DB backup restore since that would wipe manual changes that happened after the fact.
I cannot find any way to easily restore an model instance, specifically a deleted one. I can query the Historical version of the model and find everything that was deleted. With that I can also observe that all of them had deletions as their last change. I can use the instance property on history - 1 to get the state before deletion but if I try to save that it errors since the model instance was deleted and doesn't exist anymore.
So basically, what is the cleanest way to restore a deleted model instance if I have the Historical record of it with django-simple-history? I would like to retain the history if possible, so I am looking into any solution before totally recreating the objects.
As I understand, the question, it is about restoring a deleted model instance, not the class itself. So Kal's answer does not help here.
To restore a deleted instance, simple history can NOT be used. According to the documentation, simple history can only restore model instances that are still existing.
Since you have a full backup of the database, you can import this database into the django environment, load the old model instance from this backup database and save it to the production database (choose the database in django shell with "using"). See this post.
The best way to avoid such situations is to use the app "reversion". With this django-app, you actually can restore deleted instances. See the documentation.
Do you mean that your model, not just the instances, has been completely deleted? If that’s the case, it probably means some migration removed it.
You could try reverting the migration then restore from the Historical record.
The previous version of your model is stored in the _HISTORICAL<model_name> table. You could do a simple sql insert/select query to copy the data from that table back into the original table. Something like the below would work, but check the correct sql syntax for your database.
insert into app_mymodel (col_a, col_b)
select col_a, col_b from app_HISTORICALmymodel
where id in (1,2,3...)
If model using django-simple-history then,
Data can be restored from the historical model.
We need to filter from the historical model. for eg with some keyword or in some date range in which period the data got deleted accidentally.
For eg. the Model Name is Car, then by default django-simple-history creates a historical model as HistoricalCar.
historical_data = HistoricalCar.objects.filter(history_type='-')
for each in historical_data:
instance = each.instance # This return instance of car.
instance.pk = None # Create New Instance
instance.save()

Generally, when does Django model change require South?

I am new to Django. I have completed the tutorial and am reading the documentation for more learning. As I try to add to my understanding, say, in new Managers or ModelForms I am curious as to what needs South (or even just scrapping it and rewriting the app).
update django database to reflect changes in existing models
The link above says basically that any column change it is necessary, while the link below is more of what I am asking. Can someone generalize when it is not needed (eg: Adding a new Form/ModelForm based on an existing Model? Adding a Manager?) If no changes are made to the columns of the database South is not then not necessary?
Does changing a django models related_name attribute require a south migration?
There are two types of south migrations: schema and data.
Data migrations are used to change data in the DB and not the schema of the DB.
The schema migrations are the ones you are interested in. They are used to keep track of changes to the DB schema and one should accompany any changes to your models that result in DB schema change (create table, drop table, drop column, change null constrain e.g.)
Some great insights might be found if you read two consecutive migrations for a django app.
In each of them you can find code that applies the migreation, code that reverts the migrations and a snapshot of the DB schema.
P.S. It is quite easy to check if south migration is needed for a particular change in your models. Just run a schemamigration for the modified django app and delete the newly created migration if such was created. As creating a south migration is different that running it, this is a great way to test and learn.
Keep in mind that south is a piece of software like any other and it does 'support' bugs.
Related_name attribute changes only affect your project and django uses it to make queries.
Changes like blank = True/False, null = True/False, symmetrical = True/False require database changes although symmetrical = True/False does not trigger update by south, but the setting definitely makes difference at field creation.
Column changes, like the link in your post shows, require updates in database and that's what south does very good.