Django:修改/扩展第三方应用程序

13

一个新手Django问题

我想使用第三方应用程序,但我需要对其进行一些修改(在这种情况下,应用程序是django-registration,并且我需要更改一些内容,例如允许无需确认电子邮件即可注册)。

最初,我只是将应用程序安装在通用的site-packages文件夹中,并在那里更改了代码。现在,我将我的代码放在bitbucket上,我需要一种方法以可用的方式在存储库中保留我的修改,并且上传整个python代码似乎不是一个好主意。

我想最好的方法是将第三方应用程序保留在site-packages中,并在我的项目中创建一个应用程序以保留我的更改。在我的情况下,我会在我的项目中创建名为my-django-registration的应用程序,然后在需要它的代码中导入它,而不是django-registration。

我也阅读了关于virtualenv的资料,但我认为那主要用于能够在同一台机器上使用多个环境(实际上,在某些地方它建议不要更改安装在virtualenv中的模块),并且不能帮助我在存储库中保留我的更改。

欢迎任何评论!谢谢

3个回答

19

通常情况下,你应该重用并覆盖第三方应用程序中的行为,而不是修改它们的源代码。

你经常会遇到的情况是应用程序提供的模型可能不完全符合你的需求,但会完成大部分工作;你会拥有几乎完美的表单,但需要一些微调;你会有一个视图,只需要改变一件事就可以变得完美;你会有一些合理的URL,但你需要从中获取更多信息。

在大多数情况下,你只需要创建自定义应用程序并重新连接所有内容。发布映射到扩展和重写方法以实现自定义行为的视图的自己的URL;提供使用您从原始模型扩展的新模型的Meta的模型表单;等等...

这只是你可以做的冰山一角,当你充满创意时,还有更多方式。我可以给你一个例子,说明我如何使用RegistrationProfile模型,但发布了自己的URL模式和处理注册过程的自定义基于类的视图。

现在,virtualenv的作用是,你很可能会使用pip要求文件格式中指定和提供所需的依赖项。那时你需要说: "我已经扩展了django-registration应用程序,但它不能与任何版本完全兼容。它必须是X版本",或者是"从提交Y的仓库检出"。


1
这应该是正确的答案。接受的答案建议的分叉不是正确的方法。 - mbrochh
5
在某些情况下,分支是必要的。如果软件包未得到维护,但它不再与最新的 Django 兼容,那么这是不可避免的。 - Imju

12

这篇博客文章解决了这个问题,非常有用。为了方便起见,我在此将其复制粘贴:

不要修改外部应用程序代码

你不应该编辑来自外部应用程序的代码。除非你先在 GitHub 上 fork 它。

那么,如何在不 fork 的情况下进行覆盖:

覆盖模板

如果你想要覆盖 templates/userena/activate_fail.html,那么你只需要创建一个自己的 templates/userena 目录,并在其中创建你自己的 activate_fail.html

覆盖 URL

在使用外部应用程序时,您应该首先检查它的 urls.py。良好编码的视图应支持大量参数。例如,userena 在撰写本文时具有此类签名的注册视图:

def signup(request, signup_form=SignupForm,
       template_name='userena/signup_form.html', success_url=None,
       extra_context=None):

这意味着您可以替换注册视图使用的表单。要这样做,请打开您的urls.py,在顶部添加我们需要的内容:

from userena import views as userena_views
from yourforms import YourSignupForm

然后,找到包含外部应用程序的URL的位置,类似于:

url(r'^userena/', include('userena.urls')),

在此之前,添加您的URL覆盖:

url(r'^userena/signup/$', userena_views.signup, {'signup_form': YourSignupForm}, name='userena_signup'),
url(r'^userena/', include('userena.urls')),
现在,当访问者访问/userena/signup/时,您定义的自定义url将是第一个被触发的。这意味着/userena/signup/将使用YourSignupForm而不是userena的注册表单。
这个技巧适用于任何视图参数。您最常见到的应该是:
- template_name: 允许您更改模板名称 - extra_context: 允许您添加一个字典,将被添加到上下文中
几乎每个视图都应该有这些参数。
重写视图需要重写您想要替换的视图的URL。如果您希望使用自己的注册视图,则只需覆盖该URL:
import yourviews

# ...
url(r'^userena/signup/$', yourviews.yoursignup, name='userena_signup'),
url(r'^userena/', include('userena.urls')),

装饰视图

装饰视图就像是覆盖一个视图,但重用外部应用的视图。基本上,它与覆盖视图相同(请参见上文),但您的视图将如下所示

from userena import views as userena_views

def yoursignup(request):
    # do stuff before userena signup view is called

    # call the original view
    response = userena_views.signup(request)

    # do stuff after userena signup view is done

    # return the response
    return response

复刻一个应用程序

如果您不熟悉pip和virtualenv,请先阅读有关使用pip和virtualenv的帖子。

例如:

  • 你以这样的方式安装了django-userena:pip install django-userena
  • 首先应该卸载它:pip uninstall django-userena
  • 然后转到应用程序的github页面
  • 点击fork按钮
  • 这将使你拥有一个具有django-userena副本的代码库
  • 安装它的方法如下:pip install -e git+git@github.com:your-username/django-userena.git#egg=django-userena
  • 然后,您可以在yourenv/src/django-userena中编辑代码
  • 推送您的提交

感谢帖子作者!


这是一篇非常有帮助的文章,正是我所需要的! - interDist
覆盖模板:似乎还需要一件事情:在INSTALLED_APPS中,你的应用程序(带有更改的模板)应该排在第三方应用程序(带有原始模板)之前。 - mirek

0

我认为实现你所需的最简洁的方法是fork django-registration,并在你的应用程序中使用fork而不是原始项目。

话虽如此,在django-registration中可以实现非电子邮件注册,而不必更改应用程序的代码。我通过创建一个自定义 注册后端来完成这个过程,该后端在创建时将用户设置为激活状态。在这里你可以看到其他实现相同功能的方法。


对的,我所做的更改正是Lionel在你链接的问题的解决方案中所做的。 通过分叉,您的意思是(以某种方式)创建自己的django-registration分支,并在那里进行更改吗?我对Mercurial也很陌生,不确定我是否可以在第三方存储库上创建自己的分支,而且听起来有点过度。 我想,在我的项目中具有这些更改的本地应用程序将以更简单的方式实现相同的结果,尽管可能不太明确。 - xuloChavez
开源共享网站,如bitbucket和GitHub提供了一个选项来创建一个分支(就像你说的主项目的一个分支)。这只需要几个点击就可以完成。虽然可能有些过度,但我个人认为这比将整个应用程序复制到不相关的项目中要简单得多。此外,考虑到您可能希望在其他应用程序中使用相同的更改,并且希望避免每次都复制和粘贴修改后的应用程序。 - Facundo Olano
我刚试了一下,确实只需要几个点击:进入原始存储库,点击“分叉”,添加您的描述,然后您就可以在您的帐户下拥有存储库的“副本”,在那里您可以进行更改并提交。我猜您也可以轻松地合并来自主干的任何更改。是的,这绝对是一个更好的解决方案,谢谢! - xuloChavez
然而,您如何在存储库中指示主项目需要特定应用程序的分支?(我猜我也可以问一般如何指示需要特定应用程序)。我想,为此,最好将应用程序复制到您的项目中,但我猜这样您就失去了与原始第三方存储库的连接。 - xuloChavez
你可以从存储库URL中进行pip安装。我看到了在主项目中有一个requirements.txt的模式,其中包含用于安装依赖项(应用程序名称或存储库URL)的pip命令列表。您应该与virtualenv一起使用此功能或检查其他方法;我认为这并不会影响分叉或复制第三方应用程序的问题。 - Facundo Olano

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接