DeepSeek+Claude强强联手,使用AI驱动DjangoStarter 3.1框架升级

前言

上个月底培训了一周就没时间更新博客

上周有一些空闲时间,就继续体验最近很火的AI辅助编程

之前的文章中有说到我配置好了 VSCode + Cline 插件搭配本地部署的 DeepSeek 来实现AI辅助编程

参考: 开发者新选择:用DeepSeek实现Cursor级智能编程的免费方案

但 Cline 插件消耗 token 太快了,换本地部署的 DeepSeek 的话不够聪明

我后面又换了 RooCode 、 Continue 这俩插件,还有试了一下新的IDE Trae

用下来 RooCode 还不错,这是 Cline 的 fork 版本,功能多了一些,消耗 Token 数量我没去统计,感觉可能差不多

大模型服务我选择了购买 DeepSeek 和 Claude 的 API

Trae 胜在免费,不过国内外区别对待是有点让人难受的

最终我在 Claude 和 DeepSeek 的辅助下,完成了 DjangoStarter 3.1 版本的开发

关于 DjangoStarter

DjangoStarter v3 是下一代 Django 项目快速开发模板,专为提升开发效率和性能而设计。

结合了 Django 的丰富功能和 Django-Ninja 的性能、灵活、简洁特性,v3 版本旨在为开发者提供一个更加强大、简洁和高速的开发体验。

通过这个全新的框架版本,开发者能够迅速搭建起符合现代 web 应用标准的项目基础架构。

之前我写了一篇文章专门介绍这个v3版本,这里就不赘述了。

感兴趣的同学可以查看: 关于正在开发中的DjangoStarter v3版本

重构界面

本次最大的改变就是使用 Tailwind CSS 取代了原本的 Bootstrap,并且加入了很多新的页面,比如用户中心、设置、关于、联系我们、登录、注册、用户协议等,基本就是往 CMS 的方向走。

我甚至一度想引入 wagtail ,不过后面想想还是算了,已经够重了,等下完全和小项目不沾边,哈哈哈😄

国际化支持 (beta)

这次还添加了国际化支持

Django 本身是有国际化功能的

只不过很多项目都去除了

这次我加入了国际化支持,不过只是测试版,只是添加了支持,翻译部分我还没做好,所以也就还没把切换语言的按钮加上。

以下是一些国际化功能的用法

在模板里

{% translate 'Home' %} 

在python代码里

from django.utils.translation import gettext_lazy as _  print(_('hello')) 

生成翻译文件

src 目录下执行

django-admin makemessages -l [language_code] 

language_code:

  • zh_HAns
  • en_US

其他语言可以参考Django官网

编译消息文件

依然是在 src 目录下执行

django-admin compilemessages 

Windows 开发环境

如果是使用 windows 开发,需要先安装 gettext 工具

推荐使用 scoop 包管理器

scoop install gettext 

安装完成之后,执行以下命令验证

xgettext --version 

部分界面截图

旧版主页

先来看看旧版的主页长什么样

DeepSeek+Claude强强联手,使用AI驱动DjangoStarter 3.1框架升级

新版主页

新的界面使用 Tailwind CSS 重构,好看了很多

DeepSeek+Claude强强联手,使用AI驱动DjangoStarter 3.1框架升级

底部也是可以配置的

DeepSeek+Claude强强联手,使用AI驱动DjangoStarter 3.1框架升级

关于

这个页面做了很多动效,可以看看后面的动图

DeepSeek+Claude强强联手,使用AI驱动DjangoStarter 3.1框架升级

动效是用AOS做的,感觉还不错,挺方便的,不过要注意得使用 3.0 的 beta 版本,一开始没注意遇到了不少坑。

DeepSeek+Claude强强联手,使用AI驱动DjangoStarter 3.1框架升级

联系我们

这些联系方式都是可以配置的

DeepSeek+Claude强强联手,使用AI驱动DjangoStarter 3.1框架升级

表单也用上了 DjangoStarter 新版封装好的 BaseModelForm

DeepSeek+Claude强强联手,使用AI驱动DjangoStarter 3.1框架升级

封装好的 BaseModelForm 用起来是这样

