is it possible to remove an M2M field from a model and keep the joining table?
context:
I am trying to add through model to existing M2M field like described in this post
But doing it simply like this will result in a production app crash when accessing the old table during deployment - short window between migration and code update, when old code will try to access a new database for a few moments - without the old table in it.
You can use --fake flag when running manage.py migrate. That will make a migration file that says the model field has been removed and mark it as applied in the database migration table, but not actually execute the SQL to remove the corresponding tables etc. Read more here
Related
I have this model that is a post like on Twitter, that has a creator. I'd ideally like the post to always require a creator_id and if the creator gets deleted then delete the post as well
class Post(AbstractBaseModel):
creator_id = models.ForeignKey(User, on_delete=models.CASCADE, related_name="post_creator_id")
body = models.CharField(max_length=511)
Whenever I try to run 'python manage.py migrate' I get this error
"You are trying to change the nullable field 'creator_id' on cheerpost to non-nullable without a default; we can't do that (the database needs something to populate existing rows)."
The options to solve this are are 1) provide a one off default or 2) ignore for now. Neither of these seem to fulfill my constraint that I want to enforce, which is creator_id must exist and is the person who created the post or the entity gets deleted.
I've tried deleting the DB and recreating it from scratch in postgres as well as deleting it using the following query:
TRUNCATE Post;
DELETE FROM Post;
If you've deleted the DB, just the data and tables from DB are deleted.
That doesn't reflect any changes in Django. All the changes you've made to the fields of your model still exist in migrations. You have to delete the old migrations too.
Delete those old migrations from your app, create new migrations from scratch and apply them.
python manage.py makemigrations
python manage.py migrate
Django is asking you to provide a one-off default for any rows you already have in your database, since the field was nullable before the migration. The issue is that Django doesn’t know if there are any rows in the existing database where that column is null, so it needs instructions on what to do if it finds any. You can just provide one and forget about it—it will never be used again after the migration is complete.
Also, you may want to review how the related_name parameter works; you’ve got it backwards.
I am building an app in Django and it uses a live/in-use database.
Basically since the apps development the SQL Database has undergone some structure changes and it is causing issues with Django, Django will try to apply migrations to the database that already exist. For example:
In the Django app I marked the email column as unique which was fine based on the development database. However the main database now always has a table change that marks the email column as unique. Django is fighting this unique key with the one that already exists.
So is it possible to clear all Django migrations and have it make migrations again compared to the more up to date SQL database structure?
If your models are very out of sync with your database, the easiest option is probably to rebuild your models from scratch using inspectdb.
If your models are pretty close to the database already, the first step is to make sure that your models match the database exactly. You can use sqldiff from django-extensions for this.
Once your Django models match your database, follow this answer to re-create migrations based on the existing database schema.
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.
I have a question about Django's migration feature when there is an existing table.
ContentData
ContentType
Faq
UserLog
TB_TEAM_INF
When I try to do "./manage.py migrate" so it can create the 5 tables above from models.py, I got an error message because there is an existing table, TB_TEAM_INF.
Since TB_TEAM_INF is a table being used by another team, I cannot remove the table. I cannot use a separated database either due to constraints of the project. In this case I open the migration file like 0001_initial.py and manually remove the model object, TB_TEAM_INF temporarily during migration.
Is there a better way to ignore existing tables when "./manage.py migrate" rather than manually editing the migration file?
I tried --exclude=TB_TEAM_INF or --ignore=TB_TEAM_INF option with ./manage.py migrate but it seems those options are not accepted. I am using Django 1.7.2.
Add the managed option to your model definition:
class TB_TEAM_INF(models.Model):
...
class Meta:
managed = False
Excerpt from the documentation:
If False, no database table creation or deletion operations will be performed for this model.
I created a table before I code the Django app and now I merged both the app and the table with following command python manage.py inspectdb > models.py. However after some while I really need to change the value type of one of the column. Is it enough to chage it through the model file or do I need some additional steps?
If you change a field in a Django model, Django itself doesn't know how to update your database accordingly (syncdb only add tables from new models).
You have two options:
manually create your database tables;
use a migration tool like South that detects and generates migration files from changes made to your models;
I recommend the second option as it's programmatic, more error-proof and makes your life easier when you need to go back and forth between database schemas.
There is an easy way to do this. (in Django 2)
After making the necessary changes to the model.py file of your app, run command:
python manage.py makemigrations - This will generate a new file in migration folder of your app.
python manage.py migrate - This will apply those edits on actual databse.
To check if the changes have been applied, run command : .schema <tablename> in your terminal, after entering the sqlite command-line program.