django - compare two objects [using fields dynamically] -
i need compare 2 objects, determine if field has changed or not
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 # isn't true because rfc has change, how can compare field field > obj_db.rfc == obj_no_db.rfc # false expected result
i need build function generic, problem don't found information it, think can use ._meta options, i'm not sure. developed function can't discover way compare field field.
def get_insert_update(obj, key, obj_list, fields=none, exclude_fields=none): """ :param obj: object compare :param key: key compare determine if need update or insert :param obj_list: list objects compare :return: to_insert, _update """ db = {} to_insert = [] to_update = [] if key == 'pk': # field pk doesn't exists change id, because same key = 'id' exclude_fields = exclude_fields or [] fields = fields or [] if 'pk' in fields: fields[fields.index('pk')] = 'id' # change field pk, because doesn't exists if 'pk' in exclude_fields: exclude_fields[exclude_fields.index('pk')] = 'id' # change field pk, because doesn't exists meta = obj._meta # define meta object if fields none: fields = meta.get_all_field_names() fields = [f f in meta.fields if f.attname in fields] # dumping db memory _obj in obj.objects.all(): if isinstance(key, list): # first check if list create 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] f in fields if f.attname not in exclude_fields} db[_key] = obj(**d) else: # save full object db[_key] = _obj # read local objects determine if record insert or update _obj in obj_list: if isinstance(key, list): # first check if list create custom key _key = _get_key(_obj, key) else: _key = _obj.__dict__[key] if _key in db: # if key in db check if equal # if _obj.pk == 6: # debug # print(_obj.__dict__, db[_key].__dict__, _obj.__dict__ == db[_key].__dict__) if _obj != db[_key]: # here need determine if fields equal or not. to_update.append(_obj) # if object has changed, update else: pass # if object equal, didn't else: to_insert.append(_obj) # because didn't found database, create return to_insert, to_update def _get_key(obj, lst): """ create string key using multiples keys example: obj.id -> 1, obj.name -> 'foo' lst['id', 'name'] :param lst: list of keys :return: 1_foo """ k = [] t in lst: k.append(str(obj.__dict__[t])) return "_".split(k)
django's model class defines __eq__
method compare based on value of pk
attribute, why models compare equal.
one simple way override method on own model compare value of __dict__
, contains instance's values.
there's slight gotcha this, in __dict__
contains hidden _state
object compared id, you'd need filter out of comparison.
def __eq__(self, other): values = [(k,v) k,v in self.__dict__.items() if k != '_state'] other_values = [(k,v) k,v in other.__dict__.items() if k != '_state'] return values == other_values
Comments
Post a Comment