class ContactModelForm(BaseModelForm):     class Meta:         model = Contact         fields = ('name', 'email', 'phone', 'message')         widgets = {             'name': forms.TextInput(attrs={'placeholder': '请输入您的姓名'}),             'email': forms.EmailInput(attrs={'placeholder': '请输入您的邮箱'}),             'phone': forms.TextInput(attrs={'placeholder': '请输入您的联系电话'}),             'message': forms.Textarea(attrs={'placeholder': '请输入您的留言内容', 'rows': 4})         } 

登录/注册

这个登录页面是之前使用 wagtail 那个项目里面搬过来的

DeepSeek+Claude强强联手,使用AI驱动DjangoStarter 3.1框架升级

注册页面也是类似的,这里就不贴图片了

个人中心

个人中心这里的布局来自之前的 TodayTV 项目,不过原来也是从其他在线模板参考来的,界面不是很好看。

然而我用 Claude 3.5 和 DeepSeek R1 反复优化多次,仍然无法让我满意,而且代码越来越乱,感觉后面还是得自己来改。

DeepSeek+Claude强强联手,使用AI驱动DjangoStarter 3.1框架升级

下面的关于我

DeepSeek+Claude强强联手,使用AI驱动DjangoStarter 3.1框架升级

修改资料

这也是从 TodayTV 项目来的,搭配 Django Forms 实现出来的效果还可以。

DeepSeek+Claude强强联手,使用AI驱动DjangoStarter 3.1框架升级

隐私政策

这个是用 Claude 生成的,使用 RooCode 优化的提示词,看着有模有样的。

DeepSeek+Claude强强联手,使用AI驱动DjangoStarter 3.1框架升级

服务条款也是类似的,这里我就不截图了。

Demo页面

为了方便演示各种功能,我还新增了Demo页面

当然这个不太协调的页面是 AI 辅助布局的

DeepSeek+Claude强强联手,使用AI驱动DjangoStarter 3.1框架升级

错误页面

并且用 Claude 生成了几个错误页面

包括403、404、500页面,都是类似的,这里我只贴403页面的截图

DeepSeek+Claude强强联手,使用AI驱动DjangoStarter 3.1框架升级

解决了一个 issue

https://github.com/Deali-Axy/DjangoStarter/issues/20

有用户反馈本来应该返回400的接口,实际返回了200

我看了之后发现这个问题属于是从DRF迁移到ninja的历史遗留问题

之前我在框架里封装 responses 用于快捷输出各种返回状态

def ok(message: str, data: Optional[dict] = None):     return _gen_resp(message, data, 200)  def forbidden(message: str, data: Optional[dict] = None):     return _gen_resp(message, data, 403)  def bad_request(message: str, data: Optional[dict] = None):     return _gen_resp(message, data, 400)  def not_found(message: str, data: Optional[dict] = None):     return _gen_resp(message, data, 404) 

但现在 ninja 里,一直返回的都是 200,这个就是处理返回状态码的地方出问题。

有几种解决思路,反正原本我用重写 renderer 的方式是没办法的,renderer里没法定义返回值,只能改变相应内容。

要不就是用 django 中间件,但需要解析 JSON 会影响性能

最终我对 responses 进行了改造,新增了 ResponseGenerator 这个类,代码就不贴了

关键实现就是用了 ninja 的 api.create_response 这个方法可以指定 status code

在需要用到的地方,比如 src/apps/account/apis/auth/apis.py

router = Router(tags=['auth'])  _resp = ResponseGenerator(router=router)  @router.post('/register', url_name='account/auth/register') def register(request, data: RegisterSchema):     if User.objects.filter(username=data.username).exists():         return _resp.bad_request(request, '用户名已存在!')      if data.phone:         phone_pattern = '^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\d{8}$'         if not re.match(phone_pattern, data.phone):             return _resp.bad_request(request, '手机号码格式不对!')          if UserProfile.objects.filter(phone=data.phone).exists():             return _resp.bad_request(request, '手机号已存在!')      if data.password != data.confirm_password:         return _resp.bad_request(request, '密码不一致!') 

相比起原来的,每个返回的响应需要添加 request 参数

虽然比起原来复杂一点,也算是搞定了。

Todos

发表评论

您必须 [ 登录 ] 才能发表留言!

相关文章