You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用as_crispy_field渲染Django表单时持续报错:as_crispy_field got passed an invalid or inexistent field

Fixing "as_crispy_field got passed an invalid or inexistent field" in Django

Let's break down why you're hitting this error and walk through the fixes step by step:

Root Causes of the Error

  1. Incorrect form initialization for GET requests: You're creating a form bound to request.POST even when handling GET requests (which have empty POST data). This confuses crispy forms about the state of your fields.
  2. Uninitialized foreign key fields: Your company and sender fields aren't getting default values, so crispy forms struggles to render them correctly.
  3. Missing file upload support: Your form handles a FileField but doesn't include the required enctype attribute, which will cause upload failures later (even if it's not the immediate error).

Step 1: Fix the View Logic

Update your send_email view to properly initialize the form for GET requests, set default values for foreign key fields, and handle file uploads in POST:

from django.contrib import messages
from django.shortcuts import get_object_or_404, render

def send_email(request, id):
    customer = get_object_or_404(Customer, pk=id)
    customers = Customer.objects.all()

    if request.method == 'GET':
        # Initialize an unbound form with default values for foreign keys
        initial_data = {
            'company': customer,  # Auto-set to the selected customer
            'sender': request.user  # Auto-set to the logged-in user
        }
        form = Customer_Email_Form(initial=initial_data)
        context = {"customer": customer, "email_form": form, "customers": customers}
        return render(request, 'crm/email_form.html', context)

    # Handle POST requests (including file uploads)
    if request.method == 'POST':
        form = Customer_Email_Form(request.POST, request.FILES)
        if form.is_valid():
            # Save without committing to DB first to set values explicitly
            email_instance = form.save(commit=False)
            email_instance.sender = request.user
            email_instance.company = customer
            email_instance.save()
            messages.success(request, "Email Sent")
            return render(request, 'crm/listing.html', context)
        
        # If form is invalid, return it with errors
        context = {"customer": customer, "email_form": form, "customers": customers}
        return render(request, 'crm/email_form.html', context)

Step 2: Update the HTML Template

Add the required enctype for file uploads, and convert your company and sender fields to hidden inputs (since users shouldn't need to edit them):

{% load crispy_forms_tags %}
<!-- Add enctype to support file uploads -->
<form class="" method="POST" enctype="multipart/form-data">
    {% csrf_token %}
    <div class="form-group m-2">
        <label>Subject</label>
        {{ email_form.subject|as_crispy_field }}
    </div>
    <div class="form-group m-2">
        <label>Message</label>
        {{ email_form.message|as_crispy_field }}
    </div>
    <div class="form-group m-2">
        <label>Upload</label>
        {{ email_form.file_upload|as_crispy_field }}
        <span class="color-secondary">you can attach 2M files (pdf,doc)</span>
    </div>
    <!-- Hide foreign key fields since they're auto-populated -->
    {{ email_form.company.as_hidden }}
    {{ email_form.sender.as_hidden }}
    <button class="btn btn-primary btn-lg mt-5" type="submit" hx-post="email_form/p={{customer.id}}" hx-target="#crm-list" data-dismiss="modal" >
        Send Email <i class='bx bx-mail-send bx-xl'></i>
    </button>
</form>

Step 3: Verify Crispy Forms Setup

Double-check your settings.py to ensure crispy forms is properly configured (this is a common overlooked step):

INSTALLED_APPS = [
    # ... your other apps
    'crispy_forms',
    'crispy_bootstrap5',  # Use bootstrap4 if you're on an older Bootstrap version
]

# Set the template pack matching your project's Bootstrap version
CRISPY_TEMPLATE_PACK = 'bootstrap5'

Why This Works

  • Unbound form for GET: Creating an unbound form (without request.POST) ensures crispy forms recognizes all fields correctly when rendering the empty form.
  • Hidden foreign keys: By hiding company and sender, you avoid rendering issues while still passing their values to the backend.
  • File upload support: The enctype="multipart/form-data" attribute lets Django process the uploaded file correctly.

内容的提问来源于stack exchange,提问作者Ahmad Hashim

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.27 16:37:27