Django で model.Manager.create() メソッドをオーバーライドするにはどうすればいいですか? 質問する

Django で model.Manager.create() メソッドをオーバーライドするにはどうすればいいですか? 質問する

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が、どうもうまくいきません。やりたいことを実行できないのはなぜでしょうか?

ベストアンサー1

からの洞察アラスデアの回答は、文字列と Unicode 文字列の両方をキャッチするのに大いに役立ちましたが、実際に欠けていたのは、メソッド内のreturnの呼び出しの前のステートメントでした。super(HardwareManager, self).create(*args, **kwargs)HardwareManager.create()

昨日の夕方のテストで発生したエラー (コーディング中に疲れるのは得策ではありません :P) は、メソッドに がなかったためにdを使用したValueError: Cannot assign None: [...] does not allow null values.後の が原因でした。なんて愚かなミスでしょう !new_hdcreate()Nonecreate()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)   

おすすめ記事