0

I am trying to swap in the key name from a request.param for an Elixir object attribute. Below, the Elixir object bk is a Book() which has an attribute PrintTitle. PrintTitle also comes in from a form as a request.param. Rather than manually map all the parameters to the Book attributes, I would like to map them based on a simple if in. However, it doesn't work, because I have the wrong syntax or method at bk.k.

if len(request.params) != 0:
        bk = Book()
        for k, v in request.params.items():
            print k, v # gives me love
            bk.k = v # no love here
        print 'Print Title:', bk.PrintTitle # value is None (obviously)
Ben
  • 51,770
  • 36
  • 127
  • 149
MFB
  • 19,017
  • 27
  • 72
  • 118

1 Answers1

0

Unfortunately you can't just set the attribute of a Python object with a variable in this way. One way to do this is to use the setattr method to accomplish this, for example here is a crude example:

from elixir import *

metadata.bind = 'sqlite://'
metadata.bind.echo = False

class Book(Entity):
    PrintTitle = Field(String(50))

setup_all()
create_all()

params = {'PrintTitle':'Ethyl the Aardvark goes Quantity Surveying'}

bk = Book()

print "Title in database (before): {}".format(bk.PrintTitle)

for k, v in params.items():
    setattr(bk, k, v)

print "Title in database (after): {}".format(bk.PrintTitle)

The result of this script is:

Title in database (before): None
Title in database (after): Ethyl the Aardvark goes Quantity Surveying

Here I'm faking out your elixir model, and I'm just using a params dictionary to fake out whatever you're getting in request.params.

So in this example setattr(bk, k, v) is pretty much what you're trying to do with bk.k=v.

EDIT: I should add that you need to be careful using setattr, in that you need to be sure the key from your params exists in your db model first, as elixer/sqlalchemy may not like trying to set the value of a non-existent database field.

Raceyman
  • 1,354
  • 1
  • 9
  • 12
  • Raceyman, that is a confirmed winner. Thank you. A couple of further comments... I haven't come across that `format` method before(), not sure what its supposed to do, but it didn't work for me. I got the correct print by using `print "title in db before:", (bk.Printtitle)`. Also, I think I can safeguard from non-existent db fields by putting the `setattr` in a `try` block? Thanks again mate, you've really helped me out. – MFB Jun 09 '11 at 00:55
  • Aaah, I see the problem. `setattr` will actually create an attribute that doesn't already exist in the object, right? So I can accidentally create at attr that doesn't exist in the db.. that's what you were saying. Hmmm.... – MFB Jun 09 '11 at 00:59
  • Ok, so my understanding now is that I can use my form as the authority for field names, but the danger is that if I get a field name wrong, I won't be 'told' about it. Am I right? – MFB Jun 09 '11 at 01:07
  • Yes, objects are mutable so `setattr` will add these as properties if they don't already exist. The difficulty here is, the object we're talking about is an elixir/sqlalchemy object so it may behave oddly if you do that. – Raceyman Jun 09 '11 at 12:39
  • In Python 2.7 the `.format` is used in the same way as % is used for replacing parameters in strings. Earlier versions of Python may not allow this. – Raceyman Jun 09 '11 at 12:47
  • I should add that you can use sqlalchemy's `.columns` (or `.c`) property on your table object to examine your table to validate fields exist before trying to use `setattr`. – Raceyman Jun 09 '11 at 12:47