python - Django 管理员和 on_delete=PROTECTED 的单元测试之间的结果不一致
问题描述
我正在 Django 中制作一个“简单”的零件库存应用程序。
我有这个作为我的models.py。
from django.db import models
# Create your models here.
class Site(models.Model):
create_date = models.DateField(auto_now_add=True)
name = models.TextField(max_length=150, null=False, unique=True, verbose_name="Site name")
update_date = models.DateField(auto_now=True)
def __str__(self):
return self.name
class Location(models.Model):
create_date = models.DateField(auto_now_add=True)
name = models.TextField(max_length=150, null=False, unique=False)
site = models.ForeignKey(Site, null=False, on_delete=models.PROTECT)
update_date = models.DateField(auto_now=True)
@property
def site_name(self):
try:
return self.site.name
except Exception as ex:
return 'Unknown'
def __str__(self):
return self.name
class Part(models.Model):
create_date = models.DateField(auto_now_add=True)
name = models.TextField(max_length=150, null=False, unique=True)
verbose_name = models.TextField(max_length=150, null=True)
update_date = models.DateField(auto_now=True)
def __str__(self):
return self.name
class PartLocation(models.Model):
create_date = models.DateField(auto_now_add=True)
location = models.ForeignKey(Location, null=False, on_delete=models.PROTECT)
number_of_parts = models.IntegerField(null=False)
part = models.ForeignKey(Part, null=False, on_delete=models.PROTECT)
update_date = models.DateField(auto_now=True)
@property
def site(self):
try:
return self.location.site.name
except Exception as ex:
return 'Unknown'
def __str__(self):
return f'{self.part.name}/{self.location.name}/{self.site}/{self.number_of_parts}'
我添加了一个如下所示的 admin.py:
from django.contrib import admin
from .models import Location, Part, PartLocation, Site
class PartLocationAdmin(admin.ModelAdmin):
ordering = ('id', 'location', 'part', 'location__site__name', 'number_of_parts',)
list_display = ('id', 'part', 'get_part_verbose_name', 'location', 'site', 'number_of_parts',)
list_filter = ('id', 'part', 'location', 'location__site__name', 'number_of_parts',)
search_fields = ('id', 'part__name', 'location__name', 'location__site__name', 'number_of_parts',)
def get_part_verbose_name(self,obj):
if obj.part.verbose_name is None:
return "-"
return obj.part.verbose_name
get_part_verbose_name.command_order_field = 'Verbose name' #Allows column order sorting
get_part_verbose_name.short_description = 'Verbose name' #Renames column head
class LocationAdmin(admin.ModelAdmin):
ordering = ('id', 'name', 'site',)
list_display = ('id', 'name', 'site',)
search_fields = ('id', 'name', 'site__name',)
class PartAdmin(admin.ModelAdmin):
ordering = ('id', 'name', 'verbose_name')
list_display = ('id', 'name', 'verbose_name')
search_fields = ('id', 'name', 'verbose_name')
# Register your models here.
admin.site.register(Site)
admin.site.register(Location, LocationAdmin)
admin.site.register(Part, PartAdmin)
admin.site.register(PartLocation, PartLocationAdmin)
我在我的tests.py中添加了单元测试:
from django.test import TestCase, TransactionTestCase
import django.db.utils
from .models import Location, Part, PartLocation, Site
from django.db.models import ProtectedError
class ModelTestCases(TransactionTestCase):
def add_and_delete(self):
'''
In this test we will add a site, location, part and partlocation information into the database.
Then we will ensure that one cannot delete a site until all sub records have also been deleted.
:return:
'''
# Let's create a site.
site_1 = Site.objects.create(name='site_1')
# Let's demostrate that you cannot create a location without a cite.
try:
loc_1 = Location.objects.create(name='loc_1')
except django.db.utils.IntegrityError as ex:
self.assertEqual('null value in column "site_id" violates not-null constraint', ex.args[0].split('\n')[0])
# Create a Location at site_1
loc_1 = Location.objects.create(name='loc_1', site=site_1)
# Create a Part
part_1 = Part.objects.create(name='part_1', verbose_name='Part One')
# Let's add inventory or part_1 in loc_1.
part_loc_1 = PartLocation(location=loc_1, part=part_1, number_of_parts=5)
# Let's demostrate that one cannot remove site_1 because it has a location.
try:
site_1.delete()
self.fail('Deletion of site not prevented.')
except ProtectedError as ex:
pass
# Let's demostrate that one cannot remove loc_1 because it has a PartLocation record.
try:
loc_1.delete()
self.assertEqual(0, Location.objects.count())
self.fail('Deletion of location not prevented.')
except ProtectedError as ex:
pass
如果我在管理面板中转到我的位置列表,我会看到这个......
...然后我单击“开始”按钮删除所选位置,我看到:
这是我想要的行为。但是我的单元测试允许删除包含部分的位置并引发此错误。
AssertionError: Deletion of location not prevented.
为什么我的管理代码阻止删除而我的单元测试却没有?
我的 Django 版本是:
django.VERSION
(2, 1, 7, 'final', 0)
解决方案
哦!我总是犯这个错误!在我的单元测试中,我有这个:
part_loc_1 = PartLocation(location=loc_1, part=part_1, number_of_parts=5)
当我应该写这个时:
part_loc_1 = PartLocation.objects.create(location=loc_1, part=part_1, number_of_parts=5)
推荐阅读
- typescript - 我希望有一个匹配每一种联合类型的类型,但不是这些单一类型的任何联合
- r - 如何在运行时向用户询问一个整数,并递归地再次询问您是否没有得到一个?
- javascript - Nodejs express promise.all().then() 不是同步的
- ansible - 在ansible中从另一个检索变量
- java - Tomcat v9.0 服务器在 Eclipse 中启动错误
- chart.js - 两个图表的图表数据都没有更新?
- python - 修复硬币变化蛮力解决方案
- javascript - 数据表和行组的问题 - 不会折叠/展开超过 2 个组
- typescript - 在 hexToRgba 转换中按位替换
- javascript - 尽管图像大小相同,但具有相同宽度和高度的产品框