TypeError: '<' не поддерживается между экземплярами 'CombinedExpression' и 'int' при попытке реализовать сигнал post_save с помощью django-axes
Я пытаюсь создать сигнал, который отправляет письмо с информацией о попытке доступа, когда пользователь не может предоставить правильные учетные данные при входе в систему. Попытки доступа отслеживаются пакетом django-axes. Если достигнуто значение failure_limit
, используется другой сигнал. Сравнение обоих значений определяет, используется ли этот сигнал в данный момент.
Ошибка типа возникает в failures = instance.failures_since_start
.
from axes.models import AccessAttempt
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.core.mail import mail_admins
from django.template import loader
from tajnanorka.settings import AXES_FAILURE_LIMIT
@receiver(post_save, sender=AccessAttempt)
def login_attempt_email(sender, instance, **kwargs):
def _render_email_message(context):
template = loader.get_template("foo.html")
return template.render(context)
failures = instance.failures_since_start
failure_limit = int(AXES_FAILURE_LIMIT)
context = dict(
failures_since_start = failures,
)
subject = 'bar'
message = _render_email_message(context)
if failures < failure_limit:
mail_admins(
subject,
message,
fail_silently=False,
html_message = message
)
Модель AccessAttempt:
class AccessBase(models.Model):
user_agent = models.CharField(_("User Agent"), max_length=255, db_index=True)
ip_address = models.GenericIPAddressField(_("IP Address"), null=True, db_index=True)
username = models.CharField(_("Username"), max_length=255, null=True, db_index=True)
http_accept = models.CharField(_("HTTP Accept"), max_length=1025)
path_info = models.CharField(_("Path"), max_length=255)
attempt_time = models.DateTimeField(_("Attempt Time"), auto_now_add=True)
class Meta:
app_label = "axes"
abstract = True
ordering = ["-attempt_time"]
class AccessAttempt(AccessBase):
get_data = models.TextField(_("GET Data"))
post_data = models.TextField(_("POST Data"))
failures_since_start = models.PositiveIntegerField(_("Failed Logins"))
def __str__(self):
return f"Attempted Access: {self.attempt_time}"
class Meta:
verbose_name = _("access attempt")
verbose_name_plural = _("access attempts")
unique_together = [["username", "ip_address", "user_agent"]]
Вот весь трассировочный бэкграунд:
Я пытался преобразовать failures
в int()
, но не знаю, что делать дальше. Есть ли способ сравнить эти два значения?
Эта ошибка возникает потому, что instance.failures_since_start
возвращает не целое число, а CombinedExpression
.
Чтобы исправить это, нужно убедиться, что failures_since_start
оценивается как целое число перед сравнением с failure_limit
.
Попробуйте следующее:
failures = int(instance.failures_since_start)
failure_limit = int(AXES_FAILURE_LIMIT)
Вы не можете использовать instance
, или, по крайней мере, не напрямую, поскольку он использует F
выражение [Django-doc] для обновления счетчика.
Используйте .refresh_from_db(…)
[Django-doc] для перечитывания счетчика из базы данных:
@receiver(post_save, sender=AccessAttempt)
def login_attempt_email(sender, instance, **kwargs):
def _render_email_message(context):
template = loader.get_template('foo.html')
return template.render(context)
instance.refresh_from_db()
failures = instance.failures_since_start
failure_limit = int(AXES_FAILURE_LIMIT)
context = dict(
failures_since_start=failures,
)
subject = 'bar'
message = _render_email_message(context)
if failures < failure_limit:
mail_admins(subject, message, fail_silently=False, html_message=message)