Генерация непоследовательного ID / PK для модели Django

Я думаю, что ваши два примера на самом деле только один: free() должен появиться только в конце процесса, который, как вы указываете, бесполезен, так как процесс завершается.

В вас второй пример, однако, единственное различие заключается в том, что вы разрешаете неопределенное число malloc(), что может привести к нехватке памяти. Единственный способ справиться с ситуацией - проверить код возврата malloc() и действовать соответственно.

29
задан Oli 21 September 2010 в 09:37
поделиться

7 ответов

Вот что я в итоге сделал. Я сделал абстрактную модель. Мой вариант использования для этого требует нескольких моделей, которые генерируют свои собственные, случайные слизни.

Слизень выглядит как AA##AA, так что это 52x52x10x10x52x52 = 731,161,600 комбинаций. Вероятно, в тысячу раз больше, чем мне нужно, и если это когда-нибудь станет проблемой, я могу добавить письмо в 52 раза больше комбинаций.

Использование аргумента default не приведет к его сокращению, поскольку абстрактная модель должна проверять наличие столкновений слагов на дочернем элементе. Наследование было самым простым, возможно, единственным способом сделать это.

from django.db import models
from django.contrib.auth.models import User

import string, random

class SluggedModel(models.Model):
    slug = models.SlugField(primary_key=True, unique=True, editable=False, blank=True)

    def save(self, *args, **kwargs):
        while not self.slug:
            newslug = ''.join([
                random.sample(string.letters, 2),
                random.sample(string.digits, 2),
                random.sample(string.letters, 2),
            ])

            if not self.objects.filter(pk=newslug).exists():
                self.slug = newslug

        super().save(*args, **kwargs)

    class Meta:
        abstract = True
8
ответ дан Oli 21 September 2010 в 09:37
поделиться
  • 1
    Это, вероятно, isn' t самая большая идея, потому что изменения в местных жителях () являются not' t гарантировал, что был отражен в среде. – Paul Fisher 17 July 2009 в 22:00
  • 2
    Это, вероятно, isn' t самая большая идея, потому что изменения в местных жителях () являются not' t гарантировал, что был отражен в среде. – Paul Fisher 17 July 2009 в 22:00
  • 3
    Это, вероятно, isn' t самая большая идея, потому что изменения в местных жителях () являются not' t гарантировал, что был отражен в среде. – Paul Fisher 17 July 2009 в 22:00
  • 4
    Это, вероятно, isn' t самая большая идея, потому что изменения в местных жителях () являются not' t гарантировал, что был отражен в среде. – Paul Fisher 17 July 2009 в 22:00
  • 5
    Это, вероятно, isn' t самая большая идея, потому что изменения в местных жителях () являются not' t гарантировал, что был отражен в среде. – Paul Fisher 17 July 2009 в 22:00

Есть встроенный в Django способ достичь того, чего вы хотите. Добавьте поле к модели «пользовательской страницы» с именем primary_key=True и default= функции генерации ключа, например:

class CustomPage(models.Model):
    ...
    mykey = models.CharField(max_length=6, primary_key=True, default=pkgen)
    ...

Теперь для каждого экземпляра модели page, page.pk становится псевдонимом для page.mykey, который автоматически присваивается строке, возвращаемой вашей функцией pkgen() в момент создания этого экземпляра.
Быстрая и грязная реализация:

def pkgen():
    from base64 import b32encode
    from hashlib import sha1
    from random import random
    rude = ('lol',)
    bad_pk = True
    while bad_pk:
        pk = b32encode(sha1(str(random())).digest()).lower()[:6]
        bad_pk = False
        for rw in rude:
            if pk.find(rw) >= 0: bad_pk = True
    return pk

Вероятность того, что две страницы получат идентичные первичные ключи, очень мала (при условии, что random() является достаточно случайной), и нет проблем параллелизма. И, конечно же, этот метод легко расширяем, выделяя больше символов из кодированной строки.

22
ответ дан atomizer 21 September 2010 в 09:37
поделиться
  • 1
    Кроме того, Вы can' t передача b в другие функции этот путь. – ephemient 17 July 2009 в 22:37
  • 2
    Кроме того, Вы can' t передача b в другие функции этот путь. – ephemient 17 July 2009 в 22:37
  • 3
    Кроме того, Вы can' t передача b в другие функции этот путь. – ephemient 17 July 2009 в 22:37
  • 4
    Кроме того, Вы can' t передача b в другие функции этот путь. – ephemient 17 July 2009 в 22:37
  • 5
    Кроме того, Вы can' t передача b в другие функции этот путь. – ephemient 17 July 2009 в 22:37

Может быть, вам нужно взглянуть на Python UUID , он может генерировать случайные длинные символы. Но вы можете нарезать его и использовать нужное количество символов с небольшой проверкой, чтобы убедиться, что он уникален даже после нарезки.

Фрагмент UUIDField может помочь вам, если вы не хотите сами создавать UUID.

Также посмотрите это сообщение в блоге

