Home > Mobile >  Django: how to create slugs in django?
Django: how to create slugs in django?

Time:07-12

i want to create a slug in django, i have used the slug = models.SlugField(unique=True). Now when i create a post with a slug of learning-to-code it works, but if i create another post with the same slug learning-to-code, it shows an error like Unique Constraint Failed. But i want to create posts with the same slug, is there a way to make slugs unique only to the time a post was created?

this is how my model looks

class Article(models.Model):
    title = models.CharField(max_length=200)
    description = models.TextField(blank=True, null=True)
    slug = models.SlugField(unique=True)
    user = models.ForeignKey('userauths.User', on_delete=models.SET_NULL, null=True)

How can i go about achieving this?

CodePudding user response:

If you just like to convert the title into a slug but do not want it as an alternative to the oprimary key, you could use the slugify utility of django to convert the title on save and store it in a generic CharField.

https://docs.djangoproject.com/en/4.0/ref/utils/#django.utils.text.slugify

from django.utils.text import slugify

class Article(models.Model):
    title = models.CharField(max_length=200)
    description = models.TextField(blank=True, null=True)
    slug = models.CharField(max_length=300)
    user = models.ForeignKey('userauths.User', on_delete=models.SET_NULL, null=True)

    def save(self, *args, **kwargs):
        self.slug = slugify(self.title)
        return super().save(*args, **kwargs)

CodePudding user response:

you can use save to check slug before add like:

from django.utils.text import slugify


def save(self, *args, **kwargs):
    if self._state.adding:
        self._generate_slug()
    super(Article, self).save(*args, **kwargs)

def _generate_slug(self):
    if self.slug:
        slug_candidate = slug_original = self.slug
    else:
        # To Generate New Slug If None, You can change
        slug_candidate = slug_original = slugify(self.title, allow_unicode=True)
        if not slug_candidate:
            slug_candidate = slug_original = lambda: random.randint(1, 10000000)
    # Check if Slug exists and add ( learning-to-code-1, learning-to-code-2,................)
    for i in itertools.count(1):
        if not Article.objects.filter(slug=slug_candidate).exists():
            break
        slug_candidate = '{}-{}'.format(slug_original, i)

    self.slug = slug_candidate

CodePudding user response:

Creating posts with the same slug makes not much sense, since a slug is used to determine what Article is used. If two items have learning-to-code, then you can not determine which of the two Articles is the right one.

If your Article for example has a DateField, you can use this such that is works with both the date and the slug to determine the Article. The easist way to achieve that is likely with the django-autoslug package [PyPi]. This will work with a UniqueConstraint [Django-doc], such that the combination of the date and the slug is unique, so:

from autoslug import AutoSlugField
from django.conf import settings

class Article(models.Model):
    title = models.CharField(max_length=200)
    slug = AutoSlugField(populate_from='title', unique_with=['publish_date'])
    description = models.TextField(blank=True, null=True)
    user = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.SET_NULL,
        null=True
    )
    publish_date = models.DateField(auto_now_add=True)

The urls.py will need to add specifications for the date, so:

path('<int:year>/<int:month>/<int:date>/<slug:slug>', some_view, name='article_detail')

then in a DetailView, or other views, we can filter on the QuerySet with the date:

from datetime import date
from django.views.generic import DetailView

class ArticleDetailView(DetailView):
    model = Article
    
    def get_queryset(self, *args, **kwargs):
        return super().get_queryset(*args, **kwargs).filter(
            publish_date=date(self.kwargs['year'], self.kwargs['month'], self.kwargs['day'])
        )

Note: It is normally better to make use of the settings.AUTH_USER_MODEL [Django-doc] to refer to the user model, than to use the User model [Django-doc] directly. For more information you can see the referencing the User model section of the documentation.

  • Related