7

I have a table in my models file and I want to design it such that there is a limit to ten rows in the table. When the limit is exceeded the oldest row will be deleted. For some context this is for a display on the front end that shows a user the ten most recent links they have accessed. I am new to Django so if anyone had a suggestion on how to do this, it would be greatly appreciated!

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Parag Srivastava
  • 235
  • 1
  • 3
  • 8

3 Answers3

6

You could write a custom save method that checks the length of YourObject.objects.all(), and then deletes the oldest one when that length is equal to 10.

Something along the line of:

def save(self, *args, **kwargs):
    if YourModel.objects.count() == 10:
        objects[0].delete()

    super(YourModel, self).save(*args, **kwargs)
danidee
  • 9,298
  • 2
  • 35
  • 55
Daniel Rosenthal
  • 1,386
  • 4
  • 15
  • 32
4

In my opinion, you can use Signals. A post_save in this case. This way, you keep the object creation and deletion logic separate.

Since you want the oldest to be deleted, I am assuming you have a created field in the model.

Once you save,

def my_handler(sender, instance, **kwargs):
    qs = MyModel.objects.order_by('created') #ensure ordering.
    if qs.count() > 10:
        qs[0].delete() #remove the oldest element

class MyModel(models.Model):
    title = models.CharField('title', max_length=200)
    created = models.DateTimeField(auto_add_now=True, editable=False)

post_save.connect(my_handler, sender=MyModel)

Of course, nothing stops you from using the pre_save signal, but use it only if you are absolutely sure the save method wont fail.

karthikr
  • 97,368
  • 26
  • 197
  • 188
0

Improving a bit on @karthikr answer.

I also believe a post-save signal handler is the best way, but isolating the function in a class method and checking for the created flag. If for example you want to keep a log of the last 1000 emails your system has sent:

from django.db import models
from django.db.models.signals import post_save

LOG_SIZE=1000

class EmailLog(models.Model):
    """Keeps a log of the 1000 most recent sent emails."""

    sent_at = models.DateTimeField(auto_add_now=True)
    message = models.TextField()
    to_addr = models.EmailField()

    @classmethod
    def post_create(
        cls,
        sender,
        instance: "EmailLog",
        created: bool,
        *args,
        **kwargs
    ):
        if created: # Indicates if it's a new object
            qset = EmailLog.objects.order_by("sent_at") # Force ordering
            if qset.count() > LOG_SIZE:
                qset[0].delete()


post_save.connect(EmailLog.post_create, sender=EmailLog)
Caiof
  • 89
  • 1
  • 4