简体   繁体   English

Django:使用True True来增加Slug的大小

[英]Django: Increasing the size of Slug with Unique True

I need to increase size of my slug to 500 which by default is 255 characters but same time I need to keep it unique as well. 我需要将子弹的大小增加到500,默认情况下为255个字符,但同时我也需要保持其唯一性。 Is there a way around to make it happen? 有没有办法做到这一点?

models.py models.py

class Product(models.Model):
    title = models.CharField(max_length=500)
    description = models.TextField(blank=True, null=True)
    price = models.DecimalField(max_digits=20, decimal_places=2)
    sku = models.CharField(null=True, max_length=100)
    url = models.URLField(blank=True)
    slug = models.SlugField(unique=True)

Please advise. 请指教。

According to the documentation the maximum length for a SlugField is 255 characters. 根据文档SlugField的最大长度为255个字符。 But it is the database backend that enforces it so, depending on which backend you are using, you might be able to increase that. 但是数据库后端强制执行此操作,因此,根据您使用的后端,您也许可以增加它。

SQLite and PostgreSQL both allow max_length to be set to 500 with a UNIQUE constraint. SQLite和PostgreSQL都允许使用UNIQUE约束将max_length设置为500。 Note that PostgreSQL will actually enforce the length limit, whereas SQLite doesn't really care and will allow you to insert strings greater than the declared size. 请注意,PostgreSQL实际上会强制执行长度限制,而SQLite并不在乎,它允许您插入大于声明大小的字符串。

But the MySQL/Mariadb driver will enforce the 255 character limit in django/db/backends/mysql/validation.py . 但是MySQL / Mariadb驱动程序将在django/db/backends/mysql/validation.py强制使用255个字符的限制。 Within the standard backends, this is the only one that has this restriction. 在标准后端中,这是唯一具有此限制的后端。 The 255 comes from the restriction that the maximum index key for a InnoDB column is 767 bytes. 255来自InnoDB列的最大索引键为767个字节的限制。 If you store UTF8 data in the column, as you must, it can take up to 3 bytes per character, which results in 767/3 = 255 characters. 如果必须将UTF8数据存储在该列中,则每个字符最多可占用3个字节,这将导致767/3 = 255个字符。

One possible solution is to have an additional CharField containing a hash of the slug. 一种可能的解决方案是使用一个额外的CharField其中包含该段的哈希值。 That field will be short (eg 32 bytes for MD5 digest) and it will be unique which will stop duplicate slugs being inserted. 该字段将很短(例如,用于MD5摘要的32个字节) 并且它将是唯一的,这将阻止插入重复的段。 Population of the slug and its hash can be done in Product.save() . 块的填充及其哈希可以在Product.save()

The model will be: 该模型将是:

import hashlib
from django.utils.text import slugify

class Product(models.Model):
    title = models.CharField(max_length=500)
    description = models.TextField(blank=True, null=True)
    price = models.DecimalField(max_digits=20, decimal_places=2)
    sku = models.CharField(null=True, max_length=100)
    url = models.URLField(blank=True)
    slug = models.SlugField(max_length=500)
    slug_hash = models.CharField(max_length=32, unique=True)

    def save(self, *args, **kwargs):
        self.slug = slugify(self.title)
        self.slug_hash = hashlib.md5(self.slug).hexdigest()
        super(Product, self).save(*args, **kwargs)

Now if an attempt to save a record with the same slug is attempted an IntegrityError on the slug_hash will be raised. 现在,如果尝试使用相同的段名来保存记录,则会在slug_hash上引发IntegrityError

Yes, it's possible using signals. 是的,可以使用信号。 The slug field will automatically get created/updated before saving the instance of the model. 在保存模型实例之前,slug字段将自动创建/更新。 To make it unique you can concatenate the title with the id if a model instance with same slug already exists. 为了使其具有唯一性,如果已经存在具有相同子弹的模型实例,则可以将标题与id串联在一起。 See code bellow (add it to your model) : 参见下面的代码(将其添加到模型中):

def create_slug(instance, new_slug=None):
    """
    A function to create a slug
    if an object with slug already exists, it adds id value to slug
    else  just slugify the title
    """
    slug = slugify(instance.title)
    if new_slug is not None:
        slug = new_slug
    qs = Product.objects.filter(slug=slug).order_by('-id')
    exists = qs.exists()
    if exists:
        new_slug = "%s-%s" %(slug, qs.first().id)
        return create_slug(instance, new_slug=new_slug) #recursive call 
    return slug

def pre_save_product_receiver(sender, instance, *args, **kwargs):
    """
    A signal that calls the function create_slug if an object has not slug 
    """
    if not instance.slug:
        instance.slug = create_slug(instance)

pre_save.connect(pre_save_product_receiver, sender=Product)

To increase slug max characters replace your field with this : 要增加子弹头最大字符数,请用以下代码替换您的字段:

slug = models.SlugField(max_length = 255, unique=True)

Don't go over 255 to avoid trouble in case you change your database technology. 如果更改数据库技术,请不要超过255,以免造成麻烦。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM