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

Django自定义预填充表单跳转出现404错误求助

问题描述

开发自定义宠物领养项目时遇到以下问题:

  • 页面展示待领养宠物列表,每个宠物设有详情按钮;
  • 已登录用户在详情页可见“Adopt”按钮,点击该按钮需跳转到带有该宠物模型预填充字段的表单页面;
  • 用户补充少量新字段后提交,应提示领养请求已发送。

目前第一个待领养宠物的pk为1,但访问对应URL时出现404错误,提示未找到匹配的AnimalAdoptSend对象。

错误信息

Page not found (404)
No animal adopt send found matching the query
Request Method: GET
Request URL: http://127.0.0.1:8000/animals/adoption/details/1/adopt/
Raised by: animals.views.AnimalAdoptFormSendView

相关代码

子应用 urls.py

urlpatterns = [
    path('adoption/create/', AnimalAdoptCreateView.as_view(), name='animal_adopt_create'),
    path('adoption/', AnimalAdoptListView.as_view(), name='adoption_animals'),
    path('adoption/details/<int:pk>', AnimalAdoptDetails.as_view(), name='adoption_animals_details'),
    path('adoption/details/<int:pk>/adopt/', AnimalAdoptFormSendView.as_view(), name='adopt_form'),
]

views.py

class AnimalAdoptDetails(LoginRequiredMixin, DetailView):
    model = AnimalAdoptReadyCreate
    template_name = 'animal_adopt_detail.html'

class AnimalAdoptFormSendView(LoginRequiredMixin, UpdateView):
    model = AnimalAdoptSend
    form_class = AnimalAdoptSendForm
    template_name = 'animal_adopt_form.html'

models.py

class AnimalAdoptReadyCreate(models.Model):
    animal_choice = {
        ('dog', 'Dog'),
        ('cat', 'Cat'),
        ('other', 'Other')
    }

    animal_name = models.CharField(max_length=20)
    animal_type = models.CharField(max_length=30, choices=animal_choice)
    location = models.CharField(max_length=60)
    details = models.TextField()
    other = models.TextField(blank=True)
    user = models.ForeignKey(CustomUser, on_delete=models.CASCADE)
    picture = models.ImageField(upload_to='pets_for_adoption/')

    def __str__(self):
        return self.animal_name


class AnimalAdoptSend(AnimalAdoptReadyCreate):
    place_to_live = models.CharField(max_length=50)
    picture_of_place = models.ImageField(upload_to='owner_homes/%Y/%m/%d/')
    other_pets = models.TextField()
    other_details = models.TextField(blank=True, null=True)

forms.py

class AnimalAdoptSendForm(forms.ModelForm):
    class Meta:
        model = AnimalAdoptSend
        fields = [
            'animal_name', 'picture', 'location', 'animal_type', 'place_to_live', 'other_pets', 'other_details', 'picture_of_place'
        ]

宠物详情页模板

{% extends 'base.html' %}
{% load static %}

{% block content %}
    <main>
        <div>
            <h2>Pet name: {{ object.animal_name }}</h2>
            <p><img src="{{ object.picture.url }}" alt="None"></p>
            <p>Location: {{ object.location }}</p>
            <p>Type: {{ object.animal_type }}</p>
            <p>Contact with the current owner: {{ object.user.phone }}</p>
            {% if object.other %}
                <p>Other Details: {{ object.other }}</p>
            {% endif %}
            <button><a href="{% url 'adopt_form' object.pk %}">Adopt</a></button>
        </div>
    </main>
{% endblock %}

预填充表单页模板

{% extends 'base.html' %}
{% load static %}

