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

在Django+Crispy Forms项目中集成intl-tel-input获取国家信息

Django集成intl-tel-input到Crispy Forms表单的正确方案

原始场景与问题

我在开发一个基于Django Crispy Forms的项目,现有如下表单和模型:

ClientForm表单代码

class ClientForm(forms.ModelForm):
    class Meta:
        model = Client
        fields = (
            'proposal',
            'name',
            'email',
            'phone',
            'birth_date',
            'nationality',
            'occupation',
            'identification_document_type',
            'rg_rne',
            'issuing_body',
            'cpf',
            'father_name',
            'mother_name',
            'marital_status',
            'spouse',
            'public_person',
            'buyer_type',
        )

Buyer模型代码

class Buyer(BaseBuyer, BuyerModelMixin):
    name = models.CharField(_("nome"), max_length=300)
    email = models.EmailField(_("email"))
    phone = PhoneNumberField(
        _("celphone"),
        blank=True,
        null=True,
    )
    birth_date = models.DateField(_("birth_date_"))

希望在form.html中集成jQuery的intl-tel-input库,为phone字段添加国家选择功能,但多次尝试(包括CDN导入、添加字段类)均未生效,推测是HTML标签或JS选择器使用错误。以下是之前尝试的代码片段:

尝试的form.html部分代码

{% block contents %}
    <div class="row">
        <div class="col-12">
            <div class="card">
                <div class="card-body">
                    <form id="form-container" method="post" enctype="multipart/form-data">
                        {% csrf_token %}

                        <div id="form-document" style="display: block">
                            <h4 class="card-title">Buyer's Docs {{ buyer.name }}</h4>
                            <b>Pending docs</b>
                            {% for pending in pending_documents %}
                                <li>{{ pending }}</li>
                            {% endfor %}
                        <!-- 渲染phone字段 -->
                        {{ form.phone|as_crispy_field|add_class:"phone-field" }}

尝试的JS代码

<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="buyer.static.css.input.js"></script>
<script>
  $(document).ready(function() {
    $('#phone-input').intlTelInput({
    });
  });
</script>

错误点分析

  1. 库资源路径错误:引入的buyer.static.css.input.js不是intl-tel-input的官方资源,缺少正确的JS、CSS文件以及必备的utils.js
  2. 选择器不匹配:JS中使用#phone-input选择器,但实际Crispy Forms渲染的phone字段默认ID为id_phone,除非手动指定
  3. 缺少必要依赖:intl-tel-input需要配套的utils.js才能处理国家数据、号码格式化,且必须先引入jQuery

正确集成步骤

步骤1:修改表单类,指定字段ID或类名

在ClientForm的__init__方法中,为phone字段设置自定义ID,方便JS精准选择:

class ClientForm(forms.ModelForm):
    class Meta:
        model = Client
        fields = ('proposal', 'name', 'email', 'phone', ...)  # 保留原字段列表

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # 为phone字段设置自定义ID
        self.fields['phone'].widget.attrs['id'] = 'phone-input'
        # 可选:添加类名用于样式控制
        self.fields['phone'].widget.attrs['class'] = 'form-control phone-field'

步骤2:在模板中正确引入库资源

在模板的{% block scripts %}(或页面底部)引入jQuery、intl-tel-input的CSS、JS及utils.js:

{% block contents %}
<div class="row">
    <div class="col-12">
        <div class="card">
            <div class="card-body">
                <form id="form-container" method="post" enctype="multipart/form-data">
                    {% csrf_token %}
                    
                    <div id="form-document" style="display: block">
                        <h4 class="card-title">Buyer's Docs {{ buyer.name }}</h4>
                        <b>Pending docs</b>
                        {% for pending in pending_documents %}
                            <li>{{ pending }}</li>
                        {% endfor %}
                    </div>
                    
                    <!-- 渲染phone字段,无需add_class过滤器,已在表单中设置 -->
                    {{ form.phone|as_crispy_field }}
                    
                    <!-- 其他表单字段 -->
                    <button type="submit" class="btn btn-primary">Submit</button>
                </form>
            </div>
        </div>
    </div>
</div>
{% endblock %}

{% block scripts %}
<!-- 引入jQuery -->
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<!-- 引入intl-tel-input样式 -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/intl-tel-input@18.1.1/build/css/intlTelInput.min.css">
<!-- 引入intl-tel-input核心JS -->
<script src="https://cdn.jsdelivr.net/npm/intl-tel-input@18.1.1/build/js/intlTelInput.min.js"></script>
<!-- 引入配套工具库,处理国家数据与号码格式化 -->
<script src="https://cdn.jsdelivr.net/npm/intl-tel-input@18.1.1/build/js/utils.js"></script>

<script>
$(document).ready(function() {
    // 初始化intl-tel-input
    const phoneInput = document.querySelector("#phone-input");
    const iti = window.intlTelInput(phoneInput, {
        initialCountry: "auto", // 自动检测用户所在国家
        // 可选:通过IP获取国家代码(需启用跨域请求)
        geoIpLookup: function(callback) {
            $.get("https://ipinfo.io", function() {}, "jsonp").always(function(resp) {
                const countryCode = (resp && resp.country) ? resp.country : "br";
                callback(countryCode);
            });
        },
        utilsScript: "https://cdn.jsdelivr.net/npm/intl-tel-input@18.1.1/build/js/utils.js",
        preferredCountries: ["br", "us", "ca"] // 设置优先显示的国家
    });

    // 表单提交时,将格式化后的号码赋值回输入框
    $("#form-container").submit(function() {
        phoneInput.value = iti.getNumber();
    });
});
</script>
{% endblock %}

步骤3:验证渲染结果

确保页面渲染后,phone字段的ID为phone-input,且所有库资源加载正常(可通过浏览器开发者工具的Network标签检查)。

关键注意事项

  • 必须先引入jQuery,再加载intl-tel-input的JS文件
  • utils.js是核心依赖,缺少会导致国家选择器无法正常工作
  • 若未手动设置字段ID,Crispy Forms默认ID为id_phone,需对应修改JS选择器
  • 确保CSS文件正确引入,否则国家选择器样式会错乱

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 01:39:58