每天40分玩转Django:Django插件开发

Django插件开发

一、插件开发概述表

阶段主要任务技术要点难度
准备工作项目结构设计、环境配置项目布局、setup.py★★★☆☆
开发实现功能开发、测试编写Django AppConfig、Signals★★★★☆
文档编写API文档、使用说明Markdown、reStructuredText★★★☆☆
发布部署PyPI打包、发布setuptools、twine★★★★☆

二、创建可重用Django应用

我们以一个通用的评论系统插件为例,演示如何创建可重用的Django应用。

2.1 项目结构

django-generic-comments/
├── LICENSE
├── MANIFEST.in
├── README.md
├── setup.py
├── generic_comments/
│   ├── __init__.py
│   ├── apps.py
│   ├── models.py
│   ├── views.py
│   ├── urls.py
│   ├── forms.py
│   ├── signals.py
│   ├── templates/
│   │   └── generic_comments/
│   │       ├── comment_form.html
│   │       └── comment_list.html
│   └── static/
│       └── generic_comments/
│           ├── css/
│           └── js/
└── tests/├── __init__.py├── test_models.py└── test_views.py

2.2 核心代码实现

# generic_comments/apps.py
from django.apps import AppConfigclass GenericCommentsConfig(AppConfig):name = 'generic_comments'verbose_name = 'Generic Comments'def ready(self):import generic_comments.signals
# generic_comments/models.py
from django.db import models
from django.conf import settings
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentTypeclass Comment(models.Model):content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)object_id = models.PositiveIntegerField()content_object = GenericForeignKey('content_type', 'object_id')user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)content = models.TextField()created_at = models.DateTimeField(auto_now_add=True)updated_at = models.DateTimeField(auto_now=True)is_public = models.BooleanField(default=True)class Meta:ordering = ['-created_at']def __str__(self):return f'Comment by {self.user.username} on {self.content_object}'
# generic_comments/forms.py
from django import forms
from .models import Commentclass CommentForm(forms.ModelForm):class Meta:model = Commentfields = ['content']widgets = {'content': forms.Textarea(attrs={'rows': 4})}
# generic_comments/views.py
from django.shortcuts import redirect, get_object_or_404
from django.contrib.auth.decorators import login_required
from django.contrib.contenttypes.models import ContentType
from django.contrib import messages
from .forms import CommentForm
from .signals import comment_posted@login_required
def add_comment(request, content_type_id, object_id):content_type = get_object_or_404(ContentType, id=content_type_id)content_object = content_type.get_object_for_this_type(id=object_id)if request.method == 'POST':form = CommentForm(request.POST)if form.is_valid():comment = form.save(commit=False)comment.user = request.usercomment.content_type = content_typecomment.object_id = object_idcomment.save()# 触发评论发布信号comment_posted.send(sender=comment.__class__,comment=comment,request=request)messages.success(request, '评论已发布')return redirect(content_object.get_absolute_url())else:form = CommentForm()return render(request, 'generic_comments/comment_form.html', {'form': form,'content_object': content_object})
# generic_comments/signals.py
from django.dispatch import Signalcomment_posted = Signal()# 信号接收器示例
def notify_comment_posted(sender, comment, request, **kwargs):"""当评论发布时发送通知"""pass

2.3 配置文件

# setup.py
from setuptools import setup, find_packagessetup(name='django-generic-comments',version='0.1.0',packages=find_packages(exclude=['tests*']),include_package_data=True,license='MIT',description='A Django app for adding comments to any model',long_description=open('README.md').read(),long_description_content_type='text/markdown',url='https://github.com/yourusername/django-generic-comments',author='Your Name',author_email='your.email@example.com',classifiers=['Environment :: Web Environment','Framework :: Django','Framework :: Django :: 3.2','Intended Audience :: Developers','License :: OSI Approved :: MIT License','Operating System :: OS Independent','Programming Language :: Python','Programming Language :: Python :: 3','Programming Language :: Python :: 3.8','Topic :: Internet :: WWW/HTTP','Topic :: Internet :: WWW/HTTP :: Dynamic Content',],python_requires='>=3.8',install_requires=['Django>=3.2',],
)
# MANIFEST.in
include LICENSE
include README.md
recursive-include generic_comments/static *
recursive-include generic_comments/templates *
recursive-include docs *

三、应用开发流程图

在这里插入图片描述

四、测试用例编写

