假设我有:
from django.db import models
class MyContentClass(models.Model):
content = models.TextField()
another_field = models.TextField()
x = MyContentClass(content="Hello, world!", another_field="More Info")
是否有更简洁的方法来执行以下逻辑?
existing = MyContentClass.objects.filter(content=x.content, another_field=x.another_field)
if existing:
x = existing[0]
else:
x.save()
# x now points to an object which is saved to the DB,
# either one we've just saved there or one that already existed
# with the same field values we're interested in.
具体做法是:
get_or_create
,但是接受一个对象作为参数?假设执行保存的代码与生成我们需要比较的初始MyContentClass
实例的代码分开。这是典型的情况,你有一个函数,它返回一个模型对象而不保存它。
答案 0 :(得分:0)
您可以使用
将x转换为字典x_data = x.__dict__
然后可以将其传递给对象的get_or_create方法。
MyContentClass.objects.get_or_create(**x_data)
这个问题是有一些字段会导致错误输出(例如唯一ID或_state Django modelstate字段)。但是,如果你事先从词典中弹出()那些,那么你可能会很高兴:)
cleaned_dict = remove_unneeded_fields(x_data)
MyContentClass.objects.get_or_create(**cleaned_dict)
def remove_unneeded_fields(x_data):
unneeded_fields = [
'_state',
'id',
# Whatever other fields you don't want the new obj to have
# eg any field marked as 'unique'
]
for field in unneeded_fields:
del x_data[field]
return x_data
修改强> 为避免与必须维护字段的白名单/黑名单相关的问题,可以执行以下操作:
def remove_unneeded_fields(x_data, MyObjModel):
cleaned_data = {}
for field in MyObjModel._meta.fields:
if not field.unique:
cleaned_data[field.name] = x_data[field.name]
return cleaned_Data
可能必须进行更多验证,而不仅仅是检查字段不是唯一的,但是这可能会在涉及模型字段更改时提供一些灵活性。
答案 1 :(得分:0)
我建议为这些模型创建一个自定义管理器,并添加您想要对模型执行的功能(如自定义get_or_create函数)。
https://docs.djangoproject.com/en/1.10/topics/db/managers/#custom-managers
这将是最干净的方式,不涉及黑客攻击。 :)
您可以为特定模型创建特定管理器,或者为所有模型创建具有所需功能的超类。
如果您只想添加具有不同名称的第二个经理,请注意,如果您未先设置objects
经理(https://docs.djangoproject.com/en/1.10/topics/db/managers/#default-managers),它将成为默认经理