Sign In Start Free Trial
Account

Add to playlist

Create a Playlist

Modal Close icon
You need to login to use this feature.
  • Django 3 Web Development Cookbook
  • Toc
  • feedback
Django 3 Web Development Cookbook

Django 3 Web Development Cookbook

By : Aidas Bendoraitis, Jake Kronika
3.6 (9)
close
Django 3 Web Development Cookbook

Django 3 Web Development Cookbook

3.6 (9)
By: Aidas Bendoraitis, Jake Kronika

Overview of this book

Django is a web framework for perfectionists with deadlines, designed to help you build manageable medium and large web projects in a short time span. This fourth edition of the Django Web Development Cookbook is updated with Django 3's latest features to guide you effectively through the development process. This Django book starts by helping you create a virtual environment and project structure for building Python web apps. You'll learn how to build models, views, forms, and templates for your web apps and then integrate JavaScript in your Django apps to add more features. As you advance, you'll create responsive multilingual websites, ready to be shared on social networks. The book will take you through uploading and processing images, rendering data in HTML5, PDF, and Excel, using and creating APIs, and navigating different data types in Django. You'll become well-versed in security best practices and caching techniques to enhance your website's security and speed. This edition not only helps you work with the PostgreSQL database but also the MySQL database. You'll also discover advanced recipes for using Django with Docker and Ansible in development, staging, and production environments. By the end of this book, you will have become proficient in using Django's powerful features and will be equipped to create robust websites.
Table of Contents (15 chapters)
close

Handling multilingual fields

Django uses the internationalization mechanism to translate verbose strings in the code and templates. But it's up to the developer to decide how to implement the multilingual content in the models. We'll show you a couple of ways for how to implement multilingual models directly in your project. The first approach will be using language-specific fields in your model.

This approach has the following features:

  • It is straightforward to define multilingual fields in the model.
  • It is simple to use the multilingual fields in database queries.
  • You can use contributed administration to edit models with the multilingual fields, without additional modifications.
  • If you need to, you can effortlessly show all of the translations of an object in the same template.
  • After changing the amount of languages in the settings, you will need to create and run migrations for all multilingual models.

Getting ready

Have you created the myproject.apps.core package used in the preceding recipes of this chapter? You will now need a new model_fields.py file within the core app, for the custom model fields.

How to do it...

Execute the following steps to define the multilingual character field and multilingual text field:

  1. Open the model_fields.py file, and create the base multilingual field, as follows:
# myproject/apps/core/model_fields.py
from django.conf import settings
from django.db import models
from django.utils.translation import get_language
from django.utils import translation

class MultilingualField(models.Field):
SUPPORTED_FIELD_TYPES = [models.CharField, models.TextField]

def __init__(self, verbose_name=None, **kwargs):
self.localized_field_model = None
for model in MultilingualField.SUPPORTED_FIELD_TYPES:
if issubclass(self.__class__, model):
self.localized_field_model = model
self._blank = kwargs.get("blank", False)
self._editable = kwargs.get("editable", True)
super().__init__(verbose_name, **kwargs)

@staticmethod
def localized_field_name(name, lang_code):
lang_code_safe = lang_code.replace("-", "_")
return f"{name}_{lang_code_safe}"

def get_localized_field(self, lang_code, lang_name):
_blank = (self._blank
if lang_code == settings.LANGUAGE_CODE
else True)
localized_field = self.localized_field_model(
f"{self.verbose_name} ({lang_name})",
name=self.name,
primary_key=self.primary_key,
max_length=self.max_length,
unique=self.unique,
blank=_blank,
null=False, # we ignore the null argument!
db_index=self.db_index,
default=self.default or "",
editable=self._editable,
serialize=self.serialize,
choices=self.choices,
help_text=self.help_text,
db_column=None,
db_tablespace=self.db_tablespace)
return localized_field

def contribute_to_class(self, cls, name,
private_only=False,
virtual_only=False):
def translated_value(self):
language = get_language()
val = self.__dict__.get(
MultilingualField.localized_field_name(
name, language))
if not val:
val = self.__dict__.get(
MultilingualField.localized_field_name(
name, settings.LANGUAGE_CODE))
return val

# generate language-specific fields dynamically
if not cls._meta.abstract:
if self.localized_field_model:
for lang_code, lang_name in settings.LANGUAGES:
localized_field = self.get_localized_field(
lang_code, lang_name)
localized_field.contribute_to_class(
cls,
MultilingualField.localized_field_name(
name, lang_code))

setattr(cls, name, property(translated_value))
else:
super().contribute_to_class(
cls, name, private_only, virtual_only)
  1. In the same file, subclass the base field for character and text field forms, as follows:
class MultilingualCharField(models.CharField, MultilingualField):
pass

class MultilingualTextField(models.TextField, MultilingualField):
pass
  1. Create an admin.py file in the core app, and add the following content:
# myproject/apps/core/admin.py
from django.conf import settings

