繁体   English   中英

如何覆盖 Django 中的 model.Manager.create() 方法?

[英]How to override the model.Manager.create() method in Django?

我有很多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 ,这不是很 DRY:

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方法,但我似乎无法管理这个。 是什么阻止我做我想做的事?

从Insight麦金太尔的回答帮了不少忙赶上两个字符串和Unicode字符串,但什么是真正缺少的是一个return调用之前声明super(HardwareManager, self).create(*args, **kwargs)HardwareManager.create()方法。

昨天晚上我在测试中遇到的错误(在编码不是一个好主意时感到疲倦:P)是ValueError: Cannot assign None: [...] does not allow null values. 因为我create() d 的new_hd的后续使用是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)   

没有看到回溯,我认为问题出在这条线上。

    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):

我正在研究与您相同的问题,并决定不使用覆盖。

在我的情况下,考虑到我的限制,仅使用另一种方法更有意义。

class HardwareManager(models.Manager):
    def create_hardware(self, type):
        _type = HardwareType.objects.get_or_create(name=type)
        return self.create(type = _type ....)  

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM