I'm currently trying to update my Django models to incorporate some new functionality but after runnning "makemigrations", the console output makes me worried I'm going to overwrite other tables in the database.
Essentially, in my models.py, I have 8 models. One is entirely new, one is merely modified. I want to migrate these changes to the database so I run "makemigrations". A migration's file is created (I note there are no others whatsoever - presumably the colleague who created these originally has deleted them for whatever reason). The console output is:
- Create model ModelNew
- Create model ModelDontTouch
- Create model ModelDontTouch
- Create model ModelDontTouch
- Create model ModelDontTouch
- Create model ModelDontTouch
- Create model ModelDontTouch
- Create model ModelUpdated
Why does it say create model? Is it because, as far as Django knows, this is the first migration ever performed? Or does it plan on overwriting all those other tables (which would kill our app completely and result in a very terrible day)?
I also notice some models have specified
db_table = 'some_table'
db_tablespace = 'sometable'
others, just,
db_tablespace = 'sometable'
others, nothing at all. Anyone have any thoughts on this?
Django doesn't interrogate the database itself when making migrations; it builds up a graph based on previous migrations and the current state of the models. So if there are no previous migrations Django will create them from scratch. This won't overwrite your tables, but it won't actually work either, as it will attempt to create them and the database will refuse.
One option would be to temporarily revert your changes and run makemigrations again to get back to the right starting point, then run that migration with --fake-initial to mark it as applied without actually doing it, then reapply your changes and run makemigrations again.
Related
Does changing Django Model from managed=False to managed=True affect the data ?
I have a large table of a Model that has managed=False and want to add a new field to it. adding a field using migration can't be done without changing the model to managed=True
Is it safe to just change it to managed=True , migrate the change, then update fields ?
Yes. It is safe and required. I have read django documentation about your problem. That says that:
Managed option defaults to True, meaning Django will create the
appropriate database tables in migrate or as part of migrations and
remove them as part of a flush management command. That is, Django
manages the database tables’ lifecycles.
If False, no database table creation, modification, or deletion
operations will be performed for this model.
If your django model option managed=False then make it managed=True, otherwise your migration of models won't work. For more info read django documentation.
I am working on an existing Django project that contains migration code like:
someFluffyModel.objects.all().delete()
or
someModel = SomeModel(....)
someModel.save()
Now wherever there is such code and newer migrations change the schema that reflect the current version of the model, there is an issue in applying migrations from scratch.
As I understand the reason is that the model used in the migration doesn't reflect the model used in the migration at that point in time. As I have found fixtures can help in loading data but how about deletion?
Is the preferred way to manually delete data from the database?
Sorry forgot to answer my own old question it's been years now but just in case anybody is curious in your migrations you should always be using historical models. The reason is that you get the model at a point in time(reconstructed incrementally base on schema migrations).
def forwards_func(apps, schema_editor):
# We get the model from the versioned app registry;
# if we directly import it, it'll be the wrong version
Country = apps.get_model("myapp", "Country")
This way if you try to re-run your migrations at some point in the future with model schema x'' old migrations will be run using x' and x depending on their dependencies.
Avoid importing models to your migrations directly at any cost.
It is always important to be able to rer-run you migrations since that allows you to migrate forwards backwards between your environments roll back faulty deployments and above all run your tests. If you are doing it wrong your tests will fail at some point when you'll get to schema x' and you'll have to follow the correct approach mentioned above to fix them.
Thanks to #Daniel Roseman for giving me some pointers that day.
When developing models I quite often get the non-nullable field error when running makemigrations:
You are trying to add a non-nullable field 'user' to randommodel without a default; we can't do that (the database needs something to populate existing rows).
Please select a fix:
1) Provide a one-off default now (will be set on all existing rows)
2) Quit, and let me add a default in models.py
Select an option:
Almost all the time when I get this error I'm quite happy to delete the data in that table (it's normally only a couple of test entries while developing) and it would be more efficient to just delete it rather than determine what a suitable default would be.
However currently I don't have a suitable method for doing this and end up flushing the database and/or deleting the migrations, which is pretty heavy handed but works.
What's the best way to delete the data just in that model/table to remove the error? (Would it be via shell/shell_plus?)
Model:
class RandomModel(models.Model):
user_details = JSONField(unique=True)
user = models.ForeignKey(User)
Even if you have deleted all the records in that table, when running makemigrations, you'll be asked to provide default values again. This is because you're making a new migration file for an existing table.
One solution I can think of is to tell Django that you're starting that app_name over again by running migrate app_name zero. This will unapply all migration files that have ever been applied to your database.
Then delete all the migration files in your app_name. And run makemigrations again. This would create a new initial migration file. Then you just apply it to your database with migrate.
As you've said you don't mind deleting your data. This is even better. You don't have to even delete any record. It will just create a new table with the same name with all the new fields and with 0 record.
If one is using Django, what happens with changes made directly to the database (in my case postgres) through either pgadmin or psql?
How are such changes handled by migrations? Do they take precedence over what the ORM thinks the state of affairs is, or does Django override them and impose it's own sense of change history?
Finally, how are any of these issues effected, or avoided, by git, if at all?
Thanks.
You can exclude a model completely from the django migrations, and then you are responsible to adjust the schema to the django code (or the django code to the existing schema):
class SomeModel(models.Model):
class Meta:
managed = False
db_table = "some_table_name"
name = models.Fields....
Note that you can't have it both ways, so migrations are preferred when possible. You can always define a custom SQL migration, that will save the need for external changes. However, sometimes you do need to handle the schema elsewhere instead of migrations, and then use managed=False
The migrations system does not look at your current schema at all. It builds up its picture from the graph of previous migrations and the current state of models.py. That means that if you make changes to the schema from outside this system, it will be out of sync; if you then make the equivalent change in models.py and create migrations, when you run them you will probably get an error.
For that reason, you should avoid doing this. If it's done already, you could apply the conflicting migration in fake mode, which simply marks it as done without actually running the code against the database. But it's simpler to do everything via migrations in the first place.
git has no impact on this at all, other than to reiterate that migrations are code, and should be added to your git repo.
I am writing a django south migration that depends on the model in another app, so I have included --freeze OTHERAPPNAME when I ran python manage.py datamigration …
However in the forwards() function I can access the other model fine (with orm['otherappname.MyModelName']), however in the backwards() step (which also depends on the model in otherappname), if I try to access orm['otherappname.MyModelName'], I get an error
*** KeyError: "The model 'mymodelname' from the app 'otherappname' is not available in this migration."
I can see the frozen model details in the bottom of the file. Why can't I access it?
NB: This model is created in another migration inside otherappname of which this datamigration depends on.
The backwards migration actually uses the frozen ORM of the previous migration. It's logical when you think about it, but it's admittedly not very intuitive.
Moral: freeze the models you'll need in your datamigration in the schemamigration that proceeds it.