Sign In Start Free Trial
Account

Add to playlist

Create a Playlist

Modal Close icon
You need to login to use this feature.
  • Book Overview & Buying Django 3 Web Development Cookbook
  • Table Of Contents Toc
  • Feedback & Rating feedback
Django 3 Web Development Cookbook

Django 3 Web Development Cookbook

By : Aidas Bendoraitis, Jake Kronika
3.6 (9)
close
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
close

Working with model translation tables

The second approach to handling multilingual content in the database involves using model translation tables for each multilingual model.

The features of this approach are as follows:

  • You can use contributed administration to edit translations as inlines.
  • After changing the amount of languages in the settings, no migrations or other further actions are necessary.
  • You can effortlessly show the translation of the current language in the template, but it would be more difficult to show several translations in specific languages on the same page.
  • You have to know and use a specific pattern described in this recipe for creating model translations.
  • It's not that simple to use this approach for database queries, but, as you will see, it's still possible.

Getting ready

Once again, we will start with the myprojects.apps.core app.

How to do it...

Execute the following steps to prepare for multilingual models:

  1. In the core app, create model_fields.py with the following content:
# myproject/apps/core/model_fields.py
from
django.conf import settings
from django.utils.translation import get_language
from django.utils import translation

class TranslatedField(object):
def __init__(self, field_name):
self.field_name = field_name

def __get__(self, instance, owner):
lang_code = translation.get_language()
if lang_code == settings.LANGUAGE_CODE:
# The fields of the default language are in the main
model
return getattr(instance, self.field_name)
else:
# The fields of the other languages are in the
translation
# model, but falls back to the main model
translations = instance.translations.filter(
language=lang_code,
).first() or instance
return getattr(translations, self.field_name)
  1. Add the admin.py file to the core app with the following content:
# myproject/apps/core/admin.py
from
django import forms
from django.conf import settings
from django.utils.translation import gettext_lazy as _

class LanguageChoicesForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
LANGUAGES_EXCEPT_THE_DEFAULT = [
(lang_code, lang_name)
for lang_code, lang_name in settings.LANGUAGES
if lang_code != settings.LANGUAGE_CODE
]
super().__init__(*args, **kwargs)
self.fields["language"] = forms.ChoiceField(
label=_("Language"),
choices=LANGUAGES_EXCEPT_THE_DEFAULT,
required=True,
)

Now let's implement the multilingual models:

  1. First, set multiple languages in the settings for your project. Let's say, our website will support all official languages of 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, let's create the Idea and IdeaTranslations models:
# myproject/apps/ideas/models.py
from
django.db import models
from django.conf import settings
from django.utils.translation import gettext_lazy as _

from myproject.apps.core.model_fields import TranslatedField


class Idea(models.Model):
title = models.CharField(
_("Title"),
max_length=200,
)
content = models.TextField(
_("Content"),
)
translated_title = TranslatedField("title")
translated_content = TranslatedField("content")

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

def __str__(self):
return self.title


class IdeaTranslations(models.Model):
idea = models.ForeignKey(
Idea,
verbose_name=_("Idea"),
on_delete=models.CASCADE,
related_name="translations",
)
language = models.CharField(_("Language"), max_length=7)

title = models.CharField(
_("Title"),
max_length=200,
)
content = models.TextField(
_("Content"),
)

class Meta:
verbose_name = _("Idea Translations")
verbose_name_plural = _("Idea Translations")
ordering = ["language"]
unique_together = [["idea", "language"]]

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

from myproject.apps.core.admin import LanguageChoicesForm

from .models import Idea, IdeaTranslations


class IdeaTranslationsForm(LanguageChoicesForm):
class Meta:
model = IdeaTranslations
fields = "__all__"


class IdeaTranslationsInline(admin.StackedInline):
form = IdeaTranslationsForm
model = IdeaTranslations
extra = 0


@admin.register(Idea)
class IdeaAdmin(admin.ModelAdmin):
inlines = [IdeaTranslationsInline]

fieldsets = [
(_("Title and Content"), {
"fields": ["title", "content"]
}),
]

How it works...

We keep the language-specific fields of the default language in the Idea model itself. The translations for each language are in the IdeaTranslations model, which will be listed in the administration as an inline translation. IdeaTranslations don't have the language choices at the model for a reason – we don't want to create migrations every time a new language is added or some language is removed. Instead, the language choices are set in the administration form, also making sure that the default language is skipped or not available for selection in the list. The language choices are restricted using the LanguageChoicesForm class.

To get a specific field in the current language, you would use the fields defined as TranslatedField. In the template, that would look like the following:

<h1>{{ idea.translated_title }}</h1>
<div>{{ idea.translated_content|urlize|linebreaks }}</div>

To order items by a translated title in a specific language, you would use the annotate() method as follows:

>>> from django.conf import settings
>>> from django.db import models
>>> lang_code = input("Enter language code: ")

>>> if lang_code == settings.LANGUAGE_CODE:
... qs = Idea.objects.annotate(
... title_translation=models.F("title"),
... content_translation=models.F("content"),
... )
... else:
... qs = Idea.objects.filter(
... translations__language=lang_code,
... ).annotate(
... title_translation=models.F("translations__title"),
... content_translation=models.F("translations__content"),
... )

>>> qs = qs.order_by("title_translation")

>>> for idea in qs:
... print(idea.title_translation)

In this example, we prompt for a language code in the Django shell. If the language is the default one, we store the title and content as the title_translation and the content_translation from the Idea model. If there is another language chosen, we read the title and content as title_translation and content_translation from the IdeaTranslations model with the chosen language.

Afterward, we can filter or order QuerySet by title_translation or content_translation.

See also

  • The Handling multilingual fields recipe
  • Chapter 6, Model Administration

Create a Note

Modal Close icon
You need to login to use this feature.
notes
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

Delete Note

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

Edit Note

Modal Close icon
Write a note (max 255 characters)
Cancel
Update Note

Confirmation

Modal Close icon
claim successful

Buy this book with your credits?

Modal Close icon
Are you sure you want to buy this book with one of your credits?
Close
YES, BUY