我需要比较两个对象,以确定某个字段是否已更改
class Country(models.Model): # country code 'MX' -> Mexico
code = models.CharField(max_length=2)
name = models.CharField(max_length=15)
class Client(models.Model): # id=1, name=pedro, country.code=MX, rfc=12345
name = models.CharField(max_length=100)
country = models.ForeignKey(Country)
rfc = models.CharField(max_length=13)
> obj_db = Client.object.get(id=1)
> country = Country.objects.get(code='MX')
obj_no_db = Client(**{'id':1, 'name':'pedro', 'country': country, 'rfc':12345})
> obj_db == obj_no_db # True
> obj_no_db = Client(**{'id':1, 'name':'pedro', 'country': country, 'rfc':1})
> obj_db == obj_no_db # True # but isn't True because the rfc has change, how can compare field by field
> obj_db.rfc == obj_no_db.rfc # False I expected this result
我需要构建一个通用的功能,问题是我没有找到有关它的信息,我想我可以使用._meta选项,但我不确定。 我开发了这个功能,但我无法逐个发现比较的方法。
def get_insert_update(obj, key, obj_list, fields=None, exclude_fields=None):
"""
:param obj: The object for compare
:param key: a the key for compare to determine if we need to update or insert
:param obj_list: list objects to compare
:return: to_insert, _update
"""
db = {}
to_insert = []
to_update = []
if key == 'pk': # the field pk doesn't exists so we change to id, because its the same
key = 'id'
exclude_fields = exclude_fields or []
fields = fields or []
if 'pk' in fields:
fields[fields.index('pk')] = 'id' # we change the field pk, because it doesn't exists
if 'pk' in exclude_fields:
exclude_fields[exclude_fields.index('pk')] = 'id' # we change the field pk, because it doesn't exists
meta = obj._meta # we define meta object
if fields is None:
fields = meta.get_all_field_names()
fields = [f for f in meta.fields if f.attname in fields]
# dumping db into memory
for _obj in obj.objects.all():
if isinstance(key, list): # first check if is a list to create a custom key
_key = _get_key(_obj, key)
else:
_key = _obj.__dict__[key]
# if exclude fields exists
if exclude_fields:
d = {f.attname: _obj.__dict__[f.attname] for f in fields if f.attname not in exclude_fields}
db[_key] = obj(**d)
else: # we save the full object
db[_key] = _obj
# read local objects to determine if the record will be insert or update
for _obj in obj_list:
if isinstance(key, list): # first check if is a list to create a custom key
_key = _get_key(_obj, key)
else:
_key = _obj.__dict__[key]
if _key in db: # if the key is in db so we check if it equal
# if _obj.pk == 6: # debug
# print(_obj.__dict__, db[_key].__dict__, _obj.__dict__ == db[_key].__dict__)
if _obj != db[_key]: # HERE i need the determine if the fields are equal or not.
to_update.append(_obj) # if the object has changed, we update it
else:
pass # if the object is equal, we didn't do it anything
else:
to_insert.append(_obj) # because we didn't found into the database, we create it
return to_insert, to_update
def _get_key(obj, lst):
"""
create a string key using multiples keys
Example: obj.id -> 1, obj.name -> 'foo'
lst['id', 'name']
:param lst: list of keys
:return: 1_foo
"""
k = []
for t in lst:
k.append(str(obj.__dict__[t]))
return "_".split(k)
答案 0 :(得分:4)
Django的Model类根据__eq__
属性的值定义要比较的pk
方法,这就是你的模型比较相等的原因。
执行此操作的一种简单方法是在您自己的模型上覆盖该方法,以比较__dict__
的值,该值包含所有实例的值。
这有点轻微的问题,因为__dict__
还包含一个隐藏的_state
对象,该对象将按ID进行比较,因此您需要对其进行过滤比较。
def __eq__(self, other):
values = [(k,v) for k,v in self.__dict__.items() if k != '_state']
other_values = [(k,v) for k,v in other.__dict__.items() if k != '_state']
return values == other_values