ModelForm not displaying in view

I’m trying to create a ModelForm to add info to a database from the view but the only thing displaying is the submit button. I tried using the documentation but I can’t tell why the form isn’t showing up. Here is what I have so far

forms.py

from django.forms import ModelForm
from .models import Edge

class EdgeForm(ModelForm):
    class Meta:
        model = Edge
        exclude = ["user"]

views.py

@login_required(login_url="/login")
def def_edge(request):
    form = EdgeForm
    if form.is_valid:
        return redirect("/meaiapp/dashboard")
    else:
        form = EdgeForm()
    return render(request, "meai/meai_edge.html", {"form": form})

template

{% extends "_app.html" %}

{% block content %}
<form action="" method="POST">
    {% csrf_token %}
    {{ form.as_p }}
    <div class="container d-flex justify-content-center">
        <button type="submit" class="btn btn-success col-12">Submit</button>
    </div>
</form>
{% endblock %}

You need to create an instance of your EdgeForm:
form = EdgeForm()

You have other errors as well.

You want to review the the examples on the Working with forms page, paying particular attention to the syntax of the code.

The page still shows the submit button only, I updated the code in views.py below. Are there errors in the forms.py too?

from django.shortcuts import render
from django.http import HttpResponseRedirect
from django.contrib.auth.decorators import login_required
from .forms import EdgeForm

# Create your views here.
@login_required(login_url="/login")
def def_edge(request):
    if request.method == "POST":
        form = EdgeForm(request.POST)
        if form.is_valid():
            form.save()
            return HttpResponseRedirect("/meaiapp/dashboard")
    else:
        form = EdgeForm()
        return render(request, "meai/meai_dashboard.html", {"form": form})

What does your Edge model look like? What does the “_app.html” template look like?
(I don’t see anything wrong here.)

Also, please confirm what directory that template is located in. (Do you possibly have a second copy of meai/meai_dashboard.html in a different location?)

Edge Model

from django.db import models
from django.utils import timezone
from usermgmt.models import UserProfile
 

# 1 to 1 with UserProfile
class Edge(models.Model):
    user = models.OneToOneField(UserProfile, on_delete=models.CASCADE)
    ROBINHOOD = "Robinhood"
    OTHER = "Other"
    BROKER_CHOICES = (
        (ROBINHOOD, "Robinhood"),
        (OTHER, "Other")
    )
    broker = models.CharField(max_length=20, choices=BROKER_CHOICES, default="ROBINHOOD")

    CASH = "Cash"
    MARGIN = "Margin"
    ACCT_TYPE_CHOICES = (
        (CASH, "Cash"),
        (MARGIN, "Margin")
    )
    acct_type = models.CharField(max_length=10, choices=ACCT_TYPE_CHOICES, default="MARGIN")

    SHARES = "Shares"
    CONTRACTS = "Contracts"
    INST_TYPE_CHOICES = (
        (SHARES, "Shares"),
        (CONTRACTS, "Contracts")

    )
    inst_type = models.CharField(max_length=20, choices=INST_TYPE_CHOICES, default="SHARES")

    min_inst_price = models.IntegerField(null=True)
    max_inst_price = models.IntegerField(null=True)
    acct_size = models.IntegerField(null=False)
    min_profit = models.FloatField(null=True)
    max_risk = models.FloatField(null=True)

    CONSERVATIVE = "Conservative"
    MODERATE = "Moderate"
    AGGRESSIVE = "Aggressive"
    RISK_PROFILE_CHOICES = (
        (CONSERVATIVE, "Conservative"),
        (MODERATE, "Moderate"),
        (AGGRESSIVE, "Aggressive")
    )
    risk_profile = models.CharField(max_length=20, choices=RISK_PROFILE_CHOICES, default="MODERATE")
    trade_freq = models.IntegerField(null=True)

    class Meta:
        verbose_name = "Edge"
        verbose_name_plural = "Edge (by user)"

_app.html

{% load static %}

<!DOCTYPE html>
<html lang="en" data-bs-theme="light" class="bg-light">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{% block title%}{% endblock %} | MaxEdgE AI</title>
    <!-- BOOTSTRAP v5 CSS CDN -->
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/css/bootstrap.min.css">
    <!-- BOOTSTRAP ICONS -->
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.3.0/font/bootstrap-icons.css">
     <!-- IMPORT CUSTOM CSS FILE -->
    <link rel="stylesheet" href="{% static 'css/styles.css' %}">
</head>
<body>
        <!-- NAVBAR -->
        <nav class="navbar navbar-expand-lg navbar-light bg-light">
            <div class="container-fluid">
                <a class="navbar-brand" href="http://127.0.0.1:8000/meaiapp/dashboard" style="font-size: xx-large; font-weight: bolder; color: #001f1d;">MAXEdgE AI</a>
                <button 
                class="navbar-toggler" 
                type="button" 
                data-bs-toggle="collapse" 
                data-bs-target="#navbarTogglerMenu" 
                aria-controls="navbarTogglerMenu" 
                aria-expanded="false" 
                aria-label="Toggle navigation">
                <span class="navbar-toggler-icon"></span>
                </button>
                <div class="collapse navbar-collapse" id="navbarTogglerMenu">
                    <ul class="navbar-nav ms-auto mx-2">
                        <li class="nav-item dropdown mx-3">
                            <a class="nav-link dropdown-toggle text-dark" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">
                            Menu
                            </a>
                            <ul class="dropdown-menu p-1" style="background-color: #001f1d;">
                            <li><a class="dropdown-item text-secondary" href="http://127.0.0.1:8000/meaiapp/dashboard/">Dashboard</a></li>
                            <li><a class="dropdown-item text-secondary" href="http://127.0.0.1:8000/meaiapp/projections/">Projections</a></li>
                            <!-- <li><hr class="dropdown-divider"></li> -->
                            <li><a class="dropdown-item text-secondary" href="http://127.0.0.1:8000/meaiapp/tmt/">TMT</a></li>
                            <li><a class="dropdown-item text-secondary" href="http://127.0.0.1:8000/meaiapp/tracker/">EDGE Tracker</a></li>
                            </ul>
                        </li>
                    {% if user.is_authenticated %}
                    <span class="navbar-text text-dark" style="font-size: large;">Logged in as {{user.first_name}} {{user.last_name}} | </span>
                    <li class="nav-item mx-3">
                        <a class="nav-link active" aria-current="page" href="http://127.0.0.1:8000/logout/">Sign Out</a>
                    </li>
                    {% else %}
                    <li class="nav-item mx-3">
                        <a class="nav-link active" aria-current="page" href="http://127.0.0.1:8000/login/">Log In</a>
                    </li>
                    {% endif %}
                </div>
            </div>
        </nav>
    </header>
    <section class="container-fluid">
    {% block content %}

    {% endblock %}
    </section>
    <!-- BOOTSTRAP v5 JAVASCRIPT CDN -->
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>

I only have the templates separated by app, does that affect anything? Here is a screenshot of the location

I’m really stuck here. The code in views.py should work and I can see the form in the shell, why is the form not displaying?

Look at the html as it has been rendered in the browser to see if it’s in the page that has been sent. If it is, then you may have some css that is causing it to be obscured.

Also, in your original post you showed the template containing the {{ form.as_p }} reference but you didn’t specify which file that was in. Are you sure you’re rendering the right template here?

Ok. I believe I’m using the correct template if I understand what you are saying (unless you mean the {{form.as_p}} referencing ‘form’ from a specific file; I thought the form variable is limited in scope to the view being used). Also compared this html to the login/register forms which show the form fields and are being rendered with no issues. I’m not sure what it means but this is what the html for this form looks like. I’m only using bootstrap css at this point

Yes, I was asking you to confirm the file names involved. You’ve shown two different views referencing two different template names - and you’ve shown a fragment of a template rendering a form but without identifying the file name. So I was asking you to verify that you’re rendering the correct template.

Within the <form tag there is a div that can be expanded. Check that out to see if the form is present in that div. (You don’t need to post it here.)

If it’s just the button, then it’s very likely that you’re not rendering the template that you think you’re rendering. To check/verify this, make some other change to the template outside the form tag (add some text in an <h1> tag for example) and see if that is showing up on the page. If it isn’t then you’re not rendering the correct template.

Ok so the code inside the div tag was the button only, I added text in a h1 tag and it actually does show up on the page. If the correct template is being rendered, what else could be the issue? Removing the bootstrap didn’t fix it either

Do you have any other views that are rendering that same template?

Another step would be to add print statement in that view before the render to print(form.as_p()) and see what shows up in the runserver console.

I did have a second view using the same template, changed the return statement to render a different template. I’m using a different template for each view now, still no change so I’ve added the print statement in the view.

updated view

@login_required(login_url="/login")
def def_edge(request):
    if request.method == "POST":
        form = EdgeForm(request.POST)
        if form.is_valid():
            form.save()
            print(form.as_p())
            return HttpResponseRedirect("/meaiapp/edge")
        else:
            form = EdgeForm()
            return render(request, "meai/meai_edge.html", {"form": form})
    else:
        return render(request, "meai/meai_edge.html")

To clarify, when you say runserver console are you referring to the console in the browser? I’m not seeing anything there

No, I’m referring to the window in which you’re running runserver.

The problem is here:

You’re not passing the form in the context to the rendering engine - that’s why it’s not being rendered.

Ok the form is working now, thanks really appreciate your help! One more question about the view, when I passed the form in the context I had to define form again. For the nested else statement, what would that typically handle? Or is it unnecessary to have there since the form validation is being addressed?

I’m sorry, I’m not sure I’m following what you’re trying to ask here.

In general, a function-based view will frequenty follow the pattern as described in the “view” section of the Working with Forms docs. (It would probably be worth your time to review the entire page. Now that you’ve got some more experience, you may understand more than you would have previously.)

1 Like