4

I want Django to automatically create slug for this model:

class News(models.Model):
    title = models.CharField(max_length=100)
    body = models.TextField()
    teaser = models.TextField('teaser', blank=True)
    created=models.DateTimeField(auto_now_add=True)
    pub_date=models.DateTimeField(default=datetime.datetime.now)
    categories = models.ManyToManyField(Category, blank=True)
    likes = models.IntegerField(default=0)
    visits = models.IntegerField(default=0)
    slug = models.CharField(max_length=100, unique=True) 

    def __unicode__(self):
        return unicode(self.title)

    def save(self, *args, **kwargs):
        self.title = slugify_unicode(self.title)
        super(News, self).save(*args, **kwargs)

I used CharField instead of slugfield because Slug fields can only contain ASCII letters, numbers, dashses and underlines but I want to create slugs based on Persian titles.

my views.py has this function to create news items:

@staff_member_required
def add_news(request):
    if request.method == 'POST':
        form = NewsForm(request.POST)
        if form.is_valid():
            form.save()
            return HttpResponseRedirect('/all_news')

    if request.method == 'GET':
        form = NewsForm()
        args = {}
        args.update(csrf(request))
        args['form'] = form
        return render_to_response('news/add_news.html', args)  

This works fine when I create Persian slugs manually but this is really cumbersome. so I am wondering if there is a way to make Django to create the slug based on the title at save time.

so for example, when the title is:

'یک خبر مهم'

I want to automatically create 'یک-خبر-مهم' as the slug.

Community
  • 1
  • 1
qliq
  • 11,695
  • 15
  • 54
  • 66
  • Slugs have to be ASCII, so it would be prove hard to make it accept utf-8 chars. There's probably a better solution, can you explain the use-case a tad more specifically? What are you going to do with the slugs, why would you need it to be a slug at all, etc. – yuvi Feb 01 '14 at 17:59
  • Well, I am trying to implement 'Clean URLs'. SEO-wise it is better to have a url like mydomain.com/some-important-news than, mydomain.com/545454 – qliq Feb 01 '14 at 18:05
  • Well, why not go with the SO method of using both? `mydomain.com/545454/my-article-title`. Remember that titles can change, it makes a lot more sense to use a surrogate non-buisness-meaningfull key as your address, and add the title as a neat way to show your URL. You can create a method to just replace the spaces with `"-"` and create your own validation to avoid special tokens that will cause problems – yuvi Feb 01 '14 at 18:11
  • yuvi, SO style urls would also be great, but I have not ventured (yet) to create the method that you're suggesting. – qliq Feb 01 '14 at 18:14
  • I'm confused. What "module" do you mean? Just use the model's automatically created primary key. No further configuration required – yuvi Feb 01 '14 at 18:15
  • sorry, by 'method', I mean python code to create a proper dashed string out of title to append the primary key for the URL. But there are some complications to account for not only replacing spaces but also other possible inputs like conjunctions words (like'و'), symbols, etc in the title. – qliq Feb 01 '14 at 18:28

3 Answers3

7

The new option which is being introduced in django version 1.9 is SlugField.allow_unicode

If True, the field accepts Unicode letters in addition to ASCII letters. Defaults to False. doc

For example:

In models.py file, define the slug column like below:

slug = models.SlugField(allow_unicode=True)
Mojtaba Yousefi
  • 626
  • 1
  • 9
  • 27
1

Slugs need to be ASCII, so they can be safely used in URLs.

Please have a look at django-autoslug.

It will try to transliterate the title for you.

>>> import unidecode
>>> unidecode.unidecode(u'و')
'w'
>>> unidecode.unidecode(u'風')
'Feng '
Krzysztof Szularz
  • 5,151
  • 24
  • 35
  • I know that slug does not allow non-ascii. Please have a look at my question. I've updated with an example of what I want to acheive. – qliq Feb 01 '14 at 18:50
  • Frankly I don't get you. Do you want to use `یک-خبر-مهم` in the URL? Then `'-'.join(title.lower().split(' '))` is your slug function. – Krzysztof Szularz Feb 01 '14 at 18:54
  • alright, how to fill the slug field with this slug function when the views 'add_news' saves the form? – qliq Feb 01 '14 at 19:05
  • 2
    You don't need to apply it when you save the form at all. Just use it as a model method and call it when needed – yuvi Feb 01 '14 at 19:06
  • @yuvi not sure how to create the model method. a django noob is here! – qliq Feb 01 '14 at 19:09
  • Just like you would with a normal class in python. `def mymethod(self):` within the model class and call it with `instance.mymethod()` – yuvi Feb 01 '14 at 19:10
  • 1
    Or read about classes in python: http://docs.python.org/2/tutorial/classes.html#method-objects – Krzysztof Szularz Feb 01 '14 at 19:12
  • I'm sorry if you find this puzzling, but we're talking about things which require a very basic understanding of the python language. You need to know this stuff to be able to work with python (and by extention, django). copy-pasting an example is not what you are looking for, trust me. Go to that link and give it a try. – yuvi Feb 01 '14 at 19:47
  • This is not true nowadays. RFC 3986 was published in 2005 and since then it is possible to use non-ASCII characters in URLs without ambiguities. – Pablo Castellano Dec 05 '20 at 19:06
  • @PabloCastellano only because it's possible doesn't mean you should do that. Internet is a weird place and a mix of old, new and bugs. You'll be better off with ascii slugs. – Krzysztof Szularz Dec 06 '20 at 01:18
0

Simply replacing

self.title = slugify_unicode(self.title)

in def save(self... method of News with

    self.slug = slugify_unicode(self.title)

solved the problem.

qliq
  • 11,695
  • 15
  • 54
  • 66
  • This is a bad idea. You're keeping irrelevant duplicated data in your database, instead of calculating it dynamically – yuvi Feb 01 '14 at 19:49
  • nothing is duplicated. title and slug are different strings. Also note that calculating slug dynamically comes with a cost which is not desirable when you build to scale. – qliq Feb 01 '14 at 20:24
  • One is a calculation based on the other, so it **is** a duplication. The efficiency cost is negligible, especially compared with the negative effects of having a wasteful column in your table – yuvi Feb 01 '14 at 20:35