0

I am working on creating a Django forums project and I have a "settings" app which access the database for a table called settings.

The table is setup with a verbose_name, name, and value columns. The first is simply a name to be displayed to admins, the second is the name that the setting is accessed by (and is the primary key on the table.)

Now, I have some settings which are boolean, some which are integers, and some of which are string. However, value is a TEXT type in the Database so Django is returning it as a string. Right now I have this implementation to convert booleans into the Python boolean type:

class SettingsMiddleware:
    def process_request(self, request):
        request.settings = {}
        settings = Setting.objects.all()

        for setting in settings:
            if setting.value == ("True" or "1"):
                setting.value = True
            if setting.value == ("False" or "0"):
                setting.value = False

            request.settings[setting.name] = setting.value

        return None

So I have two questions:

  1. Is there a better way to go about this?
  2. How can I determine whether the string contains an integer? I know that I can convert it to an integer with int() if it is valid, but how can I tell whether or not it is valid?

Obviously, regarding question number two, I would remove the or "1" and or "0" bits of the current evaluation.

3
  • You could also serialize your data using something like JSON or pickle and then reload it with that Commented Feb 1, 2013 at 15:57
  • @JeffS I considered using JSON to serialize and deserialize it, however I realized that I would be inserting rows that looked like {"value": true} and {"value": "Please verify your email!"} and it was really a waste of space as JSON would be looping through the same way I would, albeit with (probably) more overhead. Commented Feb 1, 2013 at 15:58
  • If you're worried about the overhead, and can take on the security risk, pickle might be a good choice Commented Feb 1, 2013 at 16:00

3 Answers 3

2

It seems to me that ast.literal_eval might be useful to you.

>>> import  ast
>>> ast.literal_eval("1")
1
>>> ast.literal_eval("0")
0
>>> ast.literal_eval("True")
True
>>> ast.literal_eval("False")
False
>>> ast.literal_eval("'foobar'")
'foobar'
>>> ast.literal_eval("1.2")
1.2
>>> ast.literal_eval("1.2e3")
1200.0
>>> ast.literal_eval("1,2")
(1, 2)
>>> ast.literal_eval("[1,2]")
[1, 2]
>>> ast.literal_eval("[1,2,(1,2)]")
[1, 2, (1, 2)]
>>> ast.literal_eval("1f")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python2.7/ast.py", line 49, in literal_eval
    node_or_string = parse(node_or_string, mode='eval')
  File "/usr/local/lib/python2.7/ast.py", line 37, in parse
    return compile(source, filename, mode, PyCF_ONLY_AST)
  File "<unknown>", line 1
    1f
     ^
SyntaxError: unexpected EOF while parsing
Sign up to request clarification or add additional context in comments.

1 Comment

This looks good. I'm going to leave this open for a little bit and if there aren't any other better answers I'll mark this as best. Thanks!
1

If you want to restrict it to 0,1,True,False, I'd do

boolmapping = {'0':False, 'False': False, '1':True, 'True':True}
...
setting = boolmapping.get(setting, setting)

However, this may mistakenly convert an integer that happens to be 1 to True, when really 1 was meant, so you may better map '1' to 1, not True.

To convert a string to an int if it is one, do

try:
    setting = int(setting)
except ValueError:
    pass

7 Comments

Thanks, this looks like it would work, but are there any advantages to this over ast.literal_eval()?
I can't think of any place in python where you couldn't use True instead of 1 -- except with a check using the is operator I suppose...
@John -- This approach is probably faster than the literal_eval at the cost of a lot of flexibility (which is sometimes preferable)
To be clear, I meant that at times, a less flexible solution is desirable.
@mgilson: The most canonical case where True won't work in place of 1 is string conversion. If you use the value to fill out a field in a text file, the text file may become incorrect if you put True where 1 is required.
|
0

You can simply use:

if setting.value in ["true", "True", 1, "1"]:
    setting.value = True

1 Comment

I'm looking to add support for integers as well, as per question number two.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.