Llevaba tiempo que queria poner comentarios en el blog, a pesar de tenerlo implementado desde una de las primeras versiones de la página, nunca lo puse en activo. Sobretodo porque para responder las dudas que pudiesen surgir en alguno de los post, si alguien estuviese realmente interesado siempre podría (y puede) enviar un email a correo que se encuentra en la seccion "Whoami".
En este post pretendo explicar como se implementa un captcha para un formulario, reCAPTCHA v2 invisble en esté caso, pero tanto reCaptcha v2 checkbox como reCAPTCHA v3 son muy parecidos en cuanto a implementación.
En este caso el formulario es el de está propia página, y que se encuentra habilitado en este mismo post (en otros posts puede estar o no habilitado. Pero como digo, siempre se me puede preguntar via email.
Lo primero de todo, supongamos que se sabe como funciona el framework Django y el proposito de los archivos que lo componen: forms.py, models.py, views.py, settings.py, etc. Ya que en este post se va a obviar la explicación de estos archivos y se va a ir al grano de como implementar el captcha.
En los tiempos que corren, la utilización de estos captchas para verificar que los usuarios son realmente usuarios es algo necesario, esto es debido a la cantidad de bots que hay por la red, y que se dedican en su mayoria a insertar comentarios en su mayoria spam, y a veces en posts abandonados con el objetivo de hacer black SEO.
Además de tener un reCAPTCHA que nos filtre este tipo de bots, los comentarios no deberian ser plasmados directamente en el post, sino que deberian ser revisador por el administrador del mismo, en este caso también se implementara esto, además de la recepción de un email avisando de que se ha escrito un comentario nuevo (aunque todo esto ya no tiene nada que ver con el captcha en sí).
Lo primero que hara falta es la instalación en este caso de django-recapcha, el código fuente de django-recapcha puede ser encontrado en en este repositorio y añadir el sitio y el tipo de reCAPTCHA en Google reCAPTCHA
pip install django-recapcha
Una vez creado el sitio nos dará dos claves, una llamada CLAVE DE SITIO WEB, que será nuestra clave pública y que será con la cual se haga la petición, y la CLAVE SECRETA, que hara la comunicación entre nuestro sitio web y el servicio reCAPTCHA.
Lo siguiente será añadir el django-recapcha a nuestro settings.py:
...
INSTALLED_APPS = [
'django.contrib.admin',
...
'captcha',
]
...
# ReCaptcha v2
RECAPTCHA_PUBLIC_KEY = 'CLAVE DE SITIO WEB'
RECAPTCHA_PRIVATE_KEY = 'CLAVE SECRETA'
En forms.py:
...
from captcha.fields import ReCaptchaField
from captcha.widgets import ReCaptchaV2Invisible
class CommentForm(forms.ModelForm):
captcha = ReCaptchaField(widget=ReCaptchaV2Invisible)
class Meta:
model = Comment
fields = ('name', 'email', 'text')\
...
Y finalmente añadir a nuestro template:
...
<head>
...
<script src="https://www.google.com/recaptcha/api.js" async defer></script>
</head>
...
<form action="/yout-action" id="comment" class="form-signin" role="form" method="POST">
<div>
<textarea name="text" form="comment" class="form-control" placeholder="Leave a comment..." rows="3"></textarea>
</div>
{{ form.non_field_errors }}
{% csrf_token %}
<div class="row">
<div class="col">
<input type="text" name="name" id="id_name" class="form-control" placeholder="Name" required>
</div>
<div class="col">
<input type="email" name="email" id="id_email" class="form-control" placeholder="email" required>
</div>
</div>
<div class="row">
<div class="col">
<div class="g-recaptcha" data-sitekey="CLAVE DE SITIO WEB" data-size="invisible"></div>
</div>
</div>
<button class="btn btn-lg btn-primary btn-block" type="submit">Send</button>
</form>
...
<script>
function someFunction() {
grecaptcha.execute();
}
</script>
La funcion grecaptcha.execute(); es necesaria, ya que al usar reCAPTCHA v2 invisble, necesitamos que se haga la petición desde JavaScript.
Como he comentado, una vez que se ha pasado el captcha se enviaria el comentario a la revisión del administrtador del sitio por correo y se revisaria en el backend.
views.py (envia un email una vez se completa el formulario):
...
if request.method == "POST":
form = CommentForm(data=request.POST)
if form.is_valid():
comment = form.save(commit=False)
comment.post = post
comment.ip_address = request.META['REMOTE_ADDR']
comment.save()
email = mail.EmailMessage('subject!',
'body'),
'your@sender.is',
['your@received.is'],
connection = mail.get_connection())
email.send()
return render(request,'post.html')
...
models.py (habilita/deshabilita comentarios para el post)
class Post(models.Model):
...
comments = models.BooleanField(default=False)
...
class Comment(models.Model):
post = models.ForeignKey(Post, related_name="post_name", on_delete=models.CASCADE)
name = models.CharField(max_length=100)
email = models.CharField(max_length=200, default='default@email')
date = models.DateTimeField(default=datetime.datetime.now())
text = models.TextField(max_length=3000)
ip_address = models.CharField(max_length=200)
active = models.BooleanField(default=False)
class Meta:
ordering = ('date',)
def __str__(self):
return '{}'.format(self.name)
He cortado muchos trozos de código por legibilidad, espero no haber cortado demasiado. :)
Lucatoni
Dec. 28, 2022 @ 22.10
Muy bien explicado, con ganas de probarlo en mi sitio web. Saludos