gpt4 book ai didi

python - 如何在 Django 中刷新对象的值?

转载 作者:IT老高 更新时间:2023-10-28 22:17:20 25 4
gpt4 key购买 nike

我在 Django 中有一个模型对象。对象上的一种方法使用行级锁定来确保值准确,如下所示:

class Foo(model.Model):
counter = models.IntegerField()

@transaction.commit_on_success
def increment(self):
x = Foo.objects.raw("SELECT * from fooapp_foo WHERE id = %s FOR UPDATE", [self.id])[0]
x.counter += 1
x.save()

问题是,如果您对 foo 对象调用 increment,则该对象的值不再反射(reflect)数据库中的值。我需要一种方法来刷新对象中的值,或者至少将它们标记为过时,以便在必要时重新获取它们。显然,这是 Django 开发人员的功能 refuse to add .

我尝试使用以下代码:

for field in self.__class__._meta.get_all_field_names():
setattr(self, field, getattr(offer, field))

不幸的是,我有第二个模型,其定义如下:

class Bar(model.Model):
foo = models.ForeignKey(Foo)

这会导致错误,因为它显示在字段列表中,但您不能 getattrsetattr 它。

我有两个问题:

  • 如何刷新对象上的值?

  • 我是否需要担心刷新任何引用我的对象的对象,例如外键?

最佳答案

最后,在 Django 1.8 中,我们有一个特定的方法来执行此操作。它被称为 refresh_from_db它是 django.db.models.Model 类的新方法。

使用示例:

def update_result(self):
obj = MyModel.objects.create(val=1)
MyModel.objects.filter(pk=obj.pk).update(val=F('val') + 1)
# At this point obj.val is still 1, but the value in the database
# was updated to 2. The object's updated value needs to be reloaded
# from the database.
obj.refresh_from_db()

如果您的 Django 版本低于 1.8,但您希望拥有此功能,请将您的模型修改为从 RefreshableModel 继承:

from django.db import models
from django.db.models.constants import LOOKUP_SEP
from django.db.models.query_utils import DeferredAttribute

class RefreshableModel(models.Model):

class Meta:
abstract = True

def get_deferred_fields(self):
"""
Returns a set containing names of deferred fields for this instance.
"""
return {
f.attname for f in self._meta.concrete_fields
if isinstance(self.__class__.__dict__.get(f.attname), DeferredAttribute)
}

def refresh_from_db(self, using=None, fields=None, **kwargs):
"""
Reloads field values from the database.
By default, the reloading happens from the database this instance was
loaded from, or by the read router if this instance wasn't loaded from
any database. The using parameter will override the default.
Fields can be used to specify which fields to reload. The fields
should be an iterable of field attnames. If fields is None, then
all non-deferred fields are reloaded.
When accessing deferred fields of an instance, the deferred loading
of the field will call this method.
"""
if fields is not None:
if len(fields) == 0:
return
if any(LOOKUP_SEP in f for f in fields):
raise ValueError(
'Found "%s" in fields argument. Relations and transforms '
'are not allowed in fields.' % LOOKUP_SEP)

db = using if using is not None else self._state.db
if self._deferred:
non_deferred_model = self._meta.proxy_for_model
else:
non_deferred_model = self.__class__
db_instance_qs = non_deferred_model._default_manager.using(db).filter(pk=self.pk)

# Use provided fields, if not set then reload all non-deferred fields.
if fields is not None:
fields = list(fields)
db_instance_qs = db_instance_qs.only(*fields)
elif self._deferred:
deferred_fields = self.get_deferred_fields()
fields = [f.attname for f in self._meta.concrete_fields
if f.attname not in deferred_fields]
db_instance_qs = db_instance_qs.only(*fields)

db_instance = db_instance_qs.get()
non_loaded_fields = db_instance.get_deferred_fields()
for field in self._meta.concrete_fields:
if field.attname in non_loaded_fields:
# This field wasn't refreshed - skip ahead.
continue
setattr(self, field.attname, getattr(db_instance, field.attname))
# Throw away stale foreign key references.
if field.rel and field.get_cache_name() in self.__dict__:
rel_instance = getattr(self, field.get_cache_name())
local_val = getattr(db_instance, field.attname)
related_val = None if rel_instance is None else getattr(rel_instance, field.related_field.attname)
if local_val != related_val:
del self.__dict__[field.get_cache_name()]
self._state.db = db_instance._state.db

class MyModel(RefreshableModel):
# Your Model implementation
pass

obj = MyModel.objects.create(val=1)
obj.refresh_from_db()

关于python - 如何在 Django 中刷新对象的值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9791947/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com