Dynamically load and execute the function code and render the template using the provided data

Hello. My task is to create a platform where teachers will insert auto generated questions in the form of code from various fields. The only idea I can come up with is to create a form with 2 fields to add function(logic) and html template, then save these codes as strings in database. When rendering the exercise for students, I will dynamically load and execute the function code and render the template using the provided data. I know this can cause an app crash and it violence the security, but I’ll deal with that later. I created functions to add exercise for teachers. Unfortunately, after adding the exercise, I only see the text from the teacher template without the generated date. When the teacher adds the html template, he is asked to enter =“{{ exercise.url }}”> in the action. I generates a url for each exercise added by the teacher. Below is an example of functions and html that a teacher could add. I don’t know if what I’m doing is possible and if i can send view logic and template code to the database and dynamically load and execute ? Sorry for such a long post. here are my funcions:

def add_question(request):
    if request.method == 'POST':
        form = ExerciseForm(request.POST)
        if form.is_valid():
            chapter_name1 = form.cleaned_data['chapter_name1']
            exercise_name1 = form.cleaned_data['exercise_name1']
            function_code = form.cleaned_data['function_code']
            template_code = form.cleaned_data['template_code']

            # Generate a unique URL for the exercise
            url = get_random_string(length=10)

            # Save the function code, template code, and URL as strings in the database
            exercise = Exercise(
                chapter_name1=chapter_name1,
                exercise_name1=exercise_name1,
                function_code=function_code,
                template_code=template_code
            )
            exercise.save()

            # Associate the generated URL with the exercise
            exercise.url = url
            exercise.save()

            # Redirect to the detail view of the created exercise
            return redirect('teacher:detail', url=exercise.url)
    else:
        form = ExerciseForm()

    return render(request, 'teacher/add_question.html', {'form': form})

def detail(request, url):
    exercise = get_object_or_404(Exercise, url=url)

    # Get the function code and template code as strings from the exercise model
    function_code = exercise.function_code
    template_code = exercise.template_code

    # Create a context dictionary to hold the data for rendering the template
    context = {
        'exercise': exercise,
        'question': exercise,  # Pass the exercise object as 'question' to the template
    }
    try:
        # Dynamically load and execute the function code
        exec(function_code, globals(), context)
        print("Function code executed successfully.")  # Debug print
    except Exception as e:
        import traceback
        traceback.print_exc()
        # Handle the exception or return an error response


    # Render the template using the provided data
    template_engine = engines['django']
    template = template_engine.from_string(template_code)
    rendered_template = template.render(context, request)

    return render(request, 'teacher/detail.html', {'exercise': exercise, 'rendered_template': rendered_template})     

add_question.html:

<form method="post" action="{% url 'teacher:add_question' %}">
    {% csrf_token %}
    {{ form.as_p }}
    <button type="submit">Save Exercise</button>
</form>

detail.html:

    <h2>Exercise Details</h2>
<p>Chapter: {{ exercise.chapter_name1 }}</p>
<p>Exercise: {{ exercise.exercise_name1 }}</p>
<h3>Rendered Template:</h3>
{{ rendered_template|safe }}   

example of teacher html:

 <!DOCTYPE html>
<html>
<head>
    <title>Grouped Frequency Distribution</title>
</head>
<body>
    <h1>Grouped Frequency Distribution</h1>

    <h2>These data represent the record high temperatures in degrees Fahrenheit (°F) for each of
        the 50 states. Construct a grouped frequency distribution for the data, using 7 classes.</h2>

    <h2>Data:</h2>
    <table>
        {% for row in data %}
            <tr>
                {% for value in row %}
                    <td>{{ value }}</td>
                {% endfor %}
            </tr>
        {% endfor %}
    </table>

    <h2>Enter the frequency:</h2>
    <form method="POST" action= "{{ exercise.url }}">
        {% csrf_token %}
        {% for lower_limit, upper_limit, _ in frequency_distribution %}
            <label for="input_{{ forloop.counter }}">Class limits {{ lower_limit }} - {{ upper_limit }}:</label>
            <input type="number" id="input_{{ forloop.counter }}" name="input_{{ forloop.counter }}">
            <br>
        {% endfor %}
        <button type="submit">Submit</button>
    </form>

    {% if is_correct is not None %}
        {% if is_correct %}
            <h2>Congratulations! Your results are correct.</h2>
        {% else %}
            <h2>Sorry, your results are incorrect. Please try again.</h2>
        {% endif %}
    {% endif %}
</body>
</html>

example of teacher function:

import random
import numpy as np
from django.shortcuts import render

def calculate_frequency(request):
    # Generate random data
    data = [random.randint(100, 134) for _ in range(50)]
    num_rows = 5
    num_columns = 10
    data_table = [data[i:i + num_columns] for i in range(0, len(data), num_columns)]

    # Step 1: Determine the classes
    H = max(data)  # Highest value
    L = min(data)  # Lowest value
    R = H - L  # Range
    num_classes = 7
    class_width = R / num_classes


    # Step 2: Calculate the class boundaries
    lower_class_limit = L
    class_boundaries = [lower_class_limit + i * class_width for i in range(num_classes + 1)]
    upper_class_limit = class_boundaries[1:]

    # Step 3: Tally the data
    tally = [0] * num_classes
    for value in data:
        for i, upper_limit in enumerate(upper_class_limit):
            if value <= upper_limit:
                tally[i] += 1
                break

    if request.method == 'POST':
        user_tally = []
        for i in range(num_classes):
            user_input = int(request.POST.get(f'input_{i+1}'))
            user_tally.append(user_input)

        # Compare user's results with the correct results
        correct_tally = tally
        correct = np.array(correct_tally)
        user = np.array(user_tally)

        # Check if the user's results match the correct results
        is_correct = np.array_equal(correct, user)
    else:
        is_correct = None

    # Step 4: Generate the grouped frequency distribution
    frequency_distribution = []
    for i in range(num_classes):
        lower_limit = int(class_boundaries[i])  # Convert lower limit to integer
        upper_limit = int(class_boundaries[i + 1])  # Convert upper limit to integer
        tally_value = tally[i]
        frequency_distribution.append((lower_limit, upper_limit, tally_value))

    context = {
        'data': data_table,
        'frequency_distribution': frequency_distribution,
        'is_correct': is_correct,
    }
    return render(request, 'instructor/frequency_distribution.html', context)

Side Note: When posting code (or templates) here, enclose the code between lines of three backtick - ` characters. This means you’ll have a line of ```, then your code, then another line of ```. This forces the forum software to keep your code properly formatted. I’ve taken the liberty of editing this post for you.

1 Like