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

实操多语言博客

一、今日学习内容概述

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

二、模型设计

# 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 = _('文章翻译')

三、视图实现

# 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配置

# 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 %}

六、流程图

在这里插入图片描述

七、管理接口

# 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',)}

八、表单处理

# 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']

九、中间件

# 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

十、工具函数

# 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.mzph.cn/pingmian/65335.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

iviewui表单验证新手教程

1、表单验证介绍 下面来讲解iviewui表单验证的实现&#xff0c;下面上示例代码&#xff1a; <template><Form ref"formInline" :model"formInline" :rules"ruleInline" inline><FormItem prop"user"><!--prop属…

Doris的SQL原理解析

今天来介绍下Doris的SQL原理解析&#xff0c;主要从语法、解析、分析、执行等几个方面来介绍&#xff0c;可以帮助大家对Doris底层有个清晰的理解~ 一、Doris简介 Apache Doris是一个基于MPP架构的高性能、实时的分析型数据库&#xff0c;能够较好的满足报表分析、即席查询、…

OpenHarmony开发板环境搭建

程序员Feri一名12年的程序员,做过开发带过团队创过业,擅长Java相关开发、鸿蒙开发、人工智能等,专注于程序员搞钱那点儿事,希望在搞钱的路上有你相伴&#xff01;君志所向,一往无前&#xff01; 0.OpenHarmony 0.1 OpenHarmony OpenHarmony是一款面向全场景、全连接、全智能的…

Web前端基础知识(四)

CSS简介 CSS(层叠样式表)&#xff0c;用于定义网页样式和布局的样式表语言。 一般与HTML一起用于构建web页面的。 HTML负责定义页面的结构和内容&#xff0c;CSS负责控制页面的外观和样式。 通过CSS&#xff0c;可以指定页面中各个元素的颜色、字体、大小、间距、边框、背景…

ESP32_h2-创建一个工程后,添加驱动文件并在调用

点击F1或者ctrlshiftP 输入组件名字&#xff1a; 创建好后&#xff0c;可以看到文件目录多了components文件夹和组件文件 &#xff08;文件夹名字uart就是组件名字&#xff09;这里更改了文件名字 在整个工程目录下找到&#xff1a; 添加路径 finish&#xff01; 调用 程…

idea报错:There is not enough memory to perform the requested operation.

文章目录 一、问题描述二、先解决三、后原因&#xff08;了解&#xff09; 一、问题描述 就是在使用 IDEA 写代码时&#xff0c;IDEA 可能会弹一个窗&#xff0c;大概提示你目前使用的 IDEA 内存不足&#xff0c;其实就是提醒你 JVM 的内存不够了&#xff0c;需要重新分配。弹…

PHP高性能webman管理系统EasyAdmin8

介绍 EasyAdmin8-webman 在 EasyAdmin 的基础上使用 webman 最新版重构&#xff0c;PHP 最低版本要求不低于 8.0。基于webman和layui v2.9.x的快速开发的后台管理系统。 项目地址&#xff1a;http://easyadmin8.top 演示地址&#xff1a;http://webman.easyadmin8.top/admin …

《Ceph:一个可扩展、高性能的分布式文件系统》

大家觉得有意义和帮助记得及时关注和点赞!!! 和大多数分布式存储系统只支持单一的存储类型不同&#xff0c;Ceph 同时支持三种&#xff1a; 文件系统&#xff08;file system&#xff09;&#xff1a;有类似本地文件系统的层级结构&#xff08;目录树&#xff09;&#xff0c…

Kafka数据迁移全解析:同集群和跨集群

文章目录 一、同集群迁移二、跨集群迁移 Kafka两种迁移场景&#xff0c;分别是同集群数据迁移、跨集群数据迁移。 一、同集群迁移 应用场景&#xff1a; broker 迁移 主要使用的场景是broker 上线,下线,或者扩容等.基于同一套zookeeper的操作。 实践&#xff1a; 将需要新添加…

“智能控制的新纪元:2025年机器学习与控制工程国际会议引领变革

ICMLCE 2025 | 机器学习与控制工程国际会议 ✨宝子们&#xff0c;今天要为大家介绍的是一个在机器学习和控制工程领域备受瞩目的国际学术盛会——2025年机器学习与控制工程国际会议&#xff08;ICMLCE 2025&#xff09;。本次大会将在美丽的大理举行&#xff0c;旨在汇聚全球顶…

公路边坡安全监测中智能化+定制化+全面守护的应用方案

面对公路边坡的安全挑战&#xff0c;我们如何精准施策&#xff0c;有效应对风险&#xff1f;特别是在强降雨等极端天气下&#xff0c;如何防范滑坡、崩塌、路面塌陷等灾害&#xff0c;确保行车安全&#xff1f;国信华源公路边坡安全监测解决方案&#xff0c;以智能化、定制化为…

pyqt和pycharm环境搭建

安装 python安装&#xff1a; https://www.python.org/downloads/release/python-3913/ python3.9.13 64位(记得勾选Path环境变量) pycharm安装&#xff1a; https://www.jetbrains.com/pycharm/download/?sectionwindows community免费版 换源&#xff1a; pip config se…

在dynadot进行NS域名服务器设置后网站无法访问的可能原因

关于Dynadot Dynadot是通过ICANN认证的域名注册商&#xff0c;自2002年成立以来&#xff0c;服务于全球108个国家和地区的客户&#xff0c;为数以万计的客户提供简洁&#xff0c;优惠&#xff0c;安全的域名注册以及管理服务。 其他索引&#xff1a; Dynadot平台操作教程索引…

【初接触】【学习】编译 Rust 为 WebAssembly

前言 需要先了解以下知识&#xff1a; WebAssemblyRustwasm_bindgenwasm-packjs-sysweb-sysJavaScriptHTMLCSSwebpack 假设您已经了解所有知识点&#xff0c;并且您的环境中已安装了 Node.js和npm 以及 Rust 的完整开发工具链&#xff08;包括 rustc、cargo 和 rustup&#…

探秘仓颉编程语言:使用体验与功能剖析

目录 一、引言&#xff1a;仓颉登场&#xff0c;编程新纪元开启 二、初体验&#xff1a;搭建环境与 “Hello World” &#xff08;一&#xff09;环境搭建指南 &#xff08;二&#xff09;Hello World 初印象 三、核心特性剖析&#xff1a;智能、高效、安全多维解读 &…

AI真的可以“陪伴”吗?

人们普遍渴求陪伴&#xff0c;仅有4.6%的人认为自己的陪伴需求都被满足了&#xff0c;剩下大部分人群都面临着各种各样的社交困境。 “陪伴”有多个层次。最狭义的“陪伴”是在人与人之间发生的&#xff1b;但稍微放宽一些&#xff0c;宠物甚至植物、家具也会让…

基于cobra开发的k8s命令行管理工具k8s-manager

基于cobra开发的k8s命令行管理工具k8s-manager 如果觉得好用&#xff0c;麻烦给个Star!通用配置1 node 分析所有node的资源情况2 analysis 分析Node节点上的资源使用构成3 image 获取指定namespace的所有镜像地址4 resource 获取指定namespace的所有limit 与 Requests大小5 top…

从零开始C++游戏开发之第七篇:游戏状态机与回合管理

在游戏开发的道路上&#xff0c;状态管理是一个无法绕开的重要课题。尤其是在棋牌类游戏中&#xff0c;游戏的进行需要有条不紊地按照回合推进&#xff0c;同时管理多个游戏状态&#xff0c;如“等待玩家加入”、“游戏进行中”、“结算阶段”等。如何优雅且高效地实现这些逻辑…

USB Hub 检测设备

系列文章目录 xHCI 简单分析 USB Root Hub 分析 USB Hub 检测设备 文章目录 系列文章目录一、引言二、hub_eventshub_port_connect_changeusb_alloc_devusb_set_device_statehub_port_initusb_new_device 一、引言 USB Hub 检测设备 一文中讲到&#xff0c;当有 USB 插入时&…

MySQL从入门到入土---MySQL表的约束 (内含实践)---详细版

目录 引入&#xff1a; null 与not null default&#xff1a; comment列描述 &#xff1a; not null 和 default&#xff1a; zerofill &#xff1a; 主键&#xff1a;primary key 复合主键&#xff1a; 自增长:auto_increment 唯一键&#xff1a;unique key 外键&a…