我需要比较两个对象,以确定一个字段是否发生了变化
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)