4

I need to add slug field to django model, and i thing it's better when it not null. So i'm trying to add slug to model

slug = models.SlugField(
    'URL',
    unique=True,
    default=id_generator,
)

my id_generator:

import string
import random
def id_generator():
    size=16
    chars=string.ascii_lowercase + string.digits
    return ''.join(random.choice(chars) for x in range(size))

The problem is when i migrate changes. Method id_generator is calling one time and uses the same value for all model objects. So i have dupliicate entrie in unique field. How can i generate unique values? Django 1.11.5

P.S. I understand, that i can set null=True and customize model's save method to add slug when saving.

Eugeny Maksimov
  • 181
  • 1
  • 7
  • Side note and certainly an edge case: There's nothing in your id_generator that would guarantee uniqueness even if it was called for each instance. – user2390182 Sep 28 '17 at 11:11
  • Possible duplicate of [Add non-null and unique field with already populated model](https://stackoverflow.com/questions/27749300/add-non-null-and-unique-field-with-already-populated-model) – user2390182 Sep 28 '17 at 11:15

1 Answers1

1

MOST IMPORTANT: You have not good generator for unique slug, may be best way use uuid for example

import uuid

slug = models.CharField(max_length=64, blank=True, unique=True, default=uuid.uuid4)

by add-unique-fields

  1. Added null=True, without default With data migration
  2. Alter model with current filed description, with migrate.

example first step migration, replace YOUMODEL:

from __future__ import unicode_literals
import string
import random
from django.db import migrations, models


def id_generator():
    size=16
    chars=string.ascii_lowercase + string.digits
    return ''.join(random.choice(chars) for x in range(size))

def update_slug(pp, schema_editor):
    for instance in YOUMODEL.objects.all():
        #           ^^^^^^^
        instance.slug = id_generator()
        instance.save()


class Migration(migrations.Migration):

    operations = [
        migrations.AddField(
            model_name='YOUMODEL',
            #           ^^^^^^^
            name='slug',
            field=models.SlugField(null=True, verbose_name='URL'),
        ),
        migrations.RunPython(code=update_slug)

    ]
Brown Bear
  • 19,655
  • 10
  • 58
  • 76
  • i used my id_generator just for example. The question is why does this method called only one time, because i remember i set method in default value and it generated value for every model instance in older django versions – Eugeny Maksimov Sep 28 '17 at 11:43
  • don sure that it was worked any time, by django docs [add-unique-fields](https://docs.djangoproject.com/en/1.11/howto/writing-migrations/#migrations-that-add-unique-fields), maybe you are confusing something? – Brown Bear Sep 28 '17 at 12:14