Django Find difference in the same model instance - python

I've been searching around and I don't think I've found my answer quite yet. But I'm looking to be able to find differences in data and have a list of column names that show that.
Take for instance I have a model just called my_model that has some columns.
object = my_model.objects.get(id=1)
# Perform edit some values.
old_object = my_model.objects.get(id=1)
object.save()
# Check for differences
model_fields = [field.name for field in my_model._meta.get_fields()]
filtered_list = filter(lambda field: getattr(object, field, None) != getattr(old_object, field, None), model_fields)
Purpose of this is to notify the user after they make an update on their end to send an email to that user to just give them a reminder that they changed whatever values they changed.

Was able to answer my own question. Converting the two objects to dictionaries. I was able to end up with something like
dict1, dict2 = obj1.__dict__, obj2._dict__
changed_fields = {
'column_names': []
}
excluded_keys = '_state'
for k,v in dict1.items():
if k in excluded_keys:
continue
try:
if v != dict2[k]
changed_fields['column_names'].append(k)
except KeyError:
# Put error handling
continue

Related

Add value to Python multidimensional dict

I have a value, which I need to add it to a multidimensional dict
The problem is that the keys may or may not exist
If they exist, I just want to add it, if not .. I need to create it
What is the best way of doing this, since right now what I have looks pretty bad
if response.get('pages', {}).get(url, {}).get('variations', {}).get('custom_screenshot'):
response['pages'][url]['variations']['custom_screenshot'][command.get('params')[0]] = output
elif response.get('pages', {}).get(url, {}).get('variations'):
response['pages'][url]['variations']['custom_screenshot'] = {command.get('params')[0]: output}
elif response.get('pages', {}).get(url, {}):
response['pages'][url]['variations'] = {'custom_screenshot': {command.get('params')[0]: output}}
elif response.get('pages', {}):
response['pages']['url'] = {'variations': {'custom_screenshot': {command.get('params')[0]: output}}}
else:
response['pages'] = {url: {'variations': {'custom_screenshot': {command.get('params')[0]: output}}}}
return response
Use referential nature of Python dictionary.
Declare intermediate keys that should be in the final response (in proper order)
Loop though the keys calling dict.setdefaut method to set the inner dictionary if it's not there
Set unconditional value output for the custom key command.get('params')[0]
resp_keys = [url, 'variations', 'custom_screenshot']
pages_dict = resp.setdefault('pages', {})
for k in resp_keys:
pages_dict = pages_dict.setdefault(k, {}) # return dict under key k
pages_dict[command.get('params')[0]] = output

How to iterate values inside dictionary of lists in PYTHON

