Django - 为每个模型对象生成随机且唯一的短标识字段

5
我在Django中有一个名为ExampleModel的模型,希望每个模型对象都具有唯一标识。然而,我不希望对象的ID在URL中对用户可见;因此,我希望对象的slug是一个唯一的、随机生成的8位整数,将出现在视图URL中。这与其他类似问题不同,因为这意味着不会根据模型对象的名称/内容本身产生slug字符串。
Models.py:
class ExampleModel(models.Model):
    user = models.ForeignKey(UserModel, related_name='examplemodel', on_delete=models.CASCADE, null=True)
    title = models.CharField(max_length=50, verbose_name='Title')
    slug = models.SlugField(unique=True, blank=True, null=True)

目前slug的值是null,所以我不需要为所有当前的ExampleModel对象设置默认的slug。

可以理解这是相当模糊的,然而我还没有找到任何可以适用于我的确切情况的指南/教程。

感谢提供任何帮助/指导。

编辑 这是我的views.py文件:

def model_create(request):
    user=request.user.id
    if request.user.is_authenticated:
        try:
            example = request.user.examplemodel
        except ExampleProfile.DoesNotExist:
            example = ExampleProfile(user)
        if request.method == 'POST':
            form = NewForm(request.POST, request.FILES)
            if form.is_valid():
                form.save()
                return redirect('/dashboard/')
            else:
                return render(request, 'create.html', {'form': form})
        else:
            form = NewForm()
            return render(request, 'create.html', {'form': form})
    else:
        return redirect('/users/login/?next=')

编辑 2 Models.py(保存方法):

def save(self, *args, **kwargs):
        if self.user is None:  # Set default reference
            self.user = UserModel.objects.get(id=1)
        super(ExampleModel, self).save(*args, **kwargs)

我会使用哈希函数为标题生成哈希,并将其用作短标识。 - Bishal
3个回答

13

Django内置了一个get_random_string函数,可以生成需要用于slug的随机字符串。

正如Sebastian Wozny所提到的,您需要在覆盖保存方法时调用此函数。基本步骤如下:

from django.utils.crypto import get_random_string
# ...
the_slug = get_random_string(8,'0123456789') # 8 characters, only digits. 

那不是真正的工作代码。更详细地说,一个真正的 models.py 文件看起来像下面这样。请注意,我没有限制自己只使用数字,并且我正在进行检查以确保它既唯一又不会拼错任何东西:

from django.db import models
from django.utils.crypto import get_random_string
# ...
class SomeModelWithSlug(models.Model):
  slug = models.SlugField(max_length=5,blank=True,) # blank if it needs to be migrated to a model that didn't already have this 
  # ...
  def save(self, *args, **kwargs):
    """ Add Slug creating/checking to save method. """
    slug_save(self) # call slug_save, listed below
    Super(SomeModelWithSlug, self).save(*args, **kwargs)
# ...
def slug_save(obj):
""" A function to generate a 5 character slug and see if it has been used and contains naughty words."""
  if not obj.slug: # if there isn't a slug
    obj.slug = get_random_string(5) # create one
    slug_is_wrong = True  
    while slug_is_wrong: # keep checking until we have a valid slug
        slug_is_wrong = False
        other_objs_with_slug = type(obj).objects.filter(slug=obj.slug)
        if len(other_objs_with_slug) > 0:
            # if any other objects have current slug
            slug_is_wrong = True
        naughty_words = list_of_swear_words_brand_names_etc
        if obj.slug in naughty_words:
            slug_is_wrong = True
        if slug_is_wrong:
            # create another slug and check it again
            obj.slug = get_random_string(5)

2
如果你重写了保存方法,那么每次对象更新时slug都会改变。如果你不想让它这样做,可以像下面这样只设置一次slug:
def slug_generator():
    return ''.join(random.choices(string.ascii_lowercase + string.digits + string.ascii_uppercase, k=20))

def save(self, *args, **kwargs):
    if not self.slug:
        self.slug = slug_generator()
        super(Item, self).save()
    super(Item, self).save()

1
覆盖保存:
def save(self, *args, **kwargs):
    try:
        self.slug = ''.join(str(random.randint(0, 9)) for _ in range(8))
        super().save(*args, **kwargs)
    except IntegrityError:
        self.save(*args, **kwargs)

这可能需要更多的保护措施来防止IntegrityError。如果您可以接受两次保存:
def save(self, *args, **kwargs):
    super().save(*args, **kwargs)
    try:
        self.slug = ''.join(str(random.randint(0, 9)) for _ in range(8))
        super().save(*args, **kwargs)
    except IntegrityError:
        self.save(*args, **kwargs)

这不会返回任何错误,并且当我提交表单时对象成功保存,但是在管理页面查看对象时似乎没有生成随机的 slug。我可能错过了什么吗? - jayt
你能展示一下 models.py 文件中的 save 方法吗?(包括具体内容) - Sebastian Wozny
有一个错误,缺少了 str,它不可能正常工作。你还没有使用这段代码。 - Sebastian Wozny
在Edit 2中为我的模型添加了save方法。 - jayt
抱歉,我把你的代码放在了我的views.py文件中而不是models.py文件中。一旦我把它放到models.py中,当我尝试保存表单时就会出现错误。错误信息为 TypeError at /dashboard/campaign/new/ super() takes at least 1 argument (0 given) - jayt
让我们在聊天中继续这个讨论 - jayt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接