【问题标题】:Version number in Django applicationsDjango 应用程序中的版本号
【发布时间】:2013-01-13 11:01:37
【问题描述】:

我正在开发一个 Django 应用程序,我想显示应用程序的版本(以便发现错误的人知道应用程序的版本并可以提供更好的错误报告)。

是否有一种普遍接受的方式在 Django 中存储版本号(我的意思是我的应用程序的版本,而不是 Django)?

【问题讨论】:

标签: django


【解决方案1】:

有很多地方可以存储您的应用程序版本号以及一些允许您在 django 模板中显示它的方法。很大程度上取决于您使用的发布工具和您自己的偏好。

以下是我在当前项目中使用的方法。

将版本号放入version.txt

我将应用版本号存储在 version.txt 文件中。这是zest.releaser 发布工具(我正在使用)在发布时考虑的位置之一。

version.txt的全部内容就是应用的版本号,例如:1.0.1.dev0

将数字读入settings.py中的变量

...    
with open(version_file_path) as v_file:
    APP_VERSION_NUMBER = v_file.read()
...

创建自定义上下文处理器

本段及以下内容均基于精彩 answer by bcchunCan I access constants in settings.py from templates in Django?

自定义上下文处理器将允许您将应用版本号添加到每个渲染模板的上下文中。您不必在每次渲染模板时手动添加它(通常您会希望在每个页面的页脚中的某处都有版本号)。

在您的应用目录中创建 context_processors.py 文件:

from django.conf import settings

def selected_settings(request):
    # return the version value as a dictionary
    # you may add other values here as well
    return {'APP_VERSION_NUMBER': settings.APP_VERSION_NUMBER}

将上下文处理器添加到 settings.py

TEMPLATES = [{
    ...
    'OPTIONS': {
        'context_processors': [
            ...
            'your_app.context_processors.selected_settings'
        ],
    },
 }]

在视图中使用 RequestContextrender

RequestContextrender 使用您在 settings.py 中设置的 context_processors 提供的变量填充上下文。

例子:

def some_view(request):
    return render(request, 'content.html')
    

在模板中使用它

...
<div>{% trans 'App version' %}:{{APP_VERSION_NUMBER}}</div>
....

