You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用pytest将含预定义主键的Status模型fixture加载至Django测试数据库?

在pytest中加载Django遗留fixture数据的方案

背景

我维护一段遗留代码,其中Status模型的初始数据(含预定义主键)存储在status_data.json文件中,可通过python manage.py loaddata <fixturename>命令加载,数据示例:

{
        "model": "status.Status",
        "pk":4,
        "fields": {
            "item": "Achat",
            "table": "billing_models",
            "attribute": "status_billing_models"
          }
}

部分模型与Status模型存在外键关联,且Status的主键为静态值,示例代码:

class BillingModel(Timestemps, SafeDeleteModel):
    ACHAT = 4
    ACTIVATION = 5

    name = models.CharField(max_length=200)
    # ... 更多字段

    # achat or activation
    cycle_start_at = models.ForeignKey(Status, models.CASCADE)

需要编写该遗留代码的测试,实现通过pytest将这些初始数据加载到Django测试数据库,以便基于该数据编写测试用例。


方法1:测试用例内手动加载

借助pytest-django的django_db标记确保测试能访问数据库,直接调用Django的loaddata命令加载指定fixture:

from django.core.management import call_command
import pytest

@pytest.mark.django_db
def test_billing_model_association():
    # 加载status_data.json中的预设数据
    call_command('loaddata', 'status_data.json')
    
    # 基于已加载的Status数据编写测试逻辑
    from myapp.models import BillingModel, Status
    achat_status = Status.objects.get(pk=BillingModel.ACHAT)
    test_billing = BillingModel.objects.create(
        name="测试账单模型",
        cycle_start_at=achat_status
    )
    assert test_billing.cycle_start_at.item == "Achat"

方法2:全局Fixture自动加载

如果多个测试用例都依赖这些初始数据,可在项目根目录的conftest.py中定义一个fixture,实现自动或按需加载:

自动加载(所有测试执行前加载)

# conftest.py
import pytest
from django.core.management import call_command

@pytest.fixture(autouse=True)
def load_default_statuses(django_db_blocker):
    with django_db_blocker.unblock():
        call_command('loaddata', 'status_data.json')

按需加载(仅在测试显式引用时加载)

# conftest.py
import pytest
from django.core.management import call_command

@pytest.fixture
def status_fixture(django_db_blocker):
    with django_db_blocker.unblock():
        call_command('loaddata', 'status_data.json')

使用时在测试用例中显式声明:

@pytest.mark.django_db
def test_status_existence(status_fixture):
    from myapp.models import Status
    assert Status.objects.filter(pk=4).exists()

方法3:通过pytest标记指定加载

先确保fixture文件放在Django识别的目录中:

  1. 在项目根目录创建fixtures文件夹
  2. 在settings.py中添加配置:
FIXTURE_DIRS = [
    BASE_DIR / 'fixtures',
]

然后在测试用例中通过标记直接指定要加载的fixture:

import pytest

@pytest.mark.django_db(fixtures=['status_data'])
def test_billing_status_link():
    from myapp.models import BillingModel, Status
    assert Status.objects.get(pk=BillingModel.ACHAT).table == "billing_models"

注意事项

  • 由于Status主键是预定义的静态值,测试中创建关联模型时,优先使用模型类中定义的常量(如BillingModel.ACHAT),避免硬编码数字,提升代码可维护性。
  • 若fixture文件不在默认识别路径,可在call_command中传入完整文件路径,比如call_command('loaddata', '/path/to/status_data.json')。

内容的提问来源于stack exchange,提问作者khelalfa rabah

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 01:32:55