def get_multilingual_field_names(field_name):
lang_code_underscored = settings.LANGUAGE_CODE.replace("-",
"_")
field_names = [f"{field_name}_{lang_code_underscored}"]
for lang_code, lang_name in settings.LANGUAGES:
if lang_code != settings.LANGUAGE_CODE:
lang_code_underscored = lang_code.replace("-", "_")
field_names.append(
f"{field_name}_{lang_code_underscored}"
)
return field_names

Now, we'll consider an example of how to use the multilingual fields in your app, as follows:

  1. First, set multiple languages in the settings for your project. Let's say, our website will support all official languages of the European Union, with English being the default language:
# myproject/settings/_base.py
LANGUAGE_CODE = "en"

# All official languages of European Union
LANGUAGES = [
("bg", "Bulgarian"), ("hr", "Croatian"),
("cs", "Czech"), ("da", "Danish"),
("nl", "Dutch"), ("en", "English"),
("et", "Estonian"), ("fi", "Finnish"),
("fr", "French"), ("de", "German"),
("el", "Greek"), ("hu", "Hungarian"),
("ga", "Irish"), ("it", "Italian"),
("lv", "Latvian"), ("lt", "Lithuanian"),
("mt", "Maltese"), ("pl", "Polish"),
("pt", "Portuguese"), ("ro", "Romanian"),
("sk", "Slovak"), ("sl", "Slovene"),
("es", "Spanish"), ("sv", "Swedish"),
]
  1. Then, open the models.py file from the myproject.apps.ideas app, and create the multilingual fields for the Idea model, as follows:
# myproject/apps/ideas/models.py
from django.db import models
from django.utils.translation import gettext_lazy as _

from myproject.apps.core.model_fields import (
MultilingualCharField,
MultilingualTextField,
)

class Idea(models.Model):
title = MultilingualCharField(
_("Title"),
max_length=200,
)
content = MultilingualTextField(
_("Content"),
)

class Meta:
verbose_name = _("Idea")
verbose_name_plural = _("Ideas")

def __str__(self):
return self.title
  1. Create an admin.py file for the ideas app:
# myproject/apps/ideas/admin.py
from
django.contrib import admin
from django.utils.translation import gettext_lazy as _

from myproject.apps.core.admin import get_multilingual_field_names

from .models import Idea

@admin.register(Idea)
class IdeaAdmin(admin.ModelAdmin):
fieldsets = [
(_("Title and Content"), {
"fields": get_multilingual_field_names("title") +
get_multilingual_field_names("content")
}),
]

How it works...

The example of Idea will generate a model that is similar to the following:

class Idea(models.Model):
title_bg = models.CharField(
_("Title (Bulgarian)"),
max_length=200,
)
title_hr = models.CharField(
_("Title (Croatian)"),
max_length=200,
)
# titles for other languages…
title_sv = models.CharField(
_("Title (Swedish)"),
max_length=200,
)

content_bg = MultilingualTextField(
_("Content (Bulgarian)"),
)
content_hr = MultilingualTextField(
_("Content (Croatian)"),
)
# content for other languages…
content_sv = MultilingualTextField(
_("Content (Swedish)"),
)

class Meta:
verbose_name = _("Idea")
verbose_name_plural = _("Ideas")

def __str__(self):
return self.title

If there were any language codes with a dash, like "de-ch" for Swiss German, the fields for those languages would be replaced with underscores, like title_de_ch and content_de_ch.

In addition to the generated language-specific fields, there will be two properties – title and content – that will return the corresponding field in the currently active language. These will fall back to the default language if no localized field content is available.

The MultilingualCharField and MultilingualTextField fields will juggle the model fields dynamically, depending on your LANGUAGES setting. They will overwrite the contribute_to_class() method that is used when the Django framework creates the model classes. The multilingual fields dynamically add character or text fields for each language of the project. You'll need to create a database migration to add the appropriate fields in the database. Also, the properties are created to return the translated value of the currently active language or the main language, by default.

In the administration, get_multilingual_field_names() will return a list of language-specific field names, starting with one of the default languages and then proceeding with the other languages from the LANGUAGES setting.

Here are a couple of examples of how you might use the multilingual fields in templates and views.

If you have the following code in the template, it will show the text in the currently active language, let's say Lithuanian, and will fall back to English if the translation doesn't exist:

<h1>{{ idea.title }}</h1>
<div>{{ idea.content|urlize|linebreaks }}</div>

If you want to have your QuerySet ordered by the translated titles, you can define it as follows:

>>> lang_code = input("Enter language code: ")
>>> lang_code_underscored = lang_code.replace("-", "_")
>>> qs = Idea.objects.order_by(f"title_{lang_code_underscored}")

See also

  • The Working with model translation tables recipe
  • The Using migrations recipe
  • Chapter 6, Model Administration
bookmark search playlist download font-size

Change the font size

margin-width

Change margin width

day-mode

Change background colour

Close icon Search
Country selected

Close icon Your notes and bookmarks

Delete Bookmark

Modal Close icon
Are you sure you want to delete it?
Cancel
Yes, Delete