Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

default value as callable is only called once during django migration

I've created the following basic django model :

import string
import random

from django.db import models

def create_short_url():
    size = 6
    chars = string.ascii_uppercase + string.digits
    url = ''.join(random.choice(chars) for _ in range(size))
    print("\nSHORT_URL:%s\n" % url)
    return url

class ShortURL(models.Model):
    url = models.CharField(max_length=220, )
    shortcode = models.CharField(max_length=15, unique=True, default=create_short_url)

    def __str__(self):
        return str(self.url)

First I only coded the url field. Then I added the shortcode field and provided a function to be called to create default unique values. Django's documentation says

If callable it will be called every time a new object is created.

Unfortunately, when running the migration, I see only one short url generated and the following exception :

$ python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, sessions, shortener
Running migrations:
  Applying shortener.0002_auto_20161107_1529...
SHORT_URL:43AY7G

Traceback (most recent call last):
  File "/home/user/django1.10/py3/lib/python3.5/site-packages/django/db/backends/utils.py", line 64, in execute
    return self.cursor.execute(sql, params)
  File "/home/user/django1.10/py3/lib/python3.5/site-packages/django/db/backends/sqlite3/base.py", line 337, in execute
    return Database.Cursor.execute(self, query, params)
sqlite3.IntegrityError: UNIQUE constraint failed: shortener_shorturl.shortcode

What is missing to call that function for each entry being migrated?

like image 568
samb Avatar asked Nov 16 '25 16:11

samb


1 Answers

Initially, you will need to defer the unique constraint on the shortcode field and permit null values and then re-create and run your migration.(don't forget to remove the migration that fails)

class ShortURL(models.Model):
    url = models.CharField(max_length=220, )
    shortcode = models.CharField(max_length=15, null=True)

    def __str__(self):
        return str(self.url)

After that, 1) create a new empty migration and add a RunPython operation that leverages your create_short_url(). 2)change your model to your original definition and create a new auto migration and run it.

Refer here for more information: Migrations that add unique fields

like image 136
mrmick Avatar answered Nov 19 '25 05:11

mrmick