{% block content %}
    <main>
        {% if request.user.is_authenticated %}
            <form method="post" action="">
                {% csrf_token %}
                {{ form.as_p }}
                <button type="submit">Save</button>
            </form>
{#            <h2>Pet name: {{ object.animal_name }}</h2>#}
{#            <p><img src="{{ object.picture.url }}" alt="None"></p>#}
{#            <p>Location: {{ object.location }}</p>#}
{#            <p>Type: {{ object.animal_type }}</p>#}
{#            <p>Place to Live: {{ object.place_to_live }}</p>#}
{#            <p>Other Pets: {{ object.other_pets }}</p>#}
{#            {% if object.other_details %}
                <p>Other Details: {{ object.other_details }}</p>#}
{#            {% endif %}
{#            <p><img src="{{ object.picture_of_place.url }}" alt="None"></p>#}
        {% endif %}
    </main>
{% endblock %}

主 urls.py

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('common.urls')),
    path("accounts/", include("django.contrib.auth.urls")),
    path("accounts/", include("accounts.urls")),
    path('petshop/', include('shop.urls')),
    path('animals/', include('animals.urls')),
]

解决方案

出现404的核心原因:你用了UpdateView处理领养请求,但AnimalAdoptSend是继承AnimalAdoptReadyCreate的多表继承模型,两张表在数据库中独立存储。访问pk=1的领养URL时,UpdateView会去AnimalAdoptSend表查找pk=1的记录,但该记录尚未创建(还没人提交过该宠物的领养请求),因此抛出404。

正确逻辑是新建领养请求记录,而非更新,需修改视图并预填充原宠物字段:

1. 修改 views.py

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

class AnimalAdoptFormSendView(LoginRequiredMixin, CreateView):
    model = AnimalAdoptSend
    form_class = AnimalAdoptSendForm
    template_name = 'animal_adopt_form.html'
    success_url = '/animals/adoption/'  # 可根据需求调整跳转地址

    def get_initial(self):
        # 获取原宠物对象,预填充表单字段
        animal = get_object_or_404(AnimalAdoptReadyCreate, pk=self.kwargs['pk'])
        return {
            'animal_name': animal.animal_name,
            'picture': animal.picture,
            'location': animal.location,
            'animal_type': animal.animal_type,
        }
    
    def form_valid(self, form):
        # 提交成功后添加提示信息
        messages.success(self.request, '领养请求已发送,请等待审核')
        return super().form_valid(form)

2. 调整表单字段(可选)

若希望原宠物的基础字段不允许用户修改,可在表单中设置禁用:

class AnimalAdoptSendForm(forms.ModelForm):
    class Meta:
        model = AnimalAdoptSend
        fields = [
            'animal_name', 'picture', 'location', 'animal_type', 'place_to_live', 'other_pets', 'other_details', 'picture_of_place'
        ]
    
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # 禁用基础字段,防止用户修改
        for field_name in ['animal_name', 'picture', 'location', 'animal_type']:
            self.fields[field_name].widget.attrs['disabled'] = True
            self.fields[field_name].required = False

3. 模板调整(可选)

添加文件上传编码类型,并优化预填充内容展示:

{% extends 'base.html' %}
{% load static %}

{% block content %}
    <main>
        {% if request.user.is_authenticated %}
            <h3>领养申请:{{ form.animal_name.value }}</h3>
            <p><img src="{{ form.picture.value.url }}" alt="宠物照片" style="width:200px;"></p>
            <form method="post" enctype="multipart/form-data">
                {% csrf_token %}
                {{ form.as_p }}
                <button type="submit">提交领养请求</button>
            </form>
        {% endif %}
    </main>
{% endblock %}

额外说明

多表继承会在AnimalAdoptSend表生成指向AnimalAdoptReadyCreate的外键(默认名为animaladoptreadycreate_ptr_id),若需关联原宠物而非复制信息,可在form_valid中手动设置:

def form_valid(self, form):
    animal = get_object_or_404(AnimalAdoptReadyCreate, pk=self.kwargs['pk'])
    form.instance.animaladoptreadycreate_ptr = animal
    messages.success(self.request, '领养请求已发送,请等待审核')
    return super().form_valid(form)

内容的提问来源于stack exchange,提问作者Danail Lesev

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 05:08:06