Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python what does it mean "AttributeError: 'unicode' object has no attribute 'has_key' "

I would like to ask what does it mean "AttributeError: 'unicode' object has no attribute 'has_key'" Here is the full stack trace:

Traceback (most recent call last):
  File     "D:\Projects\GoogleAppEngine\google_appengine\google\appengine\ext\webapp\__init__.py", line 509, in __call__
    handler.post(*groups)
  File "D:\Projects\workspace\foo\src\homepage.py", line 71, in post
    country=postedcountry
  File "D:\Projects\GoogleAppEngine\google_appengine\google\appengine\ext\db\__init__.py", line 656, in __init__
    prop.__set__(self, value)
  File "D:\Projects\GoogleAppEngine\google_appengine\google\appengine\ext\db\__init__.py", line 2712, in __set__
    value = self.validate(value)
  File "D:\Projects\GoogleAppEngine\google_appengine\google\appengine\ext\db\__init__.py", line 2742, in validate
    if value is not None and not value.has_key():
AttributeError: 'unicode' object has no attribute 'has_key'

Let me describe a little bit more about the situation:

  • First I created the models.py that has the db.Model for CMSRequest which has an attribute country that reference to the CMSCountry class

    class CMSRequest(db.Model):
      country = db.ReferenceProperty(CMSCountry, required=True)
    
    class CMSCountry(db.Model):
      name = db.StringProperty(required=True)
    
  • Then, I created a bulkloader class to import the data into the CMSCountry

  • In the form, user can select the country from the drop down list box, the results are posted back and save to the CMSRequest object

    def post(self):
      postedcountry = self.request.get('country')
      cmsRequest = models.CMSRequest(postedcountry)
    

Maybe I have found the solution to my question, it is because I have not converted the posted key of CMSCountry back to save to the CMSRequest.

Thank you everyone!

like image 914
Hoang Pham Avatar asked Aug 21 '09 23:08

Hoang Pham


5 Answers

In this line:

if value is not None and not value.has_key():

value is a unicode string. It looks like the code is expecting it to be a db.Model,

(From what I can see, has_key is a method of db.Model, as well as a method of Python dictionaries, but this must be the db.Model one because it's being called with no arguments.)

Are you passing a string to a GAE API that expects a db.Model?

like image 159
RichieHindle Avatar answered Oct 04 '22 09:10

RichieHindle


Your problem is that postedcountry is a string and not a country object. Values retrieved from self.request.get are the string values of variables passed by the browser.

You need to look up a country object using some GQL. Exactly how you do that will depend on what exactly the country field of your HTML form is returning , Object Key?, country name?

def post(self):
  postedcountry = self.request.get('country')

  # <-------- Need to look up a country here !!!!!

  cmsRequest = models.CMSRequest(country=postedcountry)
like image 23
Gareth Simpson Avatar answered Oct 04 '22 08:10

Gareth Simpson


Note: normally "mapping" types in Python (dictionaries and dictionary like classes ... such as various types of dbm (indexed file) and some DBMS/ORM interfaces ... will implement a has_key() method.

Somehow you have gotten a Unicode (string) object into this statement when you were expecting to have some sort of dictionary or other mapping object reference.

In general AttributeError means that you have tangled up your object bindings (variable assignments). You've given a name to some object other than the type that you intended. (Or sometimes it means you have a typo like ".haskey()" instead of has_key() ... etc).

BTW: the use of has_key() is somewhat dated. Normally it's better to test your containers with the Python in operator (which implicitly calls __contains__() --- and which works on lists, strings, and other sequences as well as mapping types).

Also value.has_key() would raise an error even if value were a dictionary since the .has_key() method requires an argument.

In your code I would either explicitly test for if postedcountry is not None: ... or I'd supply your .get() with an (optional) default for "postedcountry."

How do you want to handle the situation where request had no postedcountry? Do you want to assume it's being posted from some particular default? Force a redirection to some page that requires the user to supply a value for that form element? Alert the Spanish Inquisition?

like image 43
Jim Dennis Avatar answered Oct 04 '22 08:10

Jim Dennis


If you read the traceback, it'll tell you exactly what is going on:

    if value is not None and not value.has_key():
AttributeError: 'unicode' object has no attribute 'has_key'

What this says is the the value variable which you're using doesn't have the has_key attribute. And, what it's telling you is that your value variable isn't a dictionary, as it looks like you're expecting...instead, it's a unicode object, which is basically a string.

like image 41
brianz Avatar answered Oct 04 '22 09:10

brianz


You're attempting to set a string to a ReferenceProperty. The 'country' field of CMSCountry is a db.ReferenceProperty, which takes a db.Key or a CMSCountry object, but you're attempting to set it to a string.

You should be doing something like this:

def post(self):
  postedcountry = self.request.get('country')
  country = models.CMSCountry.all().filter('name =', postedcountry)
  if not country:
    # Couldn't find the country
  else:
    cmsRequest = models.CMSRequest(country=country)

Please do file a bug about the rather unhelpful error message, though.

like image 23
Nick Johnson Avatar answered Oct 04 '22 09:10

Nick Johnson