7

In a comment to this question answer I asked how to remove a field with a default value function. To sum up, the example code is:

def get_deadline():
    return datetime.today() + timedelta(days=20)

class Bill(models.Model):
    name = models.CharField(max_length=50)
    customer = models.ForeignKey(User, related_name='bills')
    date = models.DateField(default=datetime.today)
    deadline = models.DateField(default=get_deadline)

and my question to the code is:

How do you remove the deadline field again while also deleting the get_deadline function? I have removed a field with a function for a default value, but now Django crashes on startup after removing the function. I could manually edit the migration, which would be ok in this case, but what if you simply changed the default function, and wanted to remove the old function?

I ended up removing the default part of the migration that referred to it, but how do you remove it nicely?

The only way I can think of is to squash the migrations, such that the migration using the function disappears, but that is not always an option.

Community
  • 1
  • 1
beruic
  • 5,517
  • 3
  • 35
  • 59

4 Answers4

8

Following the documentation from Historical Models:

References to functions in field options such as upload_to and limit_choices_to and model manager declarations with managers having use_in_migrations = True are serialized in migrations, so the functions and classes will need to be kept around for as long as there is a migration referencing them. Any custom model fields will also need to be kept, since these are imported directly by migrations.

.....

To remove old references, you can squash migrations or, if there aren’t many references, copy them into the migration files.

Using a method to get the value of default field option is same as what is described for upload_to field. The documentation itself provide two options to you if you want to remove the method:

  1. Squash migrations - if you don't need those anymore
  2. Edit migration file: Copy functions to migration files and edit the reference in migration.

Updates from comments:

In Step 2 of Edit migration file, I have just included the way described in the documentation. How exactly you edit the migration is your choice. You could copy the function in the migration file and edit the reference or you could just remove the default field from the migration file, or you could use another function from a different file.

Community
  • 1
  • 1
AKS
  • 18,983
  • 3
  • 43
  • 54
  • Or as per @Alasdair's answer: 3. Edit the migrations to use a different (or no) default – beruic Dec 06 '16 at 13:05
  • 1
    I would say both the answers suggest only two steps 1) squashing the migration 2) editing the migration. How exactly you edit the migrations is your choice. You could copy the function there and edit the reference. Or, you can just remove the default field from there, or you can use another function from somewhere else. :) – AKS Dec 06 '16 at 14:15
  • I have added my comments in the answer. – AKS Dec 06 '16 at 17:35
  • I'd prefer if the second step was clarified in the update section – beruic Dec 08 '16 at 13:11
  • @beruic: It is already clarified and explained. You don't really need to add step 2 again in the answer. – AKS Dec 08 '16 at 14:16
  • I know. I'm just worried that readers will miss it. Perhaps you can make the "Update from comments:" part bold instead to emphasize its importance, and make the first words in the text "In step 2..." instead of "In second step..." so the number is made clear. – beruic Dec 09 '16 at 14:48
  • I updated the answer with emphasis and also changed the language a bit. – AKS Dec 09 '16 at 15:07
2

It looks like you've pretty much figured out the answer for yourself. Before you remove the get_deadline function, you must remove it from any migrations that use it. There are two ways to do this:

  1. editing the migrations that use get_deadline to use a different default.
  2. squashing migrations to remove the migrations that refer to get_deadline.
Alasdair
  • 298,606
  • 55
  • 578
  • 516
  • 1
    Or as per @AKS' answer: 3. Copy functions to migration files and edit the reference in migration – beruic Dec 06 '16 at 13:06
0

How do you remove the deadline field again while also deleting the get_deadline function?

I think removing both at the same time (i.e. “while” doing the other) is not the correct way to do it. Instead:

  • Add a migration to remove the field. Deploy that migration as revision N.

  • Confirm that nothing is using the function any more.

  • In revision N+M (i.e., a later revision) remove the unused function.

That way, the database will match the state of the code, because the migrations are part of that code state: When you migrate your database back to the state as of revision N, the function will be there. When you migrate your database to the state as of revision N+M, you won't need the function any more.

bignose
  • 30,281
  • 14
  • 77
  • 110
-3

My straight forward answer will be deleting the sqlite3.db and delete all the migrations except the __init__.py in the migrations folder in each app.

Then again do python

$manage.py makemigrations
$python manage.py migrate
subha.py
  • 463
  • 3
  • 18