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

如何在Django Forms中为密码字段设置圆点占位符

问题

使用Django Forms渲染注册页面时,尝试通过widgets为密码字段设置•字符实体作为占位符,但页面渲染后,占位符被转为•,无法正常显示圆点符号。以下是相关代码:

forms.py

class Signup(forms.ModelForm):
    class Meta:
        model = User
        fields = ["username", "email", "password", "password2", "library_no", "first_name", "last_name",]
        help_texts = {
            "username":None,
        }
        labels = {
        }
        widgets = {
            "username": forms.TextInput(attrs={
                "id":"input_46",
                "name":"q46_typeA46",
                "data-type":"input-textbox",
                "class":"form-textbox validate[required]",
                "size":"310",
                "data-component":"textbox",
                "aria-labelledby":"label_46",
                "placeholder":"180591001"
            }),
            "first_name":forms.TextInput(attrs={
                "id":"first_4",
                "name":"q4_name[first]",
                "class":"form-textbox validate[required]",
                "autoComplete":"section-input_4 given-name",
                "data-component":"first", 
                "aria-labelledby":"label_4 sublabel_4_first", 
                "required":True,
                "placeholder":"Chinedu"
            }),
            "last_name":forms.TextInput(attrs={
                "id":"last_4",
                "name":"q4_name[last]", 
                "class":"form-textbox validate[required]", 
                "autoComplete":"section-input_4 family-name",  
                "data-component":"last", 
                "aria-labelledby":"label_4 sublabel_4_last", 
                "required":True,
                "placeholder":"Oladapo Dikko"
            }),
            "email":forms.EmailInput(attrs={
                "id":"input_10", 
                "name":"q10_email10",
                "class":"form-textbox validate[required, Email]", 
                "placeholder":"ex: myname@example.com",
                "data-component":"email", 
                "aria-labelledby":"label_10 sublabel_input_10",
                "required":True
            }),
            "password": forms.PasswordInput(attrs={
                "id":"first_50", 
                "name":"q50_name50[first]",
                "class":"form-textbox",  
                "autoComplete":"section-input_50 given-name",  
                "data-component":"first", 
                "aria-labelledby":"label_50 sublabel_50_first", 
                "required":True,
                "placeholder":"••"
            }),
            "password2": forms.PasswordInput(attrs={
                "id":"last_50", 
                "name":"q50_name50[last]",
                "class":"form-textbox", 
                "autoComplete":"section-input_50 family-name",
                "data-component":"last", 
                "aria-labelledby":"label_50 sublabel_50_last",
                "required": False
            }),
            "library_no": forms.TextInput(attrs={"required": False}),
        }

signup.html

<!DOCTYPE html>
<html class="supernova">
<head>
    <title>SignUp</title>
    <style type="text/css">@media print{.form-section{display:inline!important}.form-pagebreak{display:none!important}.form-section-closed{height:auto!important}.page-section{position:initial!important}}</style>
    <link rel="stylesheet" href="/static/signup/css/style.css">
    <link rel="stylesheet" href="/static/signup/css/main.css">
</head>
<body>
<form class="jotform-form" action="/signup/" method="post" name="form_230023299150548" id="230023299150548" accept-charset="utf-8" autocomplete="on">
    {%csrf_token%}
  <div role="main" class="form-all">
    <style>
      .form-all:before
      {
        background: none;
      }
    </style>
    <ul class="form-section page-section">

      <li id="cid_28" class="form-input-wide" data-type="control_head">
        <div class="form-header-group  header-large">
          <div class="header-text httal htvam">
            <h1 id="header_28" class="form-header" data-component="header">SignUp</h1>
          </div>
        </div>
      </li>

      <li class="form-line jf-required" data-type="control_textbox" id="id_46">
        <label class="form-label form-label-top form-label-auto" id="label_46" for="input_46"> Username
            <span class="form-required">*</span> 
        </label>

        <div id="cid_46" class="form-input-wide jf-required" data-layout="half"> 
            {{form.username}}
        </div>
      </li>

      <li class="form-line jf-required" data-type="control_fullname" id="id_4">
        <div id="cid_4" class="form-input-wide jf-required" data-layout="full">
            <div data-wrapper-react="true">
                <span class="form-sub-label-container" style="vertical-align:top" data-input-type="first">
                                    <label class="form-label form-label-top" id="label_4" for="first_4"> First Name
                                        <span class="form-required">*</span> 
                                    </label>
                  {{form.first_name}}
                </span>

                <span class="form-sub-label-container" style="vertical-align:top" data-input-type="last">
                                    <label class="form-label form-label-top" id="label_4" for="first_4"> Last Name
                                        <span class="form-required">*</span> 
                                    </label>
                                    {{form.last_name}}
                </span>
            </div>
        </div>
      </li>

      <li class="form-line jf-required" data-type="control_email" id="id_10">
        <label class="form-label form-label-top form-label-auto" id="label_10" for="input_10"> E-mail
            <span class="form-required">*</span> 
        </label>
        <div id="cid_10" class="form-input-wide jf-required" data-layout="half"> 
            <span class="form-sub-label-container" style="vertical-align:top">
                                {{form.email}}
            </span> 
        </div>
      </li>
      
      <li class="form-line" data-type="control_fullname" id="id_50">
        <div id="cid_50" class="form-input-wide" data-layout="full">
            <div data-wrapper-react="true">
                <span class="form-sub-label-container" style="vertical-align:top" data-input-type="first">
                                        <label class="form-label form-label-top form-label-auto" id="label_50" for="first_50"> Password 
                                            <span class="form-required">*</span> 
                                        </label>
                    {{form.password}}
                </span>

                <span class="form-sub-label-container" style="vertical-align:top" data-input-type="last">
                                        <label class="form-label form-label-top form-label-auto" id="label_50" for="first_50">Confirm Password 
                                            <span class="form-required">*</span> 
                                        </label>
                    {{form.password2}}
                </span>
            </div>
        </div>
      </li>
解决方案

问题根源是Django会自动转义HTML字符实体,把&转为&amp;,导致&bull;无法被浏览器解析为圆点。可以通过以下两种方法解决:

方法1:直接使用Unicode圆点字符

不需要使用HTML实体,直接在placeholder中写入Unicode的圆点字符•,Django不会转义普通Unicode字符,浏览器会直接显示为圆点。

修改forms.py中password字段的placeholder:

"password": forms.PasswordInput(attrs={
    # 其他属性保持不变
    "placeholder": "••"  # 直接使用Unicode圆点字符
}),

方法2:在模板中关闭字段的自动转义

如果一定要使用HTML实体,可以在模板渲染该字段时,使用|safe过滤器告诉Django不需要转义这个字段的内容。

修改signup.html中的密码字段渲染代码:

{{form.password|safe}}

同时确认password2字段如果需要同样效果也做对应修改:

{{form.password2|safe}}

注意:使用|safe时要确保字段内容是可信的,避免XSS风险,这里因为是自己设置的占位符,所以安全风险极低。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 22:31:57