获取任何实例(如果存在)或为抽象模型的任何子代创建新实例

时间:2018-12-10 15:32:07

标签: django django-models

我发现自己反复查找符合某些条件的记录,如果不存在,则创建符合这些条件的新记录。 基本上可以使用get_or_create()方法,但是如果存在多个这样的记录,它将失败。

我经常这样做,以至于我不想全都写同样的代码,而是为此使用一些简单的功能

我所有的模型都是从一个抽象的BaseModel派生的,因此在那里实现方法get_first_or_create似乎是合乎逻辑的,然后该方法将返回满足给定条件的实际模型的对象。如果有更多这样的对象,它将返回其中任何一个。它还可以在一处处理所有异常检查和一些其他常见的东西。

我不知道如何在BaseModel中创建它。像

class BaseModel(models.model):
  active = models.BooleanField(default=True)
  ...
  class Meta:
    abstract = True
  def get_first_or_create(*args,**kwargs):
    retval=ChildModel.objects.filter(*args,**kwargs).first()
    # ChildModel is ofcourse wrong, but what to use?
    if retval:
       return retval
    else:
       retval = ChildModel(*args,**kwargs)
       retval.save()
       return retval
    # actually make more Exceptions/sanity/whatever checks here
    # but this is core of the idea

class Car(BaseModel):
   name = models.TextField(blank=True)
   color = models.TextField(blank=True)
   ...
class Animal(BaseModel):
   cute=models.BooleanField(default=True)
   ...

然后调用这样的内容:

# lets get some blue car and cute pet, I do not care which one,
# just ANY one would be good
some_blue_car=Car.get_first_or_create(color="blue")
some_cute_pet=Animal.get_first_or_create(cute=True)

是否可以这样做,或者我完全错了,应该采取什么其他方法?


解决方案

这对我有用:)

class MyManager(models.Manager):  # Stolen from get_or_create() and modified
    def get_first_or_create(self, defaults=None, **kwargs):
        """
        Look up an object with the given kwargs, creating one if necessary.
        Return a tuple of (object, created), where created is a boolean
        specifying whether an object was created.
        If more objects are found, returns first() of them
        """
        query=self.get_queryset()
        lookup, params = query._extract_model_params(defaults, **kwargs)
        query._for_write = True
        try:
            clone = query.filter(**lookup)
            num = len(clone)
            if num >= 1:
                return (clone._result_cache[0], False)
            else:
                return query._create_object_from_params(lookup, params)
        except self.model.DoesNotExist:
            return query._create_object_from_params(lookup, params)

class myModel(models.Model):
    # --- common data
    active = models.BooleanField(default=True)
    ....
    objects = MyManager()

1 个答案:

答案 0 :(得分:1)

这个主意很好,但是正确的实现方法是在custom Manager中。

from django.db import models

class MyManager(models.Manager):
    def get_first_or_create(self, *args, **kwargs):
        retval = self.get_queryset().filter(*args, **kwargs).first()
        ...

class Car(BaseModel):
    ...
    objects = MyManager()

class Animal(BaseManager):
    ...
    objects = MyManager()

请注意,该方法不需要知道与之一起使用的模型的名称,它只需使用self.get_queryset()