从对象实例生成Django ORM代码(非常适合测试)
项目描述
Django-Modeler
Django-modeler从对象实例生成ORM代码,可选地包括外键依赖。
示例
$ django-modeler myapp.testmodel
from myapp.models import TestModel
from django.contrib.auth.models import User
from decimal import Decimal
import datetime
user1, created = User.objects.get_or_create(
id=1,
username=u'mike',
first_name=u'',
last_name=u'',
email=u'mike@localhost.com',
password=u'sha1$911c9$614a16c3c074f2972e14efbe97f4fa92b266b93f',
is_staff=True,
is_active=True,
is_superuser=True,
last_login=datetime.datetime(2011, 8, 18, 20, 39, 14, 352576),
date_joined=datetime.datetime(2011, 8, 18, 20, 39, 14, 352576),
)
testmodel1, created = TestModel.objects.get_or_create(
id=1,
user=user1,
)
如请求,modeler找到了TestModel实例并生成了ORM代码以重新创建它(如果尚未存在)。Modeler还生成了User对象的代码,因为它被TestModel引用。
为什么?
这是一个包含测试数据的更好方式。您可能已经有一个正在运行的站点和一些用于生产的测试数据,但“dumpdata”会序列化整个应用程序的数据。这只是为了写一个快速测试而太多!
许多人最终在他们的测试固定中有一个过时的、不再更新的生产数据副本,没有人敢更改。由于固定与站点更改保持同步很困难,因此看到大量测试依赖于相同的固定很常见。有时整个项目将仅依赖于一个或两个固定。
不幸的是,如果重构需要由于模型更改而更改固定,则更改固定可能会使与重构无关的其他测试失败。更糟糕的是,直接编辑json很困难,加载和修改它很繁琐,重构工具不会更新固定。
因此,最好是让每个测试使用与其项目中的其他应用程序无关的自己的数据。Django-modeler通过生成可以包含在测试中(或用于其他目的)的Django ORM代码来使这更容易处理。
安装
要获得这个令人惊叹的软件,请使用pip install django-modeler
或从源代码使用python setup.py install
。
用法
Modeler支持一些命令行选项
Usage: manage.py modeler [options] <model [filter option] [filter option] ...>
Writes data to ORM code to the console
Options:
-v VERBOSITY, --verbosity=VERBOSITY
Verbosity level; 0=minimal output, 1=normal output,
2=all output
--settings=SETTINGS The Python path to a settings module, e.g.
"myproject.settings.main". If this isn't provided, the
DJANGO_SETTINGS_MODULE environment variable will be
used.
--pythonpath=PYTHONPATH
A directory to add to the Python path, e.g.
"/home/djangoprojects/myproject".
--traceback Print traceback on exception
-f FILTER, --filter=FILTER
Filter objects
-e EXCLUDE, --exclude=EXCLUDE
Exclude objects
-r RELATED, --related=RELATED
number of object relationship levels to pull (does not
resolve circular references).
--exclude-related=EXCLUDE_RELATED
exclude a package or specific model when searching for
related objects (format: app_label or app_label.model)
--exclude-field=EXCLUDE_FIELD
exclude field types from ever appearing in output
(format: app_label or app_label.model)
--version show program's version number and exit
-h, --help show this help message and exit
最重要的是模型的名称。模型器从对象实例开始,并从这个点构建依赖关系树。树可以有多个起点,也可以从一个单独的实例开始。使用-f
过滤器筛选单个对象是最简单的方法。例如
$ django-modeler auth.user -f pk=1
from django.contrib.auth.models import User
from decimal import Decimal
import datetime
user1, created = User.objects.get_or_create(
id=1,
username=u'mike',
first_name=u'',
last_name=u'',
email=u'mike@localhost.com',
password=u'sha1$911c9$614a16c3c074f2972e14efbe97f4fa92b266b93f',
is_staff=True,
is_active=True,
is_superuser=True,
last_login=datetime.datetime(2011, 8, 18, 20, 39, 14, 352576),
date_joined=datetime.datetime(2011, 8, 18, 20, 39, 14, 352576),
)
-f filter
和-e exclude
选项直接传递给Django的ORM过滤器方法和排除方法上的QuerySet
,并支持相同的选项。
使用-r related
选项,模型器将尝试在其输出中使用外键引用。在上面的示例中,仅通过拉取auth.user实例就找到了一个要序列化的对象。但是,如果给相同的命令加上1个相关深度,模型器将找到更多引用此特定用户实例的对象。
$ django-modeler auth.user -f pk=1 -r1
from django.contrib.auth.models import User
from myapp.models import TestModel
from decimal import Decimal
import datetime
user1, created = User.objects.get_or_create(
id=1,
username=u'mike',
first_name=u'',
last_name=u'',
email=u'mike@localhost.com',
password=u'sha1$911c9$614a16c3c074f2972e14efbe97f4fa92b266b93f',
is_staff=True,
is_active=True,
is_superuser=True,
last_login=datetime.datetime(2011, 8, 18, 20, 39, 14, 352576),
date_joined=datetime.datetime(2011, 8, 18, 20, 39, 14, 352576),
)
testmodel1, created = TestModel.objects.get_or_create(
id=1,
user=user1,
)
使用-r2
,模型器将找到在上述示例中依赖于TestModel的另一个对象实例
$ django-modeler auth.user -f pk=1 -r2
from myapp.models import RelatedToTestModel
from django.contrib.auth.models import User
from myapp.models import TestModel
from decimal import Decimal
import datetime
user1, created = User.objects.get_or_create(
id=1,
username=u'mike',
first_name=u'',
last_name=u'',
email=u'mike@localhost.com',
password=u'sha1$911c9$614a16c3c074f2972e14efbe97f4fa92b266b93f',
is_staff=True,
is_active=True,
is_superuser=True,
last_login=datetime.datetime(2011, 8, 18, 20, 39, 14, 352576),
date_joined=datetime.datetime(2011, 8, 18, 20, 39, 14, 352576),
)
testmodel1, created = TestModel.objects.get_or_create(
id=1,
user=user1,
)
relatedtotestmodel1, created = RelatedToTestModel.objects.get_or_create(
id=1,
test_model=testmodel1,
name=u'related_one',
)
relatedtotestmodel2, created = RelatedToTestModel.objects.get_or_create(
id=2,
test_model=testmodel1,
name=u'related_two',
)
其他选项是--exclude-related
和--exclude-field
。这两个选项都需要app_label.model参数。排除相关将忽略在搜索外键关系时找到的与app_label或模型名称匹配的模型,例如在上面的示例中,在相关搜索期间找到了TestModel和RelatedToTestModel。
使用--exclude-field
可以阻止模型或应用在任何时候出现在输出中,无论它是如何被找到的。
限制
目前,当使用-r
时,模型器不尝试解决循环依赖关系。可能需要限制模型器将旅行的深度,以避免由于模型依赖关系而导致异常。
我能用它做什么?
原始用例是创建测试数据。使用模型器在测试文件夹中创建一个data.py
文件
$ django-modeler auth.user -f pk=1 -r2 > tests/data.py
data.py
可能需要load()
方法。这些tests
是这种使用方式的良好示例。
接下来,在需要此数据的测试中,添加一个setupUp方法来加载和使用数据
def setUp(self):
data.load()
支持
请使用Github。