简体   繁体   中英

Django Admin filter by function / filter only by first object in reverse foreign key lookup

I am trying to build a filter by function in django. From what I've learned by googling this is quite hard to achieve.

So here is my code:

class TrackingEventType(models.Model):
    name = models.CharField(blank=False, null=False, max_length=255)

class TrackingEvent(models.Model):    
    datetime = models.DateTimeField(blank=False, null=False, default=datetime.now, verbose_name="Zeitpunkt")    
    event_type = models.ForeignKey(TrackingEventType, help_text="Art des Events")    
    tracking = models.ForeignKey('Tracking')    

    class Meta:
        ordering = ['-datetime']


class Tracking(models.Model):
    tracking_no = models.CharField(blank=False, null=False, max_length=10, unique=True, verbose_name="Tracking Nummer")

    def get_last_event(self):
        """
        Todo: return the latest event.
        """
        return TrackingEvent.objects.filter(tracking=self.id).first()
    get_last_event.short_description = 'Last event'

    class Meta:
        ordering = ['-tracking_no']

My goal is to make it possible to filter Tracking objects by their last events type name. Displaying the result of the funtion in django admin is easy, but adding a corresponding filter isn't.

My idea was also to try to build a filter something like:

trackingevent__set__first__event_type__name

But yeah, that would be too easy :)

Any inputs are welcome.

As you've discovered it isn't trivial to filter in that manner. If you are accessing that information regularly it is probably also not very efficient either.

I would suggest that you store a reference to the latest tracking event in the Tracking model itself:

class Tracking(models.Model)
    # ...
    last_event = models.ForeignKey(TrackingEvent, null=True)

You would then use signals to update this reference whenever a new tracking event is created. Something along the lines of:

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

@receiver(post_save, sender=TrackingEvent)
def update_latest_tracking_event(sender, instance, created, **kwargs):
    # Is this a new event?
    if created:
        # If yes, then update the Tracking reference
        tracking = instance.tracking
        tracking.last_event = instance
        tracking.save()

(Please read the documentation on where to put this code).

Once all this is in place it becomes easy to filter based on the last tracking event type:

# I'm just guess what event types you have...
cancellation = TrackingEventType.objects.get(name='cancel')
Tracking.objects.filter(last_event__event_type=cancellation)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM