I am using python, Django and get the following error:
getattr(): attribute name must be string
location: val = getattr(obj, field)
if field in headers:
if not isinstance(field, str):
val = getattr(obj, field)
else:
val = getattr(obj, field.LastName)
if callable(val):
val = val()
if type(val) == unicode:
val = val.encode("utf-8")
row.append(val)
I have tried many variation of code but all failed.
You can confirm the object type of field by using print(type(field)). It will likely not be a string considering the error.
Looking at your code, it looks like field will be an object with attributes that are strings, such as LastName. The line
val = getattr(obj, field)
would probably be better off reading
val = getattr(obj, field.someattribute)
If field.someattribute is not a string, you can cast it to string using
str(field.someattribute)
For a grand total of val = getattr(obj, str(field.someattribute))
May be you are missing the attribute name.
I was getting the same error for this
price = models.DecimalField(15, 2,)
but when I modified the code like below error was resolved.
price = models.DecimalField(max_digits=15, decimal_places=2,)
Related
I have a somewhat different need/requirement in how I use mongoengine and wanted to share the below to get any ideas on how to deal with it.
My requirement is that for some fields in a document, I want to be able to keep two values. One is a system-default value and the other a user-specified value. When accessing this field, it should return back a value in the following manner:
if a user-specified value exists, return that OR
if a user-specified value doesn’t exist, return the default
I can not use the default attribute that mongoengine already provides because:
It is applied to the mongoengine class model rather than the document
The default value would need to be updated based on system changes in newer versions of the software
There would not be a memory of what the default is at the document level so it would be difficult to determine if the default needs to be changed for certain documents only
I thought of creating something called an AlternateValueField, which is based off a MapField. Below is the code for this new field type:
import mongoengine
class AlternateValueField(mongoengine.MapField):
def __init__(self, field=None, *args, **kwargs):
self.allowed_keys = (
'_active', # Active Value - changeable by user
'_default', # Default Value - provided by system
)
# Remove the field's default since it now gets handled
# as _default
self.kwargs_default = kwargs.pop('default', None)
super().__init__(field=field, *args, **kwargs)
def __get__(self, instance, owner):
result = super().__get__(instance, owner)
if isinstance(result, dict):
if '_active' in result.keys():
return result['_active']
if '_default' in result.keys():
return result['_default']
return result
def __set__(self, instance, value):
instance_dict = instance._data.get(self.name)
if isinstance(value, dict):
if isinstance(instance_dict, dict):
# To keep the order (_active followed by _default)
new_value = {}
for key in self.allowed_keys:
if (key in instance_dict.keys()
and key not in value.keys()):
new_value[key] = instance_dict[key]
elif key in value.keys():
new_value[key] = value[key]
value = new_value
elif value is not None:
new_value = {
'_active': value,
}
if isinstance(instance_dict, dict):
if '_default' in instance_dict.keys():
new_value['_default'] = instance_dict['_default']
value = new_value
else:
if self.required and self.default is not None:
new_value = {
'_default': self.kwargs_default,
}
value = new_value
self._check_for_allowed_keys(value)
super().__set__(instance, value)
def _check_for_allowed_keys(self, value):
if value is None:
return
for key in value.keys():
if key in self.allowed_keys:
continue
err_msg = (
f"Key '{key}' is not allowed."
f" Allowed keys: {self.allowed_keys}"
)
raise KeyError(err_msg)
def validate(self, value, **kwargs):
super().validate(value, **kwargs)
self._check_for_allowed_keys(value)
A document example that uses it:
class MySchedule(mongoengine.Document):
my_name = AlternateValueField(mongoengine.StringField())
sched1 = mongoengine.StringField()
Using this model to create a document:
>>> s2 = MySchedule(my_name={'_active': 'one', '_default': 'two'}, sched1='yes')
>>> s2.validate()
>>> s2.my_name # returns just the value (of active or default) instead of dict
'one'
>>> s2.to_json()
'{"my_name": {"_active": "one", "_default": "two"}, "sched1": "yes"}'
>>> s2.to_mongo()
SON([('my_name', {'_active': 'one', '_default': 'two'}), ('sched1', 'yes')])
>>> s2._fields
{'my_name': <__main__.AlternateValueField object at 0x7fd37fbaf1c0>, 'sched1': <mongoengine.fields.StringField object at 0x7fd37f968250>, 'id': <mongoengine.base.fields.ObjectIdField object at 0x7fd378225640>}
>>> s2._data
{'id': None, 'my_name': {'_active': 'one', '_default': 'two'}, 'sched1': 'yes'}
>>> s2.my_name = 'anotherone' # works due to the __set__() implementation above
>>> s2.my_name
'anotherone'
>>> s2._data
{'id': None, 'my_name': {'_active': 'anotherone', '_default': 'two'}, 'sched1': 'yes'}
>>> s2.my_name['_active'] = 'blah' # won't work now
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'str' object does not support item assignment
>>> s2._data['my_name']['_active'] = 'blah' # will work
>>> s2.my_name
'blah'
>>> s2._data
{'id': None, 'my_name': {'_active': 'blah', '_default': 'two'}, 'sched1': 'yes'}
My issue is, I would like to be able to use these cases:
s2.my_name # works - returns the _active value or _default value, not dict of them
s2.my_name = 'something' # works - via the __set__() implementation
s2.my_name['_active'] = 'blah' # causes error as shown above
The 3rd case above is what I'd like to be able to do without causing an error.
I tried the following in an attempt to get around it:
overriding __get__(), which doesn't work because it's job is done prior to recognizing there is a getitem call
thought about overriding BaseDict.__getitem__() to recognize this, but that won't work for when there is no getitem call
I would need something after the AlternateField's __get__() call and before BaseDict's __getitem__() call to recognize whether a getitem is following it or not.
Any thoughts on best way to get around this? Obviously, the above may just all be a bad idea. Any alternatives (pardon the pun :)) on creating fields with alternative values that can be changed on a per-document basis and remembered across restarts of the software? Fields can have all the types mongoengine supports, but mostly will be string, int, and potentially, list.
We use MongoDB and Django in our project, some columns have some_col element, and some columns don't have some_col element, maybe that's why we will get the error of AttributeError: 'NoneType' object has no attribute 'get', is there any solution to solve this errors?
def get_col(self, name, **kwargs):
where = {'name': name}
if 'where' in kwargs and isinstance(kwargs['where'], dict):
where.update(kwargs['where'])
find_data = self.find_one(where)
return find_data
def get_test_col(self):
colmuns = Test(self.name)
cls = colmuns.get_col('some_col')
if not cls:
self.some_col = {}
self.some_col = cls.get('data', {}) # error line
Extending vestronge's answer:
self.some_col = cls.get('data', {}) if cls else ""
Basically sets your column to an empty string if you can't get your query. Feel free to substitute the empty string for anything else.
I have a number of constants,variable in which i keep names.
ATTR_ITEM_NAME = 'pro'
I check if the attribute is attached to an objects:
if hasattr(obj1, ATTR_ITEM_NAME):
then if exist I want the attribute value to be passed to an attribute of an object, something like this:
obj2.fm = obj1.ATTR_ITEM_NAME
ATTR_ITEM_NAME being a string and not an attribute is an error, I need something that works;
Python also has getattr which works like hasattr but returns the value:
obj2.fm = getattr(obj1, ATTR_ITEM_NAME)
If you are not sure the attribute exists you could:
assign a default value (e.g. None)
DEFAULT = None
obj2.fm = getattr(obj1, ATTR_ITEM_NAME, DEFAULT)
or catch the exception using
try:
obj2.fm = getattr(obj1, ATTR_ITEM_NAME)
except AttributeError:
pass # or do something else...
I'm making my first attempts at Python.
I need to loop over a log, parse log entries and then update an object, which includes nested objects for machines listed in the log.
This is what I have:
import re
format_pat= re.compile(
r"(?P<host>(?:[\d\.]|[\da-fA-F:])+)\s"
r"(?P<identity>\S*)\s"
r"(?P<user>\S*)\s"
r"\[(?P<time>.*?)\]\s"
r'"(?P<request>.*?)"\s'
r"(?P<status>\d+)\s"
r"(?P<bytes>\S*)\s"
r'"(?P<referer>.*?)"\s'
r'"(?P<user_agent>.*?)"\s*'
)
from json import JSONEncoder
class MyEncoder(JSONEncoder):
def default(self, o):
return o.__dict__
# JSON response object
class ResponseObject(object):
def __init__(self, dict):
self.__dict__ = dict
# check for JSON response object
try:
obj
except NameError:
obj = ResponseObject({})
test = ['2001:470:1f14:169:15f3:824f:8a61:7b59 - SOFTINST [14/Nov/2012:09:32:31 +0100] "POST /setComputer HTTP/1.1" 200 4 "-" "-" 102356']
# log loop
for line in test:
try:
# try to create object from log entry
m = format_pat.match(line)
if m:
res = m.groupdict()
res["status"] = int(res["status"])
# register machine if not done
if not hasattr(obj, res["user"]):
setattr(obj, res["user"], {"downtime":"0","flag":"false","downstart":"0","init":res["time"],"last":"","uptime":"","downtime":"","totaltime":""})
machine = getattr(obj, res["user"])
flag = machine["flag"]
start = machine["downstart"]
down = machine["downtime"]
last = machine["last"]
print "done"
# set last
last = res["time"]
# PROBLEM this does not work
setattr(machine, last, res["time"])
print machine
else:
print "nope"
except:
print "nope base"
print MyEncoder().encode(obj)
The error I'm getting when trying to setattr() is
AttributeError: 'dict' object has no attribute ''
but I was afraid it was not as easy as this...
Question:
How do I update the last value in my nested object using 'setattr'? Or is there another way to update nested object attributes?
I think you need to do this:
setattr(machine, 'last', res["time"])
As setattr needs a string of the name of the attribute to be set
Do not use setattr. Just assign a value to the "last" key for each machine dictionary.
(actually you answered your own question!)
I don't understand why, but I can set the value of last like this:
print machine
print machine["last"]
print res["time"]
# this works
machine["last"] = res["time"]
print machine
If someone can explain, would be nice :-)
Ok, I recently started programming in Python, and I really like it.
However, I have run into a little issue.
I want to be able to define a function to take in some data and assign it to a variable that I designate, rather than have to perform the operation every time I want to submit the value.
Here is a code fragment:
try:
if elem.virtual.tag:
virt = True
temp_asset.set_virtual(True)
except AttributeError:
temp_asset.set_virtual(False)
if virt: #if virtual, get only faction, value, and range for presence
try:
fac = elem.presence.faction #an xml tag (objectified)
except AttributeError:
fac = "faction tag not found"
temp_asset.misload = True
try:
val = elem.presence.value
except AttributeError:
val = "value tag not found"
temp_asset.misload = True
try:
rang = elem.presence.range
except AttributeError:
rang = "range tag not found"
temp_asset.misload = True
#Set presence values
temp_asset.set_presence(fac, val, rang)
The functions set the values, but I want to be able to perform the error checking with something like this:
def checkval(self, variable_to_set, tag_to_use)
try:
variable_to_set = tag_to_use
except AttributeError:
variable_to_set = "tag not found"
temp_asset.misload = True
Is this doable? Let me know if I need to show more code.
Edit: I don't need pointers per se, just anything that works this way and saves typing.
Edit 2: Alternatively, I need a solution of how to check whether an objectified xml node exists (lxml).
Have you tried/looked into the getattr and setattr functions?
For example, assuming these "variables" are object attributes:
def checkval(self, attr, presence, tagstr):
tag = getattr(presence, tagstr, None) # tag = presence."tagstr" or None
setattr(self, attr, tag or 'tag not found') # ?? = presence."tagstr" or 'tag not found'
if tag is None:
self.temp_asset.misload = True
You call it like,
your_object.checkval('fac', elem.presence, 'faction')
Alternatively, you can pre-define these variables and set them default values before you attempt to look up the tags. For example:
class YourObject(object):
_attrmap = {
'fac': 'faction',
'val': 'value',
'rang': 'range',
}
def __init__(self):
# set default values
for attr, tagstr in self._attrmap.items():
setattr(self, attr, '%s tag not found' % tagstr)
def checkval(self, attr, presence):
for attr, tagstr in self._attrmap.items():
tag = getattr(presence, tagstr, None)
if tag is not None:
setattr(self, attr, tag)
else:
self.temp_asset.misload = True