Search code examples
djangodjango-viewsdjango-templatesdjango-filterdjango-template-filters

Showing property filter value in Django template


I have the follwoing models in my Django project:

class File(models.Model):
  client = models.ForeignKey(User, on_delete=models.PROTECT, related_name='client_files')
  title = models.CharField(max_length=250, blank=True, null=True)
  ...
class FileTracking(models.Model):
    file = models.ForeignKey(File, related_name='file_tracking', on_delete=models.CASCADE)
    description = models.CharField(max_length=250, null=True, blank=True)
    title = models.CharField(max_length=250, blank=True, null=True)
    date = models.DateField(auto_now=False, auto_now_add=False)
    active =  models.BooleanField(default=False)
    ...

my view:

class FileCurrentView(ListView):
    model = File
    template_name = 'files_current.html'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        if self.request.user.is_authenticated:
            user=self.request.user
            current_files = files.filter(...)
            ...
            context["user"] = user
            context["current_files"]= current_files
            ...
        return context

In my template, I want to show the description or title of the last active record.

I tried to create a property in the FileTracking model:

@property
def LastActiveTrack(self):
    result  = self.objects.filter(active=1).order_by("-date")[0].title
    result_txt = str(result)
    if result:            
        return result_txt
    return ''

in my template:

{% for file in current_files %}
    Title: {{file.title}}
    last Tracking: {{file.file_tracking.LastActiveTrack}}
{% endif %}

but I couldn't get the value of the LastActiveTrack in my template. Any ideas?


Solution

  • Doing this in your template is less than ideal as you will make a database call for each file, which may get expensive in overhead if you have a lot of files.

    Better to update your initial call to include each file's filtracking via prefetch_related, which should limit it to two DB calls

    current_files = files.filter(...).prefetch_related(
        Prefetch(
            'file_tracking', 
            queryset=FileTracking.objects.order_by("-date"),
            #to make it clear what we are referring to in our template
            #add a to_attr argument to Prefetch
            to_attr="filetrack_ordered"
        )
    )
    

    then in your template you can call:

    {% for file in current_files %}
        Title: {{file.title}}
        last Tracking: {{file.filetrack_ordered.0.title}}
    {% endif %}
    

    NB: in your question you seem to be looking for file_tracking.title which isn't actually mentioned in the model fields you provide. I've assumed it's in there somewhere.