Django ModelForm 预填充全部记录时遇报错及字段不渲染问题求助
Hey there, let's break down what's going wrong with your code and fix it step by step! Your goal is to display pre-filled forms for all your RunningHours records, but you're hitting two main issues—let's tackle each one and get your forms working correctly.
Why You're Seeing These Problems
First Error:
'QuerySet' object has no attribute '_meta'
This happens because you're trying to pass an entire QuerySet (a collection of objects) where Django expects a single model instance. ModelForms are designed to work with one object at a time by default, so feeding it aRunningHours.objects.all()directly (either as the instance or in a malformedinitialdict) will throw this error.Second Issue: Unrendered Fields with
initial
Your lineform_populated = RunningHoursModelForm(initial={runninghours})uses invalid syntax—initialexpects a dictionary of field names to values (e.g.,{'name': 'My Machine', 'current_runninghours': 100}), not a QuerySet wrapped in a dict. Even if you fixed the syntax, a single ModelForm can't handle multiple objects at once.
The Solution: Use ModelFormSets
To display pre-filled forms for all your RunningHours records, you need to use Django's modelformset_factory—it creates a set of forms, one for each object in your QuerySet, and handles pre-population automatically.
Step 1: Update Your views.py
We'll import the formset factory, set up the formset, and handle both creation and update logic:
from django.shortcuts import render, redirect from django.forms import modelformset_factory from .models import RunningHours from .forms import RunningHoursModelForm def runninghours(request): # Create a formset for RunningHours, no extra empty forms RunningHoursFormSet = modelformset_factory( RunningHours, form=RunningHoursModelForm, extra=0 ) if request.method == 'POST': # Handle new record creation if 'form-create' in request.POST: form = RunningHoursModelForm(request.POST) if form.is_valid(): form.save() return redirect(request.path_info) # Handle record updates elif 'form-update' in request.POST: formset = RunningHoursFormSet(request.POST, queryset=RunningHours.objects.all()) if formset.is_valid(): formset.save() return redirect(request.path_info) # Initialize forms for GET requests create_form = RunningHoursModelForm() update_formset = RunningHoursFormSet(queryset=RunningHours.objects.all()) context = { "create_form": create_form, "update_formset": update_formset } return render(request, 'runninghours.html', context)
Step 2: Fix Your forms.py
Your original form was missing proper indentation for the Meta class—this is a critical syntax error:
from django import forms from .models import RunningHours class RunningHoursModelForm(forms.ModelForm): class Meta: model = RunningHours fields = ("name", "current_runninghours", "last_runninghours",)
Step 3: Update Your Template (runninghours.html)
We'll loop through the formset to render a pre-filled form for each record, and keep your separate create form:
<!-- Form to create a new RunningHours record --> <form method="POST" action=""> {% csrf_token %} <div class="create-form"> {% render_field create_form.name %} {% render_field create_form.current_runninghours %} {% render_field create_form.last_runninghours %} <input name="form-create" type="submit" class="button1" value='Create Runninghours' /> </div> </form> <!-- Forms to update existing records --> {% for form in update_formset %} <form method="POST" action=""> {% csrf_token %} {{ form.id }} <!-- Required hidden field: lets Django identify which object to update --> <tr> <td>{% render_field form.name %}</td> <td>{% render_field form.current_runninghours %}</td> <td>{% render_field form.last_runninghours %}</td> <td>{{ form.instance.last_modified }}</td> <!-- Display read-only date --> <td> <input name="form-update" type="submit" class="button1" value='Update Runninghours' /> </td> </tr> </form> {% empty %} <p>No running hours records found yet. Create your first one above!</p> {% endfor %}
Key Fixes Explained
modelformset_factory: Generates a formset that works with multiple model objects.extra=0ensures we don't get empty forms for new records (since we have a separate create form).form.idHidden Field: Mandatory for formsets—Django uses this to map form data back to the correct database object.form.instance.last_modified: Since you didn't includelast_modifiedin your form fields, we directly access the model instance's value to display it (it's read-only here, which makes sense given your default date setting).- Separate Create/Update Logic: We check which submit button was clicked to handle either creating a new record or updating existing ones.
内容的提问来源于stack exchange,提问作者newprogrammer12