# tests/test_models.py
from django.test import TestCase
from django.contrib.auth import get_user_model
from django.contrib.contenttypes.models import ContentType
from generic_comments.models import CommentUser = get_user_model()class CommentModelTest(TestCase):def setUp(self):self.user = User.objects.create_user(username='testuser',email='test@example.com',password='testpass123')def test_comment_creation(self):comment = Comment.objects.create(user=self.user,content='Test comment',content_type=ContentType.objects.get_for_model(User),object_id=self.user.id)self.assertEqual(str(comment), f'Comment by testuser on {self.user}')self.assertTrue(comment.is_public)
# tests/test_views.py
from django.test import TestCase, Client
from django.urls import reverse
from django.contrib.auth import get_user_model
from django.contrib.contenttypes.models import ContentType
from generic_comments.models import CommentUser = get_user_model()class CommentViewsTest(TestCase):def setUp(self):self.client = Client()self.user = User.objects.create_user(username='testuser',password='testpass123')def test_add_comment(self):self.client.login(username='testuser', password='testpass123')content_type = ContentType.objects.get_for_model(User)response = self.client.post(reverse('generic_comments:add_comment', kwargs={'content_type_id': content_type.id,'object_id': self.user.id}),{'content': 'Test comment'})self.assertEqual(response.status_code, 302)self.assertEqual(Comment.objects.count(), 1)

五、文档编写

# Django Generic CommentsA reusable Django application for adding comments to any model.## Installation```bash
pip install django-generic-comments

Quick Start

  1. Add “generic_comments” to your INSTALLED_APPS setting:
INSTALLED_APPS = [...'generic_comments',
]
  1. Include the generic_comments URLconf in your project urls.py:
path('comments/', include('generic_comments.urls')),
  1. Run migrations:
python manage.py migrate

Usage

To add comments to a model:

from django.contrib.contenttypes.fields import GenericRelation
from generic_comments.models import Commentclass YourModel(models.Model):comments = GenericRelation(Comment)

