Wilco van Esch
Wilco van Esch

Reputation: 457

Chaining and splitting a QuerySet of objects from multiple models

I want to go from showing the latest 10 objects from one model to showing the latest 10 objects from that and another model, treating the objects differently depending on the model they come from.

I have gone from (abbreviated):

views.py

latest_ModelA = ModelA.objects.order_by('-pk')[:10]
context = {'latest_10': latest_10}

to:

views.py

latest_ModelA = ModelA.objects.order_by('-pk')[:10]
latest_ModelB = ModelB.objects.order_by('-pk')[:10]
latest_combined = list(chain(latest_ModelA, latest_ModelB))
latest_combined.sort(key=lambda x: x.id, reverse=True)
context = {'latest_combined': latest_combined[:10]}

But how do I then go from:

index.html

{% for a in latest_ModelA %}
    <a href="/display/thingA/{{ a.id }}/">{{ a.name }}</a>
{% endfor %}

to something like:

{% for a in latest_combined %}
    {% if a.get_classname == "thingA" %}
        <a href="/display/thingA/{{ a.id }}/">{{ a.name }}</a>
    {% if a.get_classname == "thingB" %}
        <a href="/display/thingB/{{ a.id }}/">{{ a.name }}</a>
    {% endif %}
{% endfor %}

This feels wrong. Before I go deeper down this hole, can anyone propose a more elegant solution?

For reference:

models.py

class ModelA(models.Model):
    (...)

class ModelB(models.Model):
    a = models.ManyToManyField(ModelA)

Upvotes: 0

Views: 49

Answers (2)

Peter DeGlopper
Peter DeGlopper

Reputation: 37319

Is the only difference in your desired rendering the URL? If so, I'd write a get_absolute_url method for both model classes - this is exactly the kind of situation the example there discusses.

In general, you want behavior that varies by class to be defined by the class, not by inspecting the class type in the template.

Upvotes: 3

dm03514
dm03514

Reputation: 55962

You could put the method to generate the url on the model that way each instance/class will know how to build its own url without needing a conditional

class ModelA(models.Model):
   def get_special_link(self):
      return "/display/thingA/{}/".format(self.id)

class ModelB(models.Model):
   def get_special_link(self):
      return "/display/thingB/{}/".format(self.id)

or better yet use reverse

Upvotes: 1

Related Questions