在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>
错误点分析
- 库资源路径错误:引入的
buyer.static.css.input.js不是intl-tel-input的官方资源,缺少正确的JS、CSS文件以及必备的utils.js - 选择器不匹配:JS中使用
#phone-input选择器,但实际Crispy Forms渲染的phone字段默认ID为id_phone,除非手动指定 - 缺少必要依赖: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
相关产品推荐
相关产品推荐

