我发现自己反复查找符合某些条件的记录,如果不存在,则创建符合这些条件的新记录。
基本上可以使用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()
答案 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()
。