Мы активно используем собственные батарейки для
Django. Вот типичная структура одной:
scr — корень
Python пакета (как для
PyPi)
dvhb_docs — сама батарейка
testproject — минимальный проект Django для тестирования батарейки
Пример
setup.py:# -*- coding: utf-8 -*-
import os
from distutils.core import setup
__version__ = "0.1.0"
README = open(os.path.join(os.path.dirname(__file__), 'README.md')).read()
os.chdir(os.path.normpath(os.path.join(os.path.abspath(__file__), os.pardir)))
tests_require = [
'Django>=1.5',
'model-mommy',
'south',
'pyelasticsearch',
'elasticsearch',
'django-haystack>=2.1.0',
'djangorestframework',
'django-appconf',
'webtest',
'django-webtest',
'django-celery',
'django-mptt'
]
setup(
name='dvhb_docs',
version=__version__,
packages=['dvhb_docs'],
include_package_data=True,
license='private',
description='Django application for document store and management.',
long_description=README,
url='https://github.com/dvhb/dvhb_docs',
author='Vadim Lopatyuk',
author_email='qnub@example.com',
classifiers=[
'Environment :: Web Environment',
'Framework :: Django',
'Intended Audience :: Developers',
'Operating System :: OS Independent',
'Programming Language :: Python',
'Programming Language :: Python :: 2.7',
'Topic :: Internet :: WWW/HTTP',
'Topic :: Internet :: WWW/HTTP :: Dynamic Content',
],
install_requires=[
'Django>=1.5',
'south',
'pyelasticsearch',
'elasticsearch',
'django-haystack>=2.1.0',
'djangorestframework',
'django-appconf',
'django-celery',
'django-mptt'
],
)
MANIFEST.in
recursive-include dvhb_docs *.py *.html *.css *.js *.gif *.png *.jpg *.xap *.swf
requirements.txt файл зависимостей для виртуального окружения — по желанию (там можно включать что-то для разработки пакета, что нет смысла указывать в
setup.py).
К слову новая (после 1.4) структура проекта Django способствует удобному отделению батареек. Т.е. testproject может быть обычным Вашим проектом и на том же уровне каталога будут лежать разрабатываемые модули, которые потом удаляются и ставятся уже из репозитория.
В миграции
South надо вносить правки в слепок таблиц, чтобы не было конфликтов с кастомными моделями пользователей. Если нет каких-то хитрых действий с юзером то типичную версию:
{
…
u'auth.user': {
'Meta': {'object_name': 'User'},
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Group']"}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Permission']"}),
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
}
}
мы меняем на:
from django.conf import settings
…
{
…
settings.AUTH_USER_MODEL.lower(): {
'Meta': {'object_name': settings.AUTH_USER_MODEL.split('.')[-1]},
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
}
}
А всякие указания на неё в ключах других моделей вроде:
'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'author'", 'blank': 'True', 'to': "orm['auth.User']"}),
на:
'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'author'", 'blank': 'True', 'to': u"orm['{0}']".format(settings.AUTH_USER_MODEL)}),
Ну и последнее, ставим мы их таким образом (теперь мы работаем со своим
GitLab, но для примера приведу
GitHub):
pip install git+ssh://git@github.com/dvhb/dvhb_docs.git@0.1.0#egg=dvhb_docs==0.1.0
Тут есть пара нюансов:
git+ssh://git@github.com/dvhb/dvhb_docs.git — линк для установки пакета с помощью
pip из
git (отличается от обычного линка на репу для самого git:
git@github.com:dvhb/dvhb_docs.git).
@0.1.0 — это обычный
tag в
git репозитории. Так можно устанавливать необходимую версию пакета.
#egg=dvhb_docs==0.1.0 — это то, как пакет будет предствален в окружении
python. Т.е. в этом случае он будет записан как
dvhb_docs версии
0.1.0.
В начале мы пытались и юзерский фронтенд засовывать в батарейку, но он очень сильно меняется от случая к случаю в итоге с этой затеей завязали и стали просто делать общие библиотеки на
JS, которые ставятся через
Bower (по аналогии с питоноим). Остальные нюансы уже дописываются в самом проекте.