Search code examples
pythondjangoeval

Django Eval from Database


My group and I are trying to develop a "very-dynamic" web app with Django. We have a "configurations" template for the users where everyone can configure his/her own space. Every configuration option should be read from the DB.

view:

def config(request):
    if 'logged' not in request.session:
        return redirect(login)
    apps_list = App.objects.all()
    varS = varsesion(request)
    context = Configurations.objects.all()
    for row in context:
        row.form = eval(row.form) #Not sure at all if this is ok
        print (row.form)

    context.App = 'config'
    return render(request, "index.html", {'context': context, 'apps_list ': apps_list , 'varS': varS,
                                           'context.App': context.App})

And in our DB we have the Configurations model table like this:

+----+-----+-----+-----+---------+---------------+
| id |user |Title|Body |OptionBtn|     form      |
+----+-----+-----+-----+---------+---------------+
| N  |userA|  X  |  X  |    X    | DataConfig()  |
+----+-----+-----+-----+---------+---------------+
| N2 |userA|  X  |  X  |    X    | ColorsConfig()|
+----+-----+-----+-----+---------+---------------+
| N3 |userA|  X  |  X  |    X    |ButtonsConfig()|
+----+-----+-----+-----+---------+---------------+

And many other columns that I'll skip...

Of course every Form value in the DB's form field exists in forms.py with their respective names. The problem comes when I try to iterate these forms fields in our template (every other column from the DB is displayed properly like buttons, titles, texts, etc)

Here is the template (I've skipped some of the attrs in the example table):

<div class="breadcrumb">
    <li class="breadcrumb-item">
        <a href="/config.html"><h1 style="color:#871830">Configurations panel</h1></a>
    </li>
</div>
{% for configuration in context %}
<div style="" id="panel{{ configuration.codConfi }}" class="breadcrumb form-inline">
    <div class="form-group col-12" style="color:#228718"><h3>{{ configuration.title}}</h3></div>
        <div class="form-group col-3 m-1">
            <label class="form-group">{{ configuration.body }}</label>
        </div>
    <button id="btn{{ configuration.codConfi }}" type="submit" class="btn btn-info ml-auto mr-0 mr-md-3 my-2 my-md-4">{{ configuration.OptionBtn }}</button>
</div>

All this is displayed properly and perfect. But when it comes to the form DB colum...

<!-- _______________________Forms iterations__________________________ -->
<form style="display:none" id="frm{{ configuration.codConfi }}" class="breadcrumb form-inline" action="/Config/{{ configuration.codConfi }}" method="POST" enctype="application/x-www-form-urlencoded">{% csrf_token %}
    <div class="form-group col-12" style="color:#228718"><h3>Configure {{ configuration.Title }}</h3></div>
        {% for field in configuration.form %}
            <div class="form-group col-3 m-1">
                <label class="form-group">{{ field.label }}: </label>
                {{ field }}
            </div>
        {% endfor %}
    <button type="submit" class="btn btn-success ml-auto mr-0 mr-md-3 my-2 my-md-4">Apply changes</button>
</form>
{% endfor %}

(If you see some attrs that are not showed in my example table it's just because I haven't typed all of them).

Instead of displaying the actual forms properly, it is displaying the value of form DB's column as a string. For instance, for the first value in form column (DataConfig()) it is displaying every letter as a string in the iteration (first it displays "D", then "a", then "t", etc until the last ")"). How can I tell Django it is not a String value but a variable?


Solution

  • On your Django model Configuration you could add a property that fetches and instanciates the actual form class.

    For example:

    class Configuration(models.Model):
        ...
    
        def get_form(self):
            # 'forms_module' is the Python module (file) that holds the form classes
            # 'self.form' is a string that holds the name of the form class
            form_class = getattr(forms_module, self.form)
    
            # create an (un-bound) instance of the form
            return form_class()
    

    Then, in your template (assuming that configuration is an instance of the model Configuration) you can change this line:

    {% for field in configuration.form %}
    

    into this

    {% for field in configuration.get_form %}
    

    Note: for this to work, you will need to store the form class name without the parethesis in your DB field (or remove the parethesis before calling getattr(forms_module, self.form)).


    If you need something more specific you will need to add more info to your question.