【发布时间】:2013-01-13 11:01:37
【问题描述】:
我正在开发一个 Django 应用程序,我想显示应用程序的版本(以便发现错误的人知道应用程序的版本并可以提供更好的错误报告)。
是否有一种普遍接受的方式在 Django 中存储版本号(我的意思是我的应用程序的版本,而不是 Django)?
【问题讨论】:
标签: django
我正在开发一个 Django 应用程序,我想显示应用程序的版本(以便发现错误的人知道应用程序的版本并可以提供更好的错误报告)。
是否有一种普遍接受的方式在 Django 中存储版本号(我的意思是我的应用程序的版本,而不是 Django)?
【问题讨论】:
标签: django
有很多地方可以存储您的应用程序版本号以及一些允许您在 django 模板中显示它的方法。很大程度上取决于您使用的发布工具和您自己的偏好。
以下是我在当前项目中使用的方法。
我将应用版本号存储在 version.txt 文件中。这是zest.releaser 发布工具(我正在使用)在发布时考虑的位置之一。
version.txt的全部内容就是应用的版本号,例如:1.0.1.dev0
...
with open(version_file_path) as v_file:
APP_VERSION_NUMBER = v_file.read()
...
本段及以下内容均基于精彩 answer by bcchun 至 Can 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}
TEMPLATES = [{
...
'OPTIONS': {
'context_processors': [
...
'your_app.context_processors.selected_settings'
],
},
}]
RequestContext 或 render
RequestContext 和 render 使用您在 settings.py 中设置的 context_processors 提供的变量填充上下文。
例子:
def some_view(request):
return render(request, 'content.html')
...
<div>{% trans 'App version' %}:{{APP_VERSION_NUMBER}}</div>
....
【讨论】:
对我来说最好的结果/方法是在项目文件夹中使用__init__.py,例如
.
├── project_name
│ ├── __init__.py
稍后使用标准方式进行检查,如 (PEP396) 中所述
>>> import proyect_name
>>> proyect_name.__version__
'1.0.0'
【讨论】:
如果使用 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" 选项,听起来很合理。谢谢。
我使用此选项__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
)
【讨论】:
版本信息通常保存在 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"
}
}
【讨论】:
如果您使用 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
【讨论】:
我使用了上下文处理器,它看起来像这样:
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,我必须将系统路径更改为上一级,以便导入它。
【讨论】:
我一直在寻找这个完全相同的问题,并找到了您的问题。你接受的答案我不太满意。
我正在使用 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 进行构建和版本控制。
在这种情况下,上面有点不同(但基本相同的想法):
setup.py 中的版本由 setup.py 自动编号,所以在__init__.py 你这样做:
import pkg_resources
__version__ = pkg_resources.get_distribution("fill in yourpackage name").version
VERSION = __version__ # synonym
【讨论】:
get_version方法吗?
我通过在我的 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>
【讨论】:
似乎设置文件是存储版本号的合理位置。我不相信有任何 Django 接受的方式来存储您的个人应用程序的版本号。这似乎是您应该定义的应用程序特定变量。
有关从 svn 中获取版本号的更多信息:Getting SVN revision number into a program automatically
【讨论】: