【问题标题】:Django - Generating random, unique slug field for each model objectDjango - 为每个模型对象生成随机的、唯一的 slug 字段
【发布时间】:2017-07-14 17:51:09
【问题描述】:

我在 Django 中有一个名为 ExampleModel 的模型,并且希望每个模型对象都能被唯一标识。不过,我不希望用户在 URL 中看到对象的 ID;因此,出于这个原因,我希望对象slug 是一个唯一的、随机生成的具有 8 位数字的整数,它将进入视图 URL。这与我见过的其他问题不同,因为这意味着不会生成基于模型对象名称//内容本身的 slug 字符串。

模型.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)

【问题讨论】:

  • 我会使用散列函数为标题生成散列并将其用作 slug。

标签: python django slug


【解决方案1】:

Django 有一个内置的get_random_string 函数,可以生成您的 slug 所需的随机字符串。

正如 Sebastian Wozny 所提到的,您希望在覆盖 save 方法时调用它。基础是:

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

这不是实际的工作代码。更详细地说,真正的 models.py 如下所示。请注意,我并没有将自己限制在数字上,而且我正在检查 unqueness 并确保它不会拼写错误:

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】:

    覆盖保存:

    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)
    

    这可能需要更多针对IntegrityErrors 的保护措施。 如果你能忍受两次保存:

    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。我会错过什么吗?
    • 你能用你的保存方法显示models.py的内容吗(准确的内容)
    • 有一个错误,缺少 str,它不可能工作。您还没有使用代码。
    • 在我的保存方法中添加了编辑 2 中的模型。
    • 道歉我把你的代码放在我的views.py而不是models.py中。一旦我把它放在 models.py 中,当我尝试保存表单时它会给我一个错误。成为TypeError at /dashboard/campaign/new/ super() takes at least 1 argument (0 given)
    【解决方案3】:

    如果你重写了 save 方法,每次对象更新 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()
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-05-25
      • 2011-06-06
      • 2020-06-02
      • 1970-01-01
      • 2018-06-25
      • 2013-05-31
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多