I have a complicated method that needs to work correctly, that I can't seem to figure out why it doesn't.
I have a dictionary as it follows:
{'view': ['premium_subscribers', 'premium_content'], 'delete': ['admins', 'normal_content', 'premium_content']}
I need to know how to iterate one by one through each specific key values, which are arrays. For example:
key = delete
for loop (that iterates 1 by 1 through key "delete's" values
takes "admins" value and does some processing
in the next iteration takes normal_content and does same processing
and so on ......
its basically checking for a match to be found.
In case if you're interested in my method, I have it below. It has 3 dictionaries and is comparing their key's values to accomplish access permission.
If the for loop iterates correctly through each value of that key, it will start working as expected.
def accessPermission(operation, user, object):
domains = dict()
types = dict()
access = dict()
access = json.load(open("access.txt"))
domains = json.load(open("domains.txt"))
types = json.load(open("types.txt"))
print(types)
print(access)
print(domains)
if operation in access.keys():
firstkeyvalue = access.get(operation)[0]
if firstkeyvalue in domains.keys():
if user in domains.get(firstkeyvalue):
for access.get(operation)[0] in access:
if object in types.values():
print("Success")
else:
print("Error: access denied")
else:
print("Error: access denied")
else:
print("Error: access denied")
else:
print("Error: access denied")
Seems you only need to iterate through the elements like this:
dict = {'view': ['premium_subscribers', 'premium_content'], 'delete': ['admins', 'normal_content', 'premium_content']}
key = 'delete' #set somewhere
for v in dict[key]:
print(v)
#do what you need with that
Output:
admins
normal_content
premium_content
Each Value is a list, so you need an extra loop for iterating over the items of each list:
data_dict = {'view': ['premium_subscribers', 'premium_content'], 'delete': ['admins', 'normal_content', 'premium_content']}
for key in data_dict:
values = data_dict[key]
# iterate over list of values
for v in values:
# Now you have access to each one
print(v)
Output:
premium_subscribers
premium_content
admins
normal_content
premium_content

Conditional checks for JSON key-value pairs being ignored

I am building a point feature class from a web call that returns JSON. The JSON is a bit sketchy in that sometimes keys do not exist in the record. I am trying to do this, once I have a valid JSON object:
#requests stuff above this
for i in jsonObj:
try:
if i['properties']['country']:
country = i['properties']['country']
else:
country = 'UNK'
print('Country name not found, using {}'.format(country))
except KeyError, e:
print('Key error: reason: {}'.format(str(e)))
pass
#then do all the arcpy FC creation stuff
The result is a whole bunch of key errors with "reason: 'country'" and instead of building those rows with the generic 'country' value of 'UNK', it will simply ignore them and build the feature class, leaving out those points.
I have taken out the try and left it as a conditional check, but it fails at the first row that lacks a 'country' key.
In summary, I'm just trying to check if a key-value pair exists; if it doesn't, assign a generic value of 'UNK' to the country variable.
It seems like part of the problem might be that if i['properties']['countries'] is checking for a value, but not the existence of the key itself? How might I more efficiently check for the existence of the key?
I have read Check if a given key already exists in a dictionary and have modified my code to both of these, and neither yield the expected outcome:
for i in jsonObj:
try:
# get coordinates first
if i['geometry']['coordinates']:
ycoord = float(i['geometry']['coordinates'][1])
xcoord = float(i['geometry']['coordinates'][0])
if i['properties']['city'] in i:
city = i['properties']['city']
else:
city = 'UNK'
if i['properties']['country'] in i:
country = i['properties']['country']
else:
country = 'UNK'
and
for i in jsonObj:
try:
# get coordinates first
if i['geometry']['coordinates']:
ycoord = float(i['geometry']['coordinates'][1])
xcoord = float(i['geometry']['coordinates'][0])
if 'city' in i:
city = i['properties']['city']
else:
city = 'UNK'
if 'country' in i:
country = i['properties']['country']
else:
country = 'UNK'
I do have the 'properties' key in every record/dictionary, but whether I have a 'country' key is not guaranteed. Some rows in the json response have it, some rows don't
Your last try:
if 'country' in i:
country = i['properties']['country']
else:
country = 'UNK'
was close, but you're managing a dict of dicts, and 'country' has better chance to be a key of the sub-dict, so the fix would be:
if 'country' in i['properties']:
country = i['properties']['country']
else:
country = 'UNK'
or even better & shorter using get with a default value (I recommend that last one over the quickfix):
country = i['properties'].get('country','UNK')
It seems like you don't fully understand json implementation.
x = i['geometry']['coordinates'] is basically y = i['geometry']; x = y['coordinates'], so you need safety check for each layer, becaue i['geometry'] not only will throw exception when 'geometry' field is not found but also the returned object must also implement [] for ['coordinates'] to work (so in this case it must be another json object, and not string,bool,None etc.)
I also believe your json object is implemented using python dictionary, so you can check if certain field, e.g. 'geometry' exists using x.get('geometry'), which will return either its value or None object. You can also use city = x.get('city', 'UKN') to set default value (json object, string, bool, None etc.) if it was not found in dict (python dict.get method implements default handler).
So in the end you should have something like this:
geo = i.get('geometry')
if not geo: return
coords = geo.get('coordinates')
if not coords: return
xcoord, ycoord = float(coords[0]), float(coords[1])
props = i.get('properties')
if not props: return
city = props.get('city', 'UNK')
country = props.get('country', 'UNK')
This is a draft and I did not test it, also this strongly asserts that your json object is based on python dict object.

Filtering out Python Dictionary Values with Array of Nested Keys

I am trying to filter out a number of values from a python dictionary. Based on the answer seen here: Filter dict to contain only certain keys. I am doing something like:
new = {k:data[k] for k in FIELDS if k in data}
Basically create the new dictionary and care only about the keys listed in the FIELDS array. My array looks like:
FIELDS = ["timestamp", "unqiueID",etc...]
However, how do I do this if the key is nested? I.E. ['user']['color']?
How do I add a nested key to this array? I've tried:
[user][color], ['user']['color'], 'user]['color, and none of them are right :) Many of the values I need are nested fields. How can I add a nested key to this array and still have the new = {k:data[k] for k in FIELDS if k in data} bit work?
A quite simple approach, could look like the following (it will not work for all possibilities - objects in lists/arrays). You just need to specify a 'format' how you want to look for nested values.
'findValue' will split the searchKey (here on dots) in the given object, if found it searches the next 'sub-key' in the following value (assuming it is an dict/object) ...
myObj = {
"foo": "bar",
"baz": {
"foo": {
"bar": True
}
}
}
def findValue(obj, searchKey):
keys = searchKey.split('.')
for i, subKey in enumerate(keys):
if subKey in obj:
if i == len(subKey) -1:
return obj[subKey]
else:
obj = obj[subKey]
else:
print("Key not found: %s (%s)" % (subKey, keys))
return None
res = findValue(myObj, 'foo')
print(res)
res = findValue(myObj, 'baz.foo.bar')
print(res)
res = findValue(myObj, 'cantFind')
print(res)
Returns:
bar
True
Key not found: cantFind (cantFind)
None
Create a recursive function which checks whether the dictionary key has value or dictionary.
If key has dictionary again call function until you find the non-dictionary value.
When you find value just add it to your new created dictionary.
Hope this helps.

python dictionary keys

I'm having a bit of a problem, don't even know if this is doable. I have a number of launchers that each have a interface defined with the expected inputs. The input values come as a dictionary. For example:
dict_key = str(req_input[0]['name'])
data = dict(dict_key = value)
Now req_input[0]['name'] is the key I would like to insert into the dictionary. Now I know what I'm doint here only creates a dictionary of the form {'dict_key' : value} but I was wondering if it is possible to create the dicionary as to be the form {'Actual value of dict_key' : value}
Regards,
Bogdan
The best way to do this is simply using the dict literal {}:
data = {dict_key: value}
Other ways would be
data = dict({dict_key: value})
or
data = dict()
data[dict_key] = value
but these are longer so stay with the first one.
Another way is:
data = {}
data[req_input[0]['name']] = value
This way you can add multiple values to the same dictionary, or loop through req_input if you have multiple parameters there, i.e.:
data = {}
for input in req_input:
data[input['name']] = value

Categories