4
ответ дан Srikanth Chundi 21 September 2010 в 09:37
поделиться
  • 1
    That' s не указатель тогда, а псевдоним, где Вы указываете на одно имя к другому имени. Вы can' t делают это в Python, как that' s абсолютно ненужный. В Python Вы просто назвали бы его " a" все время. Никакие псевдонимы не необходимы. – Lennart Regebro 17 July 2009 в 21:51
  • 2
    That' s не указатель тогда, а псевдоним, где Вы указываете на одно имя к другому имени. Вы can' t делают это в Python, как that' s абсолютно ненужный. В Python Вы просто назвали бы его " a" все время. Никакие псевдонимы не необходимы. – Lennart Regebro 17 July 2009 в 21:51
  • 3
    That' s не указатель тогда, а псевдоним, где Вы указываете на одно имя к другому имени. Вы can' t делают это в Python, как that' s абсолютно ненужный. В Python Вы просто назвали бы его " a" все время. Никакие псевдонимы не необходимы. – Lennart Regebro 17 July 2009 в 21:51
  • 4
    That' s не указатель тогда, а псевдоним, где Вы указываете на одно имя к другому имени. Вы can' t делают это в Python, как that' s абсолютно ненужный. В Python Вы просто назвали бы его " a" все время. Никакие псевдонимы не необходимы. – Lennart Regebro 17 July 2009 в 21:51
  • 5
    That' s не указатель тогда, а псевдоним, где Вы указываете на одно имя к другому имени. Вы can' t делают это в Python, как that' s абсолютно ненужный. В Python Вы просто назвали бы его " a" все время. Никакие псевдонимы не необходимы. – Lennart Regebro 17 July 2009 в 21:51

Django теперь включает тип UUIDField , так что вам не нужен какой-либо пользовательский код или внешний пакет, предложенный Срикант Чунди. В этой реализации используются строки HEX с черточками, поэтому текст довольно безопасный для детей, кроме 1337 выражений, таких как abad1d3a:)

Вы можете использовать его как псевдоним pk для поля uuid в качестве первичный ключ:

import uuid
from django.db import models

class MyModel(models.Model):
    uuid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    # other fields

Обратите внимание, однако, что при маршрутизации к этому представлению в urls.py вам необходимо другое регулярное выражение, как , упомянутое здесь Например:

urlpatterns = [
    url(r'mymodel/(?P<pk>[^/]+)/, MyModelDetailView.as_view(),
        name='mymodel'),
]
3
ответ дан Community 21 September 2010 в 09:37
поделиться
  • 1
    Спасибо за ответ. То, что касается меня, является последней строкой Вашего ответа. Для корректной семантики на моем старом языке I' d должны должными быть теперь распечатать 2 как на старом языке it' s указатель на a. – chollida 17 July 2009 в 21:40
  • 2
    Спасибо за ответ. То, что касается меня, является последней строкой Вашего ответа. Для корректной семантики на моем старом языке I' d должны должными быть теперь распечатать 2 как на старом языке it' s указатель на a. – chollida 17 July 2009 в 21:40
  • 3
    Спасибо за ответ. То, что касается меня, является последней строкой Вашего ответа. Для корректной семантики на моем старом языке I' d должны должными быть теперь распечатать 2 как на старом языке it' s указатель на a. – chollida 17 July 2009 в 21:40
  • 4
    Спасибо за ответ. То, что касается меня, является последней строкой Вашего ответа. Для корректной семантики на моем старом языке I' d должны должными быть теперь распечатать 2 как на старом языке it' s указатель на a. – chollida 17 July 2009 в 21:40
  • 5
    Спасибо за ответ. То, что касается меня, является последней строкой Вашего ответа. Для корректной семантики на моем старом языке I' d должны должными быть теперь распечатать 2 как на старом языке it' s указатель на a. – chollida 17 July 2009 в 21:40

Оли: Если вы беспокоитесь о том, чтобы произносить грубые слова, вы всегда можете сравнить / найти их в UUIDField, используя фильтр ненормативной лексики django, и пропустить все UUID, которые могут быть триггерами.

1
ответ дан Elf Sternberg 21 September 2010 в 09:37
поделиться

Это то, что я в итоге использовал UUID.

import uuid 

from django.db import models
from django.contrib.auth.models import User


class SluggedModel(models.Model):
    slug = models.SlugField(primary_key=True, unique=True, editable=False, blank=True)

    def save(self, *args, **kwargs):
        if not self.slug:
            uuid.uuid4().hex[:16]    # can vary up to 32 chars in length
        super(SluggedModel, self).save(*args, **kwargs)

    class Meta:
        abstract = True
1
ответ дан All Іѕ Vаиітy 21 September 2010 в 09:37
поделиться

Глядя на приведенные выше ответы, вот что я использую сейчас.

import uuid

from django.db import models
from django.utils.http import int_to_base36


ID_LENGTH = 9


def id_gen() -> str:
    """Generates random string whose length is `ID_LENGTH`"""
    return int_to_base36(uuid.uuid4().int)[:ID_LENGTH]


class BaseModel(models.Model):
    """Django abstract model whose primary key is a random string"""
    id = models.CharField(max_length=ID_LENGTH, primary_key=True, default=id_gen, editable=False)

    class Meta:
        abstract = True


class CustomPage(BaseModel):
    ...
1
ответ дан Nour Wolf 21 September 2010 в 09:37
поделиться
Другие вопросы по тегам:

Похожие вопросы: