Eugene S.
Eugene S.

Reputation: 51

Django. Non-ascii field doesn't create slug. I expect to get transliteration, but getting an empty field and error

I have simple Model with title and slug fields. I want to accept non-Latin characters as a title and transliterate them into Latin slug. Specifically, I want to transliterate Cyrillic characters, say 'Привет, мир!' into Latin 'privet-mir' slug. Instead of slug I'm getting following error:

NoReverseMatch at /blog/

Reverse for 'blog_detail' with arguments '('',)' not found. 1 pattern(s) tried: ['blog/(?P[-a-zA-Z0-9_]+)/$']

Django Version: 3.1.5
Python Version: 3.9.1
Exception Type: NoReverseMatch
Exception Value:    

Reverse for 'blog_detail' with arguments '('',)' not found. 1 pattern(s) tried: ['blog/(?P<slug>[-a-zA-Z0-9_]+)/$']

Model

from django.db import models 
from django.template.defaultfilters import slugify


class Post(models.Model):
    title = models.CharField(max_length=70)
    slug = models.SlugField(null=False, unique=True, allow_unicode=True)

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

    def __str__(self):
        return self.title

admin.py

from django.contrib import admin
from .models import Post


class PostAdmin(admin.ModelAdmin):
    prepopulated_fields = {'slug': ('title',)}

admin.site.register(Post, PostAdmin)

urls.py

from django.urls import path
from . import views

    app_name = 'blog'
    urlpatterns = [
        path('', views.BlogList.as_view(
            template_name=app_name + "/blog_list.html"), name='blog_list'),
        path('<slug:slug>/', views.BlogDetail.as_view(
            template_name=app_name + "/blog_detail.html"), name='blog_detail'),
    ]

views.py

from .models import Post
from django.views.generic import ListView, DetailView

class BlogList(ListView):
    model = Post

class BlogDetail(DetailView):
    model = Post

blog_list.html (for each post)

<a href="{% url 'blog:blog_detail' post.slug %}">{{ post.title }}</a>

blog_detail.html (short)

<h1>{{ post.title }}</h1>

Upvotes: 3

Views: 831

Answers (1)

Eugene S.
Eugene S.

Reputation: 51

I found the solution!

Thanks to KenWhitesell https://forum.djangoproject.com/t/django-slugify-error/6153/4 and Evgeny https://stackoverflow.com/a/4036665/15109119

It is also possible to use javascript, for example, as is used to auto populate the slug-field in the Django admin panel. It needs to use 'allow_unicode=True' while actually 'slugifying' the field.

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

Upvotes: 2

Related Questions