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

Django表单输入邮编时关联显示对应城市的实现问询

实现注册Person时输入邮编自动显示对应城市

问题描述

我始终没能找到解决办法,这应该是个简单问题。我有两个模型:Person(包含name和zipcode字段)和Zip(包含zipcode和city字段)。在注册新Person时,需输入姓名和邮编,希望输入邮编后自动显示Zip模型中对应的城市。以下是我的现有代码:

现有代码

models.py

class Zip(models.Model):
    zipcode = models.IntegerField()
    city = models.CharField(max_length=200)

    def __str__(self):
        return str(self.zipcode)

class Person(models.Model):
    name = models.CharField(max_length=200)
    zipcode =  models.ForeignKey('Zip',on_delete=models.CASCADE,)

    def __str__(self):
        return self.name

forms.py

from django import forms 
from .models import Zip, Person

class PersonForm(forms.ModelForm):
    class Meta:
        model = Person
        fields = ('name', 'zipcode',)
        
class ZipForm(forms.ModelForm):
    class Meta:
        model = Zip
        fields = ('zipcode', 'city',)

views.py

from django.shortcuts import render, redirect, get_object_or_404
from .forms import PersonForm, ZipForm
from .models import Zip, Person

def index(request):
    return render(request, 'theapp/index.html' )

def person_new(request):
    if request.method == "POST":
        form = PersonForm(request.POST)

        if form.is_valid():
            post = form.save(commit=False)

            post.save()
            return redirect('person_detail', pk=post.pk)
        
    else:
        form = PersonForm()
    return render(request, 'theapp/person.html', {'form': form})

def zip_new(request):
    if request.method == "POST":
        form = ZipForm(request.POST)
        
        if form.is_valid():
            post = form.save(commit=False)
            post.save()
            return redirect('zip_detail', pk=post.pk)
    else:
        form = ZipForm()
    return render(request, 'theapp/zip.html', {'form': form})


def person_detail(request, pk):
    post = get_object_or_404(Person, pk=pk)
    return render(request, 'theapp/person_detail.html', {'post': post})

def zip_detail(request, pk):
    post = get_object_or_404(Zip, pk=pk)
    return render(request, 'theapp/zip_detail.html', {'post': post})

person.html

{% block body %}
    <section>
        <h2>new person</h2>
           </section>

           
           <form method="POST" class="person-form">{% csrf_token %}
            {{ form.as_p }}
            <button type="submit" class="save btn btn-secondary">Save person</button>
        </form>


{% endblock %}

期望效果:输入邮编后自动显示对应城市(如输入邮编后显示New York)。

解决方案

要实现输入邮编后自动显示城市,需要通过前端AJAX请求后端接口获取对应城市,具体步骤如下:

1. 修改PersonForm,替换邮编为文本输入框

默认ForeignKey会生成下拉框,我们需要让用户手动输入邮编,修改forms.py:

class PersonForm(forms.ModelForm):
    # 替换默认下拉框为文本输入框
    zipcode = forms.IntegerField(label="邮编")
    
    class Meta:
        model = Person
        fields = ('name', 'zipcode',)

2. 添加后端API接口,根据邮编返回城市

在views.py中新增处理AJAX请求的视图:

from django.http import JsonResponse
from .models import Zip

def get_city_by_zip(request):
    zipcode = request.GET.get('zipcode')
    try:
        zip_obj = Zip.objects.get(zipcode=zipcode)
        return JsonResponse({'city': zip_obj.city})
    except Zip.DoesNotExist:
        return JsonResponse({'city': '未找到对应城市'})

3. 配置URL路由

在项目的urls.py中添加API路由:

from django.urls import path
from . import views

urlpatterns = [
    # 保留原有路由...
    path('get-city/', views.get_city_by_zip, name='get_city_by_zip'),
]

4. 修改person.html,添加AJAX逻辑

在模板中添加城市显示区域,并用JavaScript监听邮编输入变化:

{% block body %}
    <section>
        <h2>new person</h2>
    </section>

    <form method="POST" class="person-form">{% csrf_token %}
        {{ form.as_p }}
        <!-- 新增城市显示区域 -->
        <div>
            <label>对应城市:</label>
            <span id="city-display"></span>
        </div>
        <button type="submit" class="save btn btn-secondary">Save person</button>
    </form>

    <script>
        const zipInput = document.querySelector('#id_zipcode');
        const cityDisplay = document.querySelector('#city-display');

        zipInput.addEventListener('input', function() {
            const zipcode = this.value.trim();
            if (zipcode) {
                fetch(`/get-city/?zipcode=${zipcode}`)
                    .then(response => response.json())
                    .then(data => {
                        cityDisplay.textContent = data.city;
                    })
                    .catch(() => {
                        cityDisplay.textContent = '获取城市失败';
                    });
            } else {
                cityDisplay.textContent = '';
            }
        });
    </script>
{% endblock %}

5. 保存Person时关联Zip模型

修改person_new视图,处理输入的邮编并关联对应的Zip对象:

def person_new(request):
    if request.method == "POST":
        form = PersonForm(request.POST)

        if form.is_valid():
            zipcode = form.cleaned_data['zipcode']
            try:
                zip_obj = Zip.objects.get(zipcode=zipcode)
                person = Person(
                    name=form.cleaned_data['name'],
                    zipcode=zip_obj
                )
                person.save()
                return redirect('person_detail', pk=person.pk)
            except Zip.DoesNotExist:
                form.add_error('zipcode', '该邮编未收录,请先添加邮编信息')
    else:
        form = PersonForm()
    return render(request, 'theapp/person.html', {'form': form})

完成以上步骤后,用户输入邮编时前端会实时显示对应城市,提交表单时系统会验证邮编是否存在并关联Zip对象。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 01:05:00