Repository: jazzband/django-axes

Issue:
DB indexes missing on AccessAttempt
The model `AccessAttempt` does not contain any DB indexes. If this table contains a lot of entries then the login performance is very slow. I saw it already happen with 50K+ entries.

The following fields should have an index to prevent performance issues:
- user_agent
- ip_address
- username
- trusted

See `decorators.py:_get_user_attempts`: https://github.com/django-pci/django-axes/blob/master/axes/decorators.py#L229-L235



Discussion:
Will you make a PR solving it?

Yes, I can. 

I plan to just add four individual `db_index=True` to the data model. It would also be possible to use a composite index over all four of them but I think it's to restrictive in case someone like's to filter by only one of those fields. What do you think?

I agree is too restrictive.

Don't forget to add the migration as well.


Resolving patch:
diff --git a/axes/migrations/0002_auto_20151217_2044.py b/axes/migrations/0002_auto_20151217_2044.py
new file mode 100644
--- /dev/null
+++ b/axes/migrations/0002_auto_20151217_2044.py
@@ -0,0 +1,54 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('axes', '0001_initial'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='accessattempt',
+            name='ip_address',
+            field=models.GenericIPAddressField(db_index=True, null=True, verbose_name=b'IP Address'),
+        ),
+        migrations.AlterField(
+            model_name='accessattempt',
+            name='trusted',
+            field=models.BooleanField(db_index=True, default=False),
+        ),
+        migrations.AlterField(
+            model_name='accessattempt',
+            name='user_agent',
+            field=models.CharField(db_index=True, max_length=255),
+        ),
+        migrations.AlterField(
+            model_name='accessattempt',
+            name='username',
+            field=models.CharField(db_index=True, max_length=255, null=True),
+        ),
+        migrations.AlterField(
+            model_name='accesslog',
+            name='ip_address',
+            field=models.GenericIPAddressField(db_index=True, null=True, verbose_name=b'IP Address'),
+        ),
+        migrations.AlterField(
+            model_name='accesslog',
+            name='trusted',
+            field=models.BooleanField(db_index=True, default=False),
+        ),
+        migrations.AlterField(
+            model_name='accesslog',
+            name='user_agent',
+            field=models.CharField(db_index=True, max_length=255),
+        ),
+        migrations.AlterField(
+            model_name='accesslog',
+            name='username',
+            field=models.CharField(db_index=True, max_length=255, null=True),
+        ),
+    ]
diff --git a/axes/models.py b/axes/models.py
--- a/axes/models.py
+++ b/axes/models.py
@@ -4,22 +4,26 @@
 class CommonAccess(models.Model):
     user_agent = models.CharField(
         max_length=255,
+        db_index=True,
     )
 
     ip_address = models.GenericIPAddressField(
         verbose_name='IP Address',
         null=True,
+        db_index=True,
     )
 
     username = models.CharField(
         max_length=255,
         null=True,
+        db_index=True,
     )
 
     # Once a user logs in from an ip, that combination is trusted and not
     # locked out in case of a distributed attack
     trusted = models.BooleanField(
         default=False,
+        db_index=True,
     )
 
     http_accept = models.CharField(


Test patch: