每天40分玩转Django:实操多语言博客

embedded/2024/12/27 10:35:52/

实操多语言博客

一、今日学习内容概述

学习模块重要程度主要内容
国际化配置⭐⭐⭐⭐⭐基础设置、语言切换
翻译模型⭐⭐⭐⭐⭐多语言字段、翻译管理
视图处理⭐⭐⭐⭐多语言内容展示、URL处理
前端实现⭐⭐⭐⭐语言切换、界面适配

二、模型设计

python"># models.py
from django.db import models
from django.conf import settings
from django.urls import reverse
from django.utils.translation import gettext_lazy as _class Category(models.Model):"""文章分类"""name = models.CharField(_('名称'), max_length=100)slug = models.SlugField(_('URL标识'), unique=True)class Meta:verbose_name = _('分类')verbose_name_plural = _('分类')def __str__(self):return self.nameclass Post(models.Model):"""博客文章"""category = models.ForeignKey(Category,on_delete=models.CASCADE,verbose_name=_('分类'))created_at = models.DateTimeField(_('创建时间'), auto_now_add=True)updated_at = models.DateTimeField(_('更新时间'), auto_now=True)is_active = models.BooleanField(_('是否激活'), default=True)class Meta:verbose_name = _('文章')verbose_name_plural = _('文章')def get_absolute_url(self):return reverse('post_detail', args=[str(self.id)])class PostTranslation(models.Model):"""文章翻译"""post = models.ForeignKey(Post,on_delete=models.CASCADE,related_name='translations')language = models.CharField(_('语言'),max_length=10,choices=settings.LANGUAGES)title = models.CharField(_('标题'), max_length=200)content = models.TextField(_('内容'))slug = models.SlugField(_('URL标识'), max_length=200)class Meta:unique_together = ('post', 'language')verbose_name = _('文章翻译')verbose_name_plural = _('文章翻译')

三、视图实现

python"># views.py
from django.shortcuts import render, get_object_or_404
from django.utils.translation import get_language
from django.views.generic import ListView, DetailView
from .models import Post, PostTranslationclass PostListView(ListView):template_name = 'blog/post_list.html'context_object_name = 'posts'def get_queryset(self):language = get_language()return Post.objects.filter(translations__language=language,is_active=True).select_related('category').prefetch_related('translations')class PostDetailView(DetailView):model = Posttemplate_name = 'blog/post_detail.html'def get_object(self, queryset=None):post = super().get_object(queryset)language = get_language()translation = get_object_or_404(PostTranslation,post=post,language=language)post.translation = translationreturn postdef get_context_data(self, **kwargs):context = super().get_context_data(**kwargs)context['available_languages'] = PostTranslation.objects.filter(post=self.object).values_list('language', flat=True)return context

四、URL配置

python"># urls.py
from django.conf.urls.i18n import i18n_patterns
from django.urls import path, include
from . import viewsurlpatterns = [path('i18n/', include('django.conf.urls.i18n')),
]urlpatterns += i18n_patterns(path('', views.PostListView.as_view(), name='post_list'),path('<int:pk>/<slug:slug>/', views.PostDetailView.as_view(), name='post_detail'),prefix_default_language=False
)

五、模板实现

<!-- templates/blog/base.html -->
{% load i18n %}
<!DOCTYPE html>
<html lang="{{ LANGUAGE_CODE }}">
<head><meta charset="UTF-8"><title>{% block title %}{% trans "多语言博客" %}{% endblock %}</title>
</head>
<body><header><nav><form action="{% url 'set_language' %}" method="post" class="language-form">{% csrf_token %}<input name="next" type="hidden" value="{{ request.path }}"><select name="language" onchange="this.form.submit()">{% get_current_language as LANGUAGE_CODE %}{% get_available_languages as LANGUAGES %}{% for lang_code, lang_name in LANGUAGES %}<option value="{{ lang_code }}"{% if lang_code == LANGUAGE_CODE %}selected{% endif %}>{{ lang_name }}</option>{% endfor %}</select></form></nav></header><main>{% block content %}{% endblock %}</main>
</body>
</html><!-- templates/blog/post_list.html -->
{% extends "blog/base.html" %}
{% load i18n %}{% block content %}
<div class="container"><h1>{% trans "文章列表" %}</h1>{% for post in posts %}<article class="post-preview"><h2>{{ post.translations.title }}</h2><p class="meta">{% blocktrans with category=post.category.name date=post.created_at %}分类:{{ category }} | 发布于:{{ date }}{% endblocktrans %}</p><div class="excerpt">{{ post.translations.content|truncatewords:50 }}</div><a href="{{ post.get_absolute_url }}" class="read-more">{% trans "" %}</a></article>{% endfor %}
</div>
{% endblock %}

六、流程图

在这里插入图片描述

七、管理接口

python"># admin.py
from django.contrib import admin
from django.utils.translation import gettext_lazy as _
from .models import Category, Post, PostTranslationclass PostTranslationInline(admin.StackedInline):model = PostTranslationextra = 1@admin.register(Post)
class PostAdmin(admin.ModelAdmin):list_display = ('get_title', 'category', 'created_at', 'is_active')list_filter = ('is_active', 'category', 'created_at')search_fields = ('translations__title', 'translations__content')inlines = [PostTranslationInline]def get_title(self, obj):default_trans = obj.translations.filter(language=settings.LANGUAGE_CODE).first()return default_trans.title if default_trans else _('无标题')get_title.short_description = _('标题')@admin.register(Category)
class CategoryAdmin(admin.ModelAdmin):list_display = ('name', 'slug')prepopulated_fields = {'slug': ('name',)}

八、表单处理

python"># forms.py
from django import forms
from django.utils.translation import gettext_lazy as _
from .models import Post, PostTranslationclass PostTranslationForm(forms.ModelForm):class Meta:model = PostTranslationfields = ['title', 'content', 'slug']def clean_slug(self):slug = self.cleaned_data['slug']language = self.cleaned_data.get('language')if PostTranslation.objects.filter(slug=slug,language=language).exists():raise forms.ValidationError(_('此URL标识已被使用'))return slugclass PostForm(forms.ModelForm):class Meta:model = Postfields = ['category', 'is_active']

九、中间件

python"># middleware.py
from django.utils import translation
from django.conf import settings
from django.urls import resolveclass LanguageMiddleware:def __init__(self, get_response):self.get_response = get_responsedef __call__(self, request):# 检查URL中的语言代码resolved = resolve(request.path_info)language = resolved.kwargs.get('language')if language:# 如果URL中包含语言代码,则设置语言translation.activate(language)request.LANGUAGE_CODE = languageelse:# 否则使用默认语言或用户偏好language = request.COOKIES.get(settings.LANGUAGE_COOKIE_NAME)if language:translation.activate(language)request.LANGUAGE_CODE = languageresponse = self.get_response(request)return response

十、工具函数

python"># utils.py
from django.utils import translation
from django.conf import settingsdef get_translated_field(obj, field_name, language=None):"""获取翻译字段的值"""if language is None:language = translation.get_language()try:trans = obj.translations.get(language=language)return getattr(trans, field_name)except obj.translations.model.DoesNotExist:# 如果找不到翻译,返回默认语言的值try:trans = obj.translations.get(language=settings.LANGUAGE_CODE)return getattr(trans, field_name)except obj.translations.model.DoesNotExist:return Nonedef copy_translation(obj, from_lang, to_lang):"""复制翻译"""try:source = obj.translations.get(language=from_lang)target, created = obj.translations.get_or_create(language=to_lang)if not created:return Falsefor field in ['title', 'content', 'slug']:setattr(target, field, getattr(source, field))target.save()return Trueexcept obj.translations.model.DoesNotExist:return False

通过本章学习,你应该能够:

  1. 实现多语言博客系统
  2. 管理翻译内容
  3. 处理URL国际化
  4. 优化多语言用户体验

怎么样今天的内容还满意吗?再次感谢朋友们的观看,关注GZH:凡人的AI工具箱,回复666,送您价值199的AI大礼包。最后,祝您早日实现财务自由,还请给个赞,谢谢!


http://www.ppmy.cn/embedded/149149.html

相关文章

Day 15:Spring 框架基础

目标 理解 Spring 核心概念&#xff0c;学习依赖注入&#xff08;DI&#xff09;和控制反转&#xff08;IoC&#xff09;的基本实现方式&#xff0c;并能够配置一个简单的 Spring 项目。 1. 什么是 Spring&#xff1f; Spring 是一个轻量级的开源框架&#xff0c;旨在解决企…

【Go】Go数据类型详解—map

1. 前言 本篇博客将会介绍Go语言当中的另一大核心数据类型——map&#xff08;映射&#xff09;&#xff0c;当然在介绍这个数据类型之前我们还是要思考引入这个数据类型的原因&#xff1a; ❓ 需求&#xff1a;要求完成对一个班级所有同学的信息管理&#xff08;包括但不限于…

从 GitLab.com 到 JihuLab.com 的迁移指南

本文分享从 GitLab.com 到 JihuLab.com 的迁移指南。 近期&#xff0c;GitLab Inc. 针对其 SaaS 产品做了限制&#xff0c;如果被判定为国内用户&#xff0c;则会建议使用其在国内的发布版本极狐GitLab。从 GitLab SaaS 产品&#xff08;GitLab.com&#xff09;迁移到极狐GitL…

人工智能的崛起:从机器学习到深度学习,再到计算机视觉

在科技迅速发展的今天&#xff0c;人工智能&#xff08;AI&#xff09;已经从科幻的想象&#xff0c;逐步成为改变社会的核心动力之一。从自动驾驶到智能语音助手&#xff0c;从医疗诊断到推荐系统&#xff0c;人工智能技术的应用场景无处不在。在这些技术背后&#xff0c;机器…

解锁 Claude 的无限潜力:Prompt Engineering 从入门到精通

在人工智能领域&#xff0c;大型语言模型&#xff08;LLM&#xff09;如 Claude 的崛起&#xff0c;为我们带来了前所未有的机遇。然而&#xff0c;如何有效地与这些强大的模型进行交互&#xff0c;使其发挥出最大的潜力&#xff0c;成为了关键。Prompt Engineering&#xff08…

基于ArcGIS Pro的SWAT模型在流域水循环、水生态模拟中的应用及案例分析;SWAT模型安装、运行到结果读取全流程指导

目前&#xff0c;流域水资源和水生态问题逐渐成为制约社会经济和环境可持续发展的重要因素。SWAT模型是一种基于物理机制的分布式流域水文与生态模拟模型&#xff0c;能够对流域的水循环过程、污染物迁移等过程进行精细模拟和量化分析。SWAT模型目前广泛应用于流域水文过程研究…

稳定的碰一碰发视频、碰一碰矩阵源码技术开发,支持OEM

一、引言 碰一碰发视频作为一种新兴的信息传递和交互方式&#xff0c;在多个领域展现出了广阔的应用前景&#xff0c;尤其是在商业推广、文化传播、教育等方面。碰一碰矩阵则是对传统碰一碰技术的一种拓展&#xff0c;通过多个碰一碰设备或标签的组合&#xff0c;实现更复杂的功…

监听器listener

文章目录 监听器( listener)对Application内置对象监听的语法和配置对session内置对象监听的语法和配置 监听器( listener) 对象与对象的关系&#xff1a; 继承关联 tomcat一启动创建的顺序&#xff1a;监听器&#xff0c;config&#xff0c;application(全局初始化参数)&am…