我有很多Hardware
模型,其HardwareType
具有各种特征。像这样:
# models.py
from django.db import models
class HardwareType(model.Models):
name = models.CharField(max_length=32, unique=True)
# some characteristics of this particular piece of hardware
weight = models.DecimalField(max_digits=12, decimal_places=3)
# and more [...]
class Hardware(models.Model):
type = models.ForeignKey(HardwareType)
# some attributes
is_installed = models.BooleanField()
location_installed = models.TextField()
# and more [...]
如果我想添加一个新的Hardware
对象,我首先必须每次检索HardwareType
,这不是很干:
tmp_hd_type = HardwareType.objects.get(name='NG35001')
new_hd = Hardware.objects.create(type=tmp_hd_type, is_installed=True, ...)
因此,我尝试覆盖HardwareManager.create()
方法,以便在创建新Hardware
时自动导入类型,如下所示:
# models.py
from django.db import models
class HardwareType(model.Models):
name = models.CharField(max_length=32, unique=True)
# some characteristics of this particular piece of hardware
weight = models.DecimalField(max_digits=12, decimal_places=3)
# and more [...]
class HardwareManager(models.Manager):
def create(self, *args, **kwargs):
if 'type' in kwargs and kwargs['type'] is str:
kwargs['type'] = HardwareType.objects.get(name=kwargs['type'])
super(HardwareManager, self).create(*args, **kwargs)
class Hardware(models.Model):
objects = HardwareManager()
type = models.ForeignKey(HardwareType)
# some attributes
is_installed = models.BooleanField()
location_installed = models.TextField()
# and more [...]
# so then I should be able to do:
new_hd = Hardware.objects.create(type='ND35001', is_installed=True, ...)
但是我一直在从ORM中得到错误和非常奇怪的行为(我没有在这里,但如果需要我可以发布它们)。我在Django文档和SO线程中搜索过,但大多数时候我最终得到的解决方案是:
Hardware.save()
方法(我应该在那里获得HardwareType
吗?)或create_something
方法,该方法调用self.create()
。我也开始深入挖掘代码并发现Manager
是一种特殊的QuerySet
,但我不知道如何从那里继续。我真的想替换create
方法,我似乎无法管理它。什么阻止我做我想做的事?
答案 0 :(得分:3)
来自Alasdair的答案的见解有助于捕获字符串和unicode字符串,但在调用return
之前,实际上缺少的是super(HardwareManager, self).create(*args, **kwargs)
语句在HardwareManager.create()
方法中。
昨天晚上我在测试中遇到的错误(在编码时感到厌倦不是一个好主意:P)是ValueError: Cannot assign None: [...] does not allow null values.
,因为我new_hd
的后续使用create()
d为None
,因为我的create()
方法没有return
。多么愚蠢的错误!
最终更正的代码:
class HardwareManager(models.Manager):
def create(self, *args, **kwargs):
if 'type' in kwargs and isinstance(kwargs['type'], basestring):
kwargs['type'] = HardwareType.objects.get(name=kwargs['type'])
return super(HardwareManager, self).create(*args, **kwargs)
答案 1 :(得分:2)
如果没有看到追溯,我认为问题出在这一行上。
if 'type' in kwargs and kwargs['type'] is str:
这是检查kwargs['type']
是否与str
是同一个对象,它始终是假的。
在Python 3中,要检查`kwargs ['type']是否为字符串,您应该这样做:
if 'type' in kwargs and isinstance(kwargs['type'], str):
如果您使用的是Python 2,则应使用basestring
来捕获字节字符串和unicode字符串。
if 'type' in kwargs and isinstance(kwargs['type'], basestring):
答案 2 :(得分:1)
我正在研究与您相同的问题,并决定不使用覆盖。
就我而言,考虑到我的限制,仅使用另一种方法更有意义。
class HardwareManager(models.Manager):
def create_hardware(self, type):
_type = HardwareType.objects.get_or_create(name=type)
return self.create(type = _type ....)