Создать уникальную строку для каждого объекта БД - PullRequest
2 голосов
/ 18 февраля 2020

У меня есть модель, в которой мне нужно создать строку UNIQUE для каждого объекта в БД.

Я создал функцию для генерации строки, но я могу создать объект, использующий администратора django один раз, а затем во второй раз он выдаст ошибку и скажет, что значение не является уникальным.

Что я могу сделать, так что Django просто генерирует новую строку, если предыдущая уже использовался?

models.py

def randomword(length):
   letters = string.ascii_lowercase
   return ''.join(random.choice(letters) for i in range(length))

class Refferal(models.Model):
    email = models.EmailField(max_length=254, unique=True)
    coupon = models.CharField(default=randomword(4), primary_key=True, editable=False, max_length=4)
    count = models.IntegerField(default=0)

Вывод журнала, когда я пытался создать второй объект с помощью администратора Вышеуказанное исключение было прямой причиной следующего исключения:

Traceback (most recent call last):
  File "/usr/local/lib/python3.7/site-packages/django/core/handlers/exception.py", line 34, in inner
    response = get_response(request)
  File "/usr/local/lib/python3.7/site-packages/django/core/handlers/base.py", line 115, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File "/usr/local/lib/python3.7/site-packages/django/core/handlers/base.py", line 113, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/usr/local/lib/python3.7/site-packages/django/contrib/admin/options.py", line 607, in wrapper
    return self.admin_site.admin_view(view)(*args, **kwargs)
  File "/usr/local/lib/python3.7/site-packages/django/utils/decorators.py", line 130, in _wrapped_view
    response = view_func(request, *args, **kwargs)
  File "/usr/local/lib/python3.7/site-packages/django/views/decorators/cache.py", line 44, in _wrapped_view_func
    response = view_func(request, *args, **kwargs)
  File "/usr/local/lib/python3.7/site-packages/django/contrib/admin/sites.py", line 231, in inner
    return view(request, *args, **kwargs)
  File "/usr/local/lib/python3.7/site-packages/django/contrib/admin/options.py", line 1638, in add_view
    return self.changeform_view(request, None, form_url, extra_context)
  File "/usr/local/lib/python3.7/site-packages/django/utils/decorators.py", line 43, in _wrapper
    return bound_method(*args, **kwargs)
  File "/usr/local/lib/python3.7/site-packages/django/utils/decorators.py", line 130, in _wrapped_view
    response = view_func(request, *args, **kwargs)
  File "/usr/local/lib/python3.7/site-packages/django/contrib/admin/options.py", line 1522, in changeform_view
    return self._changeform_view(request, object_id, form_url, extra_context)
  File "/usr/local/lib/python3.7/site-packages/django/contrib/admin/options.py", line 1565, in _changeform_view
    self.save_model(request, new_object, form, not add)
  File "/usr/local/lib/python3.7/site-packages/django/contrib/admin/options.py", line 1081, in save_model
    obj.save()
  File "/usr/local/lib/python3.7/site-packages/django/db/models/base.py", line 746, in save
    force_update=force_update, update_fields=update_fields)
  File "/usr/local/lib/python3.7/site-packages/django/db/models/base.py", line 784, in save_base
    force_update, using, update_fields,
  File "/usr/local/lib/python3.7/site-packages/django/db/models/base.py", line 887, in _save_table
    results = self._do_insert(cls._base_manager, using, fields, returning_fields, raw)
  File "/usr/local/lib/python3.7/site-packages/django/db/models/base.py", line 926, in _do_insert
    using=using, raw=raw,
  File "/usr/local/lib/python3.7/site-packages/django/db/models/manager.py", line 82, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "/usr/local/lib/python3.7/site-packages/django/db/models/query.py", line 1204, in _insert
    return query.get_compiler(using=using).execute_sql(returning_fields)
  File "/usr/local/lib/python3.7/site-packages/django/db/models/sql/compiler.py", line 1384, in execute_sql
    cursor.execute(sql, params)
  File "/usr/local/lib/python3.7/site-packages/django/db/backends/utils.py", line 68, in execute
    return self._execute_with_wrappers(sql, params, many=False, executor=self._execute)
  File "/usr/local/lib/python3.7/site-packages/django/db/backends/utils.py", line 77, in _execute_with_wrappers
    return executor(sql, params, many, context)
  File "/usr/local/lib/python3.7/site-packages/django/db/backends/utils.py", line 86, in _execute
    return self.cursor.execute(sql, params)
  File "/usr/local/lib/python3.7/site-packages/django/db/utils.py", line 90, in __exit__
    raise dj_exc_value.with_traceback(traceback) from exc_value
  File "/usr/local/lib/python3.7/site-packages/django/db/backends/utils.py", line 86, in _execute
    return self.cursor.execute(sql, params)
django.db.utils.IntegrityError: duplicate key value violates unique constraint "index_refferal_coupon_a6e4bc31_pk"
DETAIL:  Key (coupon)=(vtgs) already exists.

1 Ответ

4 голосов
/ 18 февраля 2020

Здесь вы оцените с нетерпением вызов randomword(4) и установите результат этого вызова функции в качестве значения по умолчанию. Однако вы можете передать вызываемое:

def randomword(length):
   letters = string.ascii_lowercase
   return ''.join(random.choice(letters) for i in range(length))

def <b>random4</b>():
    return randomword(4)

class Refferal(models.Model):
    email = models.EmailField(max_length=254, unique=True)
    coupon = models.CharField(default=<b>random4</b>, primary_key=True, editable=False, max_length=4)
    count = models.IntegerField(default=0)

Обратите внимание, что мы не вызываем функцию. Мы только передаем ссылку на функцию.

При этом, возможно, было бы лучше использовать Django s UUIDField [Django -doc] . Это сделано для хранения и генерации случайных UUID, которые, вероятно, являются лучшими источниками случайных строк.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...