获取或创建具有给定字段值的对象的简明方法

时间:2016-10-24 14:39:58

标签: django

假设我有:

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.

具体做法是:

  1. 有没有办法在不指定的情况下查询两个(所有)字段 每个人分别?
  2. 是否有更好的习惯用于获取旧对象或保存新对象?类似于get_or_create,但是接受一个对象作为参数?
  3. 假设执行保存的代码与生成我们需要比较的初始MyContentClass实例的代码分开。这是典型的情况,你有一个函数,它返回一个模型对象而不保存它。

2 个答案:

答案 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),它将成为默认经理