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()
Related
After setting up history for a model using django-simple-history, I wanted to run populate_history to populate the history table based on the existing contents of the table. However, other users have already made a number of changes, causing the history table to be partially populated. Running populate_history --auto simply results in message Existing history found, skipping model.
I wish to retain the existing history, but populate history for all records not currently stored in the history. Is there a way to do this?
I ended up writing a modified script based on populate_history. It identified all objects with no historical records, and added them in to the history table. A simple version (no batching) is below.
from django.apps import apps
from simple_history.utils import get_history_manager_for_model, get_history_model_for_model
def populate_model_history(model):
history = get_history_model_for_model(model)
history_manager = get_history_manager_for_model(model)
# Insert historical records for objects without existing history
# NOTE: A better approach would be to do this in batches, as in populate_history.py
for instance in model.objects.exclude(pk__in=history.objects.values_list(model._meta.pk.name)):
history_manager.bulk_history_create([instance], batch_size=1)
model = apps.get_model('app', 'my_model')
populate_model_history(model)
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 deployed my Django website but just now realized that I didn't make one of the fields compulsory. For the field it is currently,
blank=True, null=True
Now if I go ahead and change it to
blank=False
will there be any effect on the database and already existing data in it?
No. blank is enforced solely at the application level.
As discussed at https://docs.djangoproject.com/en/dev/ref/models/fields/#django.db.models.Field.blank :
"blank" is about the form validation; you can change this at any time without affecting
your database.
"null" is about the storage in the database, not about form validation
So if you change from "blank=True, null=True" to "blank=False", you'll still be able to store null values in the table--but you won't have a way to actually get those null values into the database, since your forms will require input.
This might be exactly what you want (and no db migration would be needed).
If you want to get existing null values out of your database, update your data, then set both blank and null to False. At that point, though, you'd need to do a database migration (via South or by just directly changing your database with an ALTER TABLE ... ALTER command).
I just tested it myself. I had Django models, and there have already been instances of the models in the database.
Then I added a dummy integer field to a model and ran manage.py syncdb. Checked the database, and nothing happened to the table. I don't see the extra field added in.
Is this the expected behavior? What's the proper way of modifying the model, and how will that alter the data that's already in the database?
Django will not alter already existing tables, they even say so in the documentation. The reason for this is that django can not guarantee that there will be no information lost.
You have two options if you want to change existing tables. Either drop them and run syncdb again, but you will need to store your data somehow if you want to keep it. The other options is to use a migrations tool to do this for you. Django can show you the SQL for the new database schema and you can diff that to the current version of the database to create the update script.
You could even update your database mannually if it is a small change and you don't want to bother with migrations tools, though I would recommend to use one.
Please use south for any kind of changes to get reflected to your database tables,
here goes the link for using south
Link for South documentation