Как переопределить модель.Менеджер.метод create () в 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 каждый раз, который не очень сухой:

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, но в основном я заканчиваю на решениях, где:

  • the Hardware.save() метод переопределен (должен ли я получить HardwareType есть ?) или
  • менеджер определяет новый create_something метод, который называет self.create().

я также начал копаться в коде и увидел, что Manager это какой-то особый вид QuerySet но я не знаю как продолжить оттуда. Я бы очень хотел заменить create метод на месте, и я не могу с этим справиться. Что мешает мне делать то, что я хочу сделать?

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

представление от Аласдерответ очень помог поймать как строки, так и строки unicode, но на самом деле не хватало return оператор перед вызовом super(HardwareManager, self).create(*args, **kwargs) на HardwareManager.create() метод.

ошибки, которые я получал в своих тестах вчера вечером (устал, Когда кодирование не является хорошей идеей: P) были ValueError: Cannot assign None: [...] does not allow null values. потому что последующее использование new_hd что у меня было create()д 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)