【讨论】:

    【解决方案2】:

    对我来说最好的结果/方法是在项目文件夹中使用__init__.py,例如

    .
    ├── project_name
    │   ├── __init__.py
    

    稍后使用标准方式进行检查,如 (PEP396) 中所述

    >>> import proyect_name
    >>> proyect_name.__version__
    '1.0.0'
    

    【讨论】:

      【解决方案3】:

      如果使用 GIT 进行源代码版本控制,您可能需要手动升级稳定版 发布和开发提交的自动编号。

      为什么要在 Django 项目中获得它的一个原因是:

      在“PROJECT/_ init _.py”中定义:

      __version__ = '1.0.1'
      __build__ = ''
      

      然后在setting.py中做:

      import os
      import subprocess
      import PROJECT
      
      BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
      
      try:
          PROJECT.__build__ = subprocess.check_output(["git", "describe", "--tags", "--always"], cwd=BASE_DIR).decode('utf-8').strip()
      except:
          PROJECT.__build__ = PROJECT.__version__ + " ?"
      

      因此,PROJECT._ build _ 将显示:

      v1.0.1 in stable releases
      

      v1.0.1-N-g8d2ec45 
      

      当最近的标签不指向最后一次提交时(其中N计算标签后的额外提交次数,后跟提交签名)

      【讨论】:

      • 优雅,我喜欢这个。感谢分享。
      • 没有strip(),由于某种原因,我得到了一个尾随换行符,但没有检查原因。我会尝试"--always" 选项,听起来很合理。谢谢。
      • mmhhh ... 有趣 ... strip() 添加!更好的安全然后抱歉,谢谢@Dário
      • 我喜欢这个答案,但我需要将第一个 abspath 替换为 dirname 才能正常工作
      • 谢谢@deMangler。在我的项目中,我通常将默认的“settings.py”文件“向下”移动到“project/settings”文件夹(实际上是一个模块)中。这就是为什么我需要调整 BASE_DIR 的定义。我编辑了我的评论以恢复“startproject”命令给出的更常见的表达式。
      【解决方案4】:

      我使用此选项__import__('project').VERSION__import__('project').__version__。正如大家所说,版本放在__init__.py文件中,例如:

      proyect_name
        | __init__.py
      
      # __init__.py file
      VERSION = '1.0.0' # or __version__ = '1.0.0'
      

      现在你可以从任何地方得到它:

      # Error tracking settings
      sentry_sdk.init(
          ...
          release=__import__('cjvc_project').VERSION
      )
      

      【讨论】:

        【解决方案5】:

        版本信息通常保存在 git commit 标签中。否则,即使是 git 提交和上次更新时间也可以很好地指示哪个版本正在运行以及何时部署。

        对于那些使用django-rest-framework并且只有一个API的人,你可以返回这两个;使用/api/version 端点的“最后更新”和“最后 git 提交”:

        views.py:

        import os
        import time
        import subprocess
        import json
        
        class VersionViewSet(ViewSet):
            def list(self, request):
                # ['git', 'describe', '--tags'] # use this for named tags (version etc)
                # ['git', 'describe', '--all', '--long'] # use this for any commit
                # git log -1 --pretty=format:"Last commit %h by %an, %ar ("%s")"
                # {"commit_hash": "%h", "full_commit_hash": "%H", "author_name": "%an", "commit_date": "%aD", "comment": "%s"}
                FILE_DIR = os.path.dirname(os.path.abspath(__file__))
                git_command = ['git', 'log', '-1', '--pretty={"commit_hash": "%h", "full_commit_hash": "%H", "author_name": "%an", "commit_date": "%aD", "comment": "%s"}']
                git_identifier = subprocess.check_output(git_command, cwd=FILE_DIR).decode('utf-8').strip()
                git_identifier = json.loads(git_identifier)
                last_updated = time.strftime('%a, %-e %b %Y, %I:%M:%S %p (%Z)', time.localtime(os.path.getmtime('.git'))).strip()
                return Response({
                    "last_updated": last_updated,
                    "git_commit": git_identifier
                }, status=200)
        

        urls.py:

        from myapp.views import VersionViewSet
        
        router = routers.DefaultRouter()
        ...
        router.register(r'version', VersionViewSet, base_name='version')
        

        这会根据您的 API 中的其他端点创建端点。

        输出将在http://www.example.com/api/version/

        HTTP 200 OK
        Allow: GET, HEAD, OPTIONS
        Content-Type: application/json
        Vary: Accept
        
        {
            "last_updated": "Mon, 6 May 2019, 11:19:58 PM (IST)",
            "git_commit": {
                "commit_hash": "e265270",
                "full_commit_hash": "e265270dda196f4878f4fa194187a3748609dde0",
                "author_name": "Authorname",
                "commit_date": "Mon, 6 May 2019 23:19:51 +0530",
                "comment": "The git commit message or subject or title here"
            }
        }
        

        【讨论】:

          【解决方案6】:

          如果您使用 Git 和版本标记,您可以在管理站点标题中显示应用程序版本。

          在项目或任何应用模块中创建version.py 文件:

          import os
          import subprocess
          
          FILE_DIR = os.path.dirname(os.path.abspath(__file__))
          
          
          def get_version_from_git():
              try:
                  return subprocess.check_output(['git', 'describe', '--tags'],
                                                 cwd=FILE_DIR).decode('utf-8').strip()
              except:
                  return '?'
          
          
          VERSION = get_version_from_git()
          

          将版本添加到urls.py中的管理站点标题:

          from django.contrib import admin
          from django.utils.safestring import mark_safe
          
          from utils import version
          
          ...
          
          admin.site.site_header = mark_safe('MyApp admin <span style="font-size: x-small">'
                                             f'({version.VERSION})</span>')
          

          如果您需要将版本提供给 Django Debug Toolbar 等外部工具,您可以按照上面的建议在项目 __init__.py 中公开版本:

          from utils import version
          
          __version__ = version.VERSION
          VERSION = __version__  # synonym
          

          【讨论】:

            【解决方案7】:

            我使用了上下文处理器,它看起来像这样:

            import sys
            sys.path.append('..')
            
            from content_services import __version__
            
            
            def get_app_version(request):
                """
                Get the app version
                :param request:
                :return:
                """
                return {'APP_VERSION': __version__}
            

            由于项目名称是content_services,我必须将系统路径更改为上一级,以便导入它。

            【讨论】:

              【解决方案8】:

              我一直在寻找这个完全相同的问题,并找到了您的问题。你接受的答案我不太满意。

              我正在使用 django 调试工具栏,您还可以在其中显示使用的应用程序的所有版本。我想知道如何让我的自定义应用程序的版本也显示在那里。

              再看一点,我发现了这个问题和答案: How to check the version of a installed application in Django in running time?

              但是这个答案并没有告诉我把这个__version__放在哪里

              所以我查看了一个打开的应用程序,它确实显示在 django 工具栏中。 我查看了 django restframework 代码,发现:

              版本放在__init__.py文件中

              (见https://github.com/tomchristie/django-rest-framework/blob/master/rest_framework/init.py

              它被放在这里:

              __version__ = '2.2.7'
              VERSION = __version__  # synonym
              

              然后,在他的 setup.py 中,他从 __init__.py 获取这个版本: 见:https://github.com/tomchristie/django-rest-framework/blob/master/setup.py

              像这样:

              import re
              
              def get_version(package):
                  """
                  Return package version as listed in `__version__` in `init.py`.
                  """
                  init_py = open(os.path.join(package, '__init__.py')).read()
                  return re.match("__version__ = ['\"]([^'\"]+)['\"]", init_py).group(1)
              
              version = get_version('rest_framework')
              

              使用 buildout 和 zestreleaser 时:

              顺便说一句,我正在使用 buildout 和 zest.releaser 进行构建和版本控制。

              在这种情况下,上面有点不同(但基本相同的想法):

              http://zestreleaser.readthedocs.org/en/latest/versions.html#using-the-version-number-in-setup-py-and-as-version

              setup.py 中的版本由 setup.py 自动编号,所以在__init__.py 你这样做:

              import pkg_resources
              
              __version__ = pkg_resources.get_distribution("fill in yourpackage name").version
              VERSION = __version__  # synonym
              

              【讨论】:

              • 难道没有比使用正则表达式解析你自己的python代码更好的get_version方法吗?
              【解决方案9】:

              我通过在我的 django 项目中添加一个模板标签解决了这个问题:

              在 proj/templatetags 中,添加了 version.py:

              from django import template
              import time
              import os
              
              register = template.Library()
              
              @register.simple_tag
              def version_date():
                  return time.strftime('%m/%d/%Y', time.gmtime(os.path.getmtime('../.git')))
              

              然后,在我的 base.html(或任何模板)中,添加:

              {% load version %}
              <span class='version'>Last Updated: {% version_date %}</span>
              

              【讨论】:

              • 这是一个非常有趣的答案 - 我喜欢 git 插件。
              • 很好的答案!
              • 我认为这是最好的一个,因为与其他解决方案相反,您不需要修改您的视图(如果您有很多视图,这可能会很麻烦!)。只需更改基本模板,我喜欢它!
              【解决方案10】:

              不是针对 Django 应用程序本身,而是针对 Python 模块,是的。请参阅 PEP 396PEP 386verlib 库 (easy_install verlib)。

              (我会详细说明,但我现在才发现这一点,我自己。)

              【讨论】:

                【解决方案11】:

                似乎设置文件是存储版本号的合理位置。我不相信有任何 Django 接受的方式来存储您的个人应用程序的版本号。这似乎是您应该定义的应用程序特定变量。

                有关从 svn 中获取版本号的更多信息:Getting SVN revision number into a program automatically

                【讨论】:

                  猜你喜欢
                  • 2023-01-30
                  • 2011-09-25
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2019-03-25
                  • 1970-01-01
                  • 2014-07-29
                  • 1970-01-01
                  相关资源
                  最近更新 更多