## 六、发布到PyPI### 6.1 打包准备1. 安装必要工具:
```bash
pip install setuptools wheel twine
  1. 创建分发包:
python setup.py sdist bdist_wheel
  1. 上传到PyPI:
twine upload dist/*

6.2 发布检查清单

  1. 代码质量检查:
# 运行测试
python runtests.py# 代码风格检查
flake8 generic_comments
  1. 文档完整性检查:
  • README.md 是否完整
  • 使用说明是否清晰
  • API文档是否完整
  1. 版本号管理:
# generic_comments/__init__.py
VERSION = (0, 1, 0)
__version__ = '.'.join(map(str, VERSION))

七、使用示例

7.1 在项目中集成

# settings.py
INSTALLED_APPS = [...'generic_comments',
]# 可选配置
GENERIC_COMMENTS_CONFIG = {'moderate_comments': False,'email_notifications': True,
}# models.py
from django.db import models
from django.contrib.contenttypes.fields import GenericRelation
from generic_comments.models import Commentclass Article(models.Model):title = models.CharField(max_length=200)content = models.TextField()comments = GenericRelation(Comment)def get_absolute_url(self):return reverse('article_detail', args=[self.id])

7.2 模板使用

{% load generic_comments_tags %}<div class="comments">{% get_comment_list for article as comments %}{% for comment in comments %}<div class="comment"><div class="comment-user">{{ comment.user }}</div><div class="comment-content">{{ comment.content }}</div><div class="comment-date">{{ comment.created_at|date:"Y-m-d H:i" }}</div></div>{% endfor %}{% if user.is_authenticated %}{% get_comment_form for article as form %}<form method="post" action="{% url 'generic_comments:add_comment' content_type_id=content_type.id object_id=article.id %}">{% csrf_token %}{{ form.as_p }}<button type="submit">提交评论</button></form>{% endif %}
</div>

八、最佳实践建议

  1. 代码组织:

    • 遵循Django应用规范
    • 保持代码模块化
    • 使用合适的设计模式
  2. 测试覆盖:

    • 编写完整的单元测试
    • 包含集成测试
    • 测试边界情况
  3. 文档维护:

    • 详细的安装说明
    • 清晰的API文档
    • 丰富的使用示例
  4. 版本控制:

    • 语义化版本号
    • 更新日志维护
    • 分支管理策略

本节课程介绍了如何开发和发布一个Django可重用应用。通过具体的评论系统示例,展示了从开发到发布的完整流程。建议学习者在实践中注意以下几点:

  1. 充分考虑应用的可复用性和扩展性
  2. 编写完整的测试和文档
  3. 遵循Python包发布的最佳实践
  4. 持续维护和更新应用

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/891808.shtml

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

相关文章

什么是TDD测试驱动开发(Test Driven Development)?

什么是测试驱动开发&#xff1f; 软件开发团队通常会编写自动化测试套件来防止回归。这些测试通常是在编写应用程序功能代码之后编写的。我们将采用另一种方法&#xff1a;在实现应用程序代码之前编写测试。这称为测试驱动开发 (TDD)。 为什么要应用 TDD&#xff1f;通过在实…

后台管理系统用户退出登录方案实现

退出登录一直是一个通用的前端实现方案&#xff0c;对于退出登录而言&#xff0c;它的触发时机一般有两种&#xff1a; 1. 用户主动退出&#xff0c;即用户点击登录按钮之后退出&#xff1b; 2. 用户被动退出&#xff0c;Token过期或被 其他人"顶下来" 时退出&…

文献分享:BGE-M3——打通三种方式的嵌入模型

文章目录 1. \textbf{1. } 1. 背景与导论 1.1. \textbf{1.1. } 1.1. 研究背景 1.2. \textbf{1.2. } 1.2. 本文的研究 1.3. \textbf{1.3. } 1.3. 有关工作 2. M3-Embedding \textbf{2. M3-Embedding} 2. M3-Embedding 2.1. \textbf{2.1. } 2.1. 模型核心: 混合检索方式 2.1.1. \…

Hadoop•FinalShell连接VMware免密登录

听说这是目录哦 FinalShell连接VMware&#x1f324;️解决重连失效FinalShell的使用 免密登录⛈️能量站&#x1f61a; FinalShell连接VMware&#x1f324;️ 保持虚拟机的开机状态&#xff0c;打开FinalShell&#xff0c;如果虚拟机关机或者挂起&#xff0c;连接就会断开。 …

一个在ios当中采用ObjectC和opencv来显示图片的实例

前言 在ios中采用ObjectC编程利用opencv来显示一张图片&#xff0c;并简单绘图。听上去似乎不难&#xff0c;但是实际操作下来&#xff0c;却不是非常的容易的。本文较为详细的描述了这个过程&#xff0c;供后续参考。 一、创建ios工程 1.1、选择ios工程类型 1.2、选择接口模…

《Rust权威指南》学习笔记(五)

高级特性 1.在Rust中&#xff0c;unsafe是一种允许绕过Rust的安全性保证的机制&#xff0c;用于执行一些Rust默认情况下不允许的操作。unsafe存在的原因是&#xff1a;unsafe 允许执行某些可能被 Rust 的安全性检查阻止的操作&#xff0c;从而可以进行性能优化&#xff0c;如手…

【顶刊TPAMI 2025】多头编码(MHE)之极限分类 Part 3:算法实现

目录 1 三种多头编码&#xff08;MHE&#xff09;实现1.1 多头乘积&#xff08;MHP&#xff09;1.2 多头级联&#xff08;MHC&#xff09;1.3 多头采样&#xff08;MHS&#xff09;1.4 标签分解策略 论文&#xff1a;Multi-Head Encoding for Extreme Label Classification 作者…

docker中使用Dockerfile设置Volume挂载点

关于在docker中如何使用Volume&#xff0c;可以参考文章&#xff1a; docker中使用Volume完成数据共享-CSDN博客 如果想在生成docker镜像的时候设置好挂载点&#xff0c;而不是在运行镜像生成容器时生成。 下面以自建一个tomcat镜像为例&#xff0c;演示如何在生成镜像时设置…

springboot548二手物品交易boot代码(论文+源码)_kaic

摘 要 如今社会上各行各业&#xff0c;都喜欢用自己行业的专属软件工作&#xff0c;互联网发展到这个时候&#xff0c;人们已经发现离不开了互联网。新技术的产生&#xff0c;往往能解决一些老技术的弊端问题。因为传统二手物品交易信息管理难度大&#xff0c;容错率低&#x…

通往O1开源之路

“Scaling of Search and Learning: A Roadmap to Reproduce o1 from Reinforcement Learning Perspective”由复旦大学和上海人工智能实验室的研究者撰写。该论文从强化学习视角出发&#xff0c;深入分析了实现类似OpenAI o1模型性能的路线图&#xff0c;聚焦于策略初始化、奖…

SD下载、安装、使用、卸载-Stable Diffusion整合包v4.10发布!

目录 前言概述 SD安装1、安装软件2、启动3、配置4、运行5、测试 导入SD模型【决定画风】常用模型下载安装模型 SD卸载SD文生图提示词提示词使用技巧提示词的高级使用技巧强调关键词 前言 我向来不喜欢搞一些没有用的概念&#xff0c;所以直接整理可能用到的东西。 sd简单的说…

Mac iTerm2集成DeepSeek AI

1. 去deepseek官网申请api key&#xff0c;DeepSeek 2. 安装iTerm2 AI Plugin插件&#xff0c;https://iterm2.com/ai-plugin.html&#xff0c;插件解压后直接放到和iTerms相同的位置&#xff0c;默认就在/Applications 下 3. 配置iTerm2 4. 重启iTerm2,使用快捷键呼出AI对话…

MySQL数据库笔记——多版本并发控制MVCC

大家好&#xff0c;这里是Good Note&#xff0c;关注 公主号&#xff1a;Goodnote&#xff0c;本文详细介绍MySQL的并发控制&#xff1a;多版本并发控制MVCC。 文章目录 背景介绍数据库并发控制——锁机制悲观锁和乐观锁悲观锁乐观锁 数据库并发控制——MVCC 的引入MVCC 和锁机…

电脑里msvcr120.dll文件丢失怎样修复?

电脑里msvcr120.dll文件丢失的修复指南 在电脑的日常使用中&#xff0c;我们可能会遇到各种各样的系统文件丢失问题&#xff0c;其中msvcr120.dll文件的丢失就是较为常见的一种。作为一名在软件开发领域深耕多年的从业者&#xff0c;我将为大家详细解析msvcr120.dll文件的重要…

今日头条ip属地根据什么显示?不准确怎么办

在今日头条这样的社交媒体平台上&#xff0c;用户的IP属地信息对于维护网络环境的健康与秩序至关重要。然而&#xff0c;不少用户发现自己的IP属地显示与实际位置不符&#xff0c;这引发了广泛的关注和讨论。本文将深入探讨今日头条IP属地的显示依据&#xff0c;并提供解决IP属…

【Rust自学】10.3. trait Pt.1:trait的定义、约束与实现

喜欢的话别忘了点赞、收藏加关注哦&#xff0c;对接下来的教程有兴趣的可以关注专栏。谢谢喵&#xff01;(&#xff65;ω&#xff65;) 题外话&#xff1a;trait的概念非常非常非常重要&#xff01;&#xff01;&#xff01;整个第10章全都是Rust的重难点&#xff01;&#x…

大白话拆解——多线程中关于死锁的一切(七)(已完结)

前言&#xff1a; 25年初&#xff0c;这个时候好多小伙伴都在备战期末 小编明天还有一科考试&#xff0c;日更一篇&#xff0c;今天这篇一定会对小白非常有用的&#xff01;&#xff01;&#xff01; 因为我们会把案例到用代码实现的全过程思路呈现出来&#xff01;&#xff…

GitLab集成Runner详细版--及注意事项汇总【最佳实践】

一、背景 看到网上很多用户提出的runner问题其实实际都不是问题&#xff0c;不过是因为对runner的一些细节不清楚导致了误解。本文不系统性的介绍GitLab-Runner&#xff0c;因为这类文章写得好的特别多&#xff0c;本文只汇总一些常几的问题/注意事项。旨在让新手少弯路。 二、…

《数据结构》期末考试测试题【中】

《数据结构》期末考试测试题【中】 21.循环队列队空的判断条件为&#xff1f;22. 单链表的存储密度比1&#xff1f;23.单链表的那些操作的效率受链表长度的影响&#xff1f;24.顺序表中某元素的地址为&#xff1f;25.m叉树第K层的结点数为&#xff1f;26. 在双向循环链表某节点…

「Mac畅玩鸿蒙与硬件54」UI互动应用篇31 - 滑动解锁屏幕功能

本篇教程将实现滑动解锁屏幕功能&#xff0c;通过 Slider 组件实现滑动操作&#xff0c;学习事件监听、状态更新和交互逻辑的实现方法。 关键词 滑动解锁UI交互状态管理动态更新事件监听 一、功能说明 滑动解锁屏幕功能包含以下功能&#xff1a; 滑动解锁区域&#xff1a;用…