Django - 为每个模型对象生成随机、唯一的 slug 字段
Django - Generating random, unique slug field for each model object
我在 Django 中有一个名为 ExampleModel
的模型,并希望每个模型对象都被唯一标识。虽然,我不希望 URL 中的用户可以看到对象的 ID;因此,出于这个原因,我希望对象 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 的值为空,因此我不必为所有当前 ExampleModel
对象设置默认 slug。
这是可以理解的相当模糊的内容,但是我还没有找到任何 guides/tutorials 可能适合我的具体情况。
感谢 help/guidance 提供
编辑
这是我的 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)
覆盖保存:
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)
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)
如果您重写保存方法,每次对象更新时 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()
我在 Django 中有一个名为 ExampleModel
的模型,并希望每个模型对象都被唯一标识。虽然,我不希望 URL 中的用户可以看到对象的 ID;因此,出于这个原因,我希望对象 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 的值为空,因此我不必为所有当前 ExampleModel
对象设置默认 slug。
这是可以理解的相当模糊的内容,但是我还没有找到任何 guides/tutorials 可能适合我的具体情况。
感谢 help/guidance 提供
编辑 这是我的 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)
覆盖保存:
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)
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)
如果您重写保存方法,每次对象更新时 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()