pip install django-simple-captcha
# 添加 captcha APP
INSTALLED_APPS = [
# 添加 验证码 APP
'captcha',
]
# Captcha 配置
# Captcha 默认格式
CAPTCHA_OUTPUT_FORMAT = '%(image)s %(text_field)s %(hidden_field)s '
CAPTCHA_NOISE_FUNCTIONS = (
# 'captcha.helpers.noise_null', # 没有样式
# 'captcha.helpers.noise_arcs', # 线
'captcha.helpers.noise_dots', # 点
)
# 图片中的文字为随机英文字母,如 mdsh
CAPTCHA_CHALLENGE_FUNCT = 'captcha.helpers.random_char_challenge'
# 图片中的文字为数字表达式,如 2 + 2 =
# CAPTCHA_CHALLENGE_FUNCT = 'captcha.helpers.math_challenge'
# 超时(minutes)
CAPTCHA_TIMEOUT = 30
# 验证码输入框指定 TEMPLATE, 表单使用 CaptchaField 字段生效
CAPTCHA_TEXT_FIELD_TEMPLATE = "captcha_text_field.html"
captcha_text_field.html(加了一个 placeholder)
<input autocapitalize="off" autocomplete="off" autocorrect="off" spellcheck="false" id="{{id}}_1" name="{{name}}_1" type="text" placeholder="请输入验证码" />
urlpatterns = [
# 添加 captcha url
url(r'^captcha/', include('captcha.urls')), # django 1.11
]
Using a CaptchaField
is quite straight-forward:
To embed a CAPTCHA in your forms, simply add a CaptchaField
to the form definition:
from django import forms
from captcha.fields import CaptchaField
class CaptchaTestForm(forms.Form):
myfield = AnyOtherField()
captcha = CaptchaField()
…or, as a ModelForm
:
from django import forms
from captcha.fields import CaptchaField
class CaptchaTestModelForm(forms.ModelForm):
captcha = CaptchaField()
class Meta:
model = MyModel
In your view, validate the form as usual. If the user didn’t provide a valid response to the CAPTCHA challenge, the form will raise a ValidationError
:
def some_view(request):
if request.POST:
form = CaptchaTestForm(request.POST)
# Validate the form: the captcha field will automatically
# check the input
if form.is_valid():
human = True
else:
form = CaptchaTestForm()
return render_to_response('template.html',locals())
{{ form.captcha }}
CaptchaField
takes a few optional arguements:
output_format
will let you format the layout of the rendered field. Defaults to the value defined in : CAPTCHA_OUTPUT_FORMAT.id_prefix
Optional prefix that will be added to the ID attribute in the generated fields and labels, to be used when e.g. several Captcha fields are being displayed on a same page. (added in version 0.4.4)generator
Optional callable or module path to callable that will be used to generate the challenge and the response, e.g. generator='path.to.generator_function'
or generator=lambda: ('LOL', 'LOL')
, see also Generators and modifiers. Defaults to whatever is defined in settings.CAPTCHA_CHALLENGE_FUNCT
.An example CAPTCHA validation in AJAX:
from django.views.generic.edit import CreateView
from captcha.models import CaptchaStore
from captcha.helpers import captcha_image_url
from django.http import HttpResponse
import json
class AjaxExampleForm(CreateView):
template_name = ''
form_class = AjaxForm
def form_invalid(self, form):
if self.request.is_ajax():
to_json_response = dict()
to_json_response['status'] = 0
to_json_response['form_errors'] = form.errors
to_json_response['new_cptch_key'] = CaptchaStore.generate_key()
to_json_response['new_cptch_image'] = captcha_image_url(to_json_response['new_cptch_key'])
return HttpResponse(json.dumps(to_json_response), content_type='application/json')
def form_valid(self, form):
form.save()
if self.request.is_ajax():
to_json_response = dict()
to_json_response['status'] = 1
to_json_response['new_cptch_key'] = CaptchaStore.generate_key()
to_json_response['new_cptch_image'] = captcha_image_url(to_json_response['new_cptch_key'])
return HttpResponse(json.dumps(to_json_response), content_type='application/json')
And in javascript your must update the image and hidden input in form
# html:
<form action='.' method='POST'>
{{ form }}
<input type="submit" />
<button class='js-captcha-refresh'></button>
</form>
# javascript:
$('.js-captcha-refresh').click(function(){
$form = $(this).parents('form');
$.getJSON($(this).data('url'), {}, function(json) {
// This should update your captcha image src and captcha hidden input
});
return false;
});
# javascript:
$('.captcha').click(function () {
$.getJSON("/captcha/refresh/", function (result) {
$('.captcha').attr('src', result['image_url']);
$('#id_captcha_0').val(result['key'])
});
});
个人使用时未使用到 Django 的表单的验证,直接在前端用 ajax 获取验证码,加了 1 分钟缓存,即 1 分钟只能获取一次,除非使用掉。
from captcha.models import CaptchaStore
from captcha.helpers import captcha_image_url
from ipware.ip import get_ip
def view_test(request):
# hashkey 验证码生成的秘钥,image_url 验证码的图片地址
hashkey_name = "hashkey_%s" % get_ip(request)
hashkey = cache.get(hashkey_name)
if not hashkey:
hashkey= CaptchaStore.generate_key()
cache.set(hashkey_name, hashkey, 60 * 1)
image_url = captcha_image_url(hashkey)
return "" # 此处省略
def captcha_refresh(request):
""" Return json with new captcha for ajax refresh request """
ip = get_ip(request)
if not request.is_ajax():
raise Http404
if cache.get("hashkey_%s" % ip):
to_json_response = {
'code': 403,
'msg': "1 分钟内只能获取 1 次验证码"
}
return HttpResponse(json.dumps(to_json_response), content_type='application/json')
new_key = CaptchaStore.pick(ip=ip)
cache.set("hashkey_%s" % ip, new_key, 60 * 1) # 1 分钟获取 1 次
to_json_response = {
'code': 200,
'key': new_key,
'image_url': captcha_image_url(new_key),
'audio_url': captcha_audio_url(new_key) if settings.CAPTCHA_FLITE_PATH else None
}
return HttpResponse(json.dumps(to_json_response), content_type='application/json')
<div class="m-form-group am-u-sm-6 blog-clear-right">
<div class="am-input-group">
<input autocomplete="off" id="id_captcha_1" name="captcha_code" type="text"
placeholder="* 验证码" class="am-form-field" required="required">
<span class="am-input-group-btn">
<img src="{{ image_url }}" alt="captcha" class="captcha" id="captcha"
style="height: 38px;">
</span>
<input id="id_reg_captcha_0" name="captcha_hashkey" type="hidden" value="{{ hashkey }}">
</div>
<script>
$('#captcha').click(function () {
$.getJSON("/captcha/refresh/", function (result) {
if (result['code'] === 200) {
$('#captcha').attr('src', result['image_url']);
$('#id_reg_captcha_0').val(result['key'])
} else {
toastr.warning(result['msg']);
}
});
});
</script>
</div>
from captcha.models import CaptchaStore
from captcha.helpers import captcha_image_url
from ipware.ip import get_ip
def view_test_2(request):
ip = get_ip(request)
# 前端回传:captcha_code 验证码的值,captcha_hashkey 哈希之后的值
captcha_code = request.POST.get("captcha_code".strip(), None)
captcha_hashkey = request.POST.get("captcha_hashkey", None)
try:
# 如果没过期找到了就删除掉
CaptchaStore.objects.get(response=captcha_code.lower(), hashkey=captcha_hashkey,
expiration__gt=timezone.now()).delete()
if cache.has_key("hashkey_%s" % ip):
# 验证通过,如果还存在 key, 就删除掉
cache.delete("hashkey_%s" % ip)
except CaptchaStore.DoesNotExist:
return HttpResponse("验证码无效或已过期")
return "" # 此处省略