是否有一种惯用的get_or_create方法然后更新Django中的对象?

bry*_*ryn 7 django idioms django-models

我有一个名为StaffSettings的Django模型,它包含我的Django应用程序中用户的各种配置选项.每个用户在StaffSettings表中最多只有一个条目.

假设一个设置是default_year_level,我有我的用户对象的代码,如:

def set_default_year_level(u, year_level):
    obj, _created = StaffSettings.objects.get_or_create(user=u)
    obj.default_year_level = year_level
    obj.save()
Run Code Online (Sandbox Code Playgroud)

我希望函数的主体适合一行,因为它看起来像一个常见的用例,但如果我将其定义为

def set_default_year_level(u, year_level):
    StaffSettings.objects.filter(user=u).update(default_year_level=year_level)
Run Code Online (Sandbox Code Playgroud)

如果有问题的用户已在StaffSettings表中有一行,但如果它不存在则不会创建相关行,这可以正常工作.

编写此代码的惯用/最佳方法是什么?(例如,是否存在某种filter_or_create功能?还是其他人编写装饰器/辅助函数来处理这个习惯用法?)

Los*_*ses 6

从 Django 1.7 开始,您可以使用update_or_create()

def set_default_year_level(u, year_level):
    obj, _created = StaffSettings.objects.update_or_create(
        user=u,
        default_year_level=year_level
    )
Run Code Online (Sandbox Code Playgroud)

或者,对于上一个答案中解释的更通用的情况:

def set_default_values(u, **kwargs):
    obj, _created = StaffSettings.objects.update_or_create(user=u, defaults=kwargs)
Run Code Online (Sandbox Code Playgroud)

这也满足您的额外要求

我希望函数体适合一行


Pon*_*ech 5

我没有看到你的第一个函数有任何问题,我会为这个用例写同样的东西.

但是,如果您需要在模型的许多字段上使用相同的功能,并且您不想重复自己,则可以将该字段作为参数传递:

def set_default_value(u, field, value):
  obj, _created = StaffSettings.objects.get_or_create(user=u)
  setattr(obj, field, value)
  obj.save()
Run Code Online (Sandbox Code Playgroud)

而且我会远离update()函数,因为这个函数意味着一次更新多个对象并且不会触发你的模型上的save()方法和信号(参见https://docs.djangoproject.com/en/dev/topics/db/queries/#newed-multiple-objects-at-once)