losee
losee

Reputation: 2238

How do I loop through results and store them in a list so I can use them in my Django template

I tried to loop thorough an object and store and store the results in a list so i could use it in my django template and display it. I tried to copy something I have elsewhere in my code to suit my needs but it doesnt work. I tried to duplicate this

{% for tag in instance.tags.all %}
      {{ tag.post_set.all }}
{% endfor %}

this returns everything in one block. I want to be able to loop through it so I tried this

links = []
for t in tag:
   links.append(
       t.post_set.all()
   )

mylink = links
context = {
    "title": "detail ",
    "instance": instance,
    "hops": mylink
}

but it didn't work. What's the proper syntax to tore my results from a loop and store them in a list I can then use in my template. All help or advice is welcome

EDIT:

my view

 def post_detail(request, slug=None):
    instance = get_object_or_404(Post, slug=slug)

    tag = instance.tags.all
    links = []
    for t in tag:
       links.append(
           t.post_set.distinct()
       )

   share_string = quote_plus(instance.content)
   tag = instance.tags.all()
   context = {
       "title": "detail ",
       "instance": instance,
       "share_string": share_string,
       "tag": tag
   }
   return render(request, "posts/post_detail.html", context)



 class Tag(models.Model):
    title = models.CharField(max_length=250)
    slug = models.SlugField(max_length=200, unique=True)
    timestamp = models.DateTimeField(auto_now=False, auto_now_add=True)
    updated = models.DateTimeField(auto_now=True, auto_now_add=False)

    def __str__(self):
        return self.title

   def get_absolute_url(self):
        return reverse("posts:tag_index", kwargs={"slug": self.slug})

   class Meta:
        ordering = ["-timestamp"]


class Post(models.Model):
    user = models.ForeignKey(settings.AUTH_USER_MODEL, default=1)
    slug = models.SlugField(unique=True)
    title = models.CharField(max_length=120)
    image = models.ImageField(upload_to=upload_location, null=True, blank=True,
                              width_field="width_field",
                              height_field="height_field")
    height_field = models.IntegerField(default=0)
    width_field = models.IntegerField(default=0)
    content = models.TextField()
    draft = models.BooleanField(default=False)
    publish = models.DateField(auto_now=False, auto_now_add=False)
    timestamp = models.DateTimeField(auto_now=False, auto_now_add=True)
    updated = models.DateTimeField(auto_now=True, auto_now_add=False)
    tags = models.ManyToManyField(Tag)

    objects = PostManager()

    def __str__(self):
        return self.title

    def get_absolute_url(self):
        return reverse("posts:detail", kwargs={"slug": self.slug})

    class Meta:
        ordering = ["-timestamp"]


def create_slug(instance, new_slug=None):
    slug = slugify(instance.title)
    if new_slug is not None:
        slug = new_slug
    qs = Post.objects.filter(slug=slug).order_by("-id")
    exists = qs.exists()
    if exists:
        new_slug = "%s-%s" % (slug, qs.first().id)
       return create_slug(instance, new_slug=new_slug)
    return slug


def pre_save_post_receiver(sender, instance, *args, **kwargs):
    if not instance.slug:
        instance.slug = create_slug(instance)


pre_save.connect(pre_save_post_receiver, sender=Post)

this is what I have

Upvotes: 4

Views: 132

Answers (3)

David Rowe
David Rowe

Reputation: 61

I'll throw in another answer. alecxe's answer has the correct template syntax.

You should be trying to minimize the business logic happening in templates since render performance is already bad enough. Move the distinct logic into your Python code. Using distinct() might work out for you

links = []
for t in tag:
   links.append(
       t.post_set.distinct()
   )

Keeps the template logic basic

Just access and store the tags directly from the model and return them in the context. instance.tags should return a query-set if I'm not mistaken, meaning you can simply call distinct() on tags.

def post_detail(request, slug=None):
    instance = get_object_or_404(Post, slug=slug)

    tags = instance.tags.distinct()

    share_string = quote_plus(instance.content)

    context = {
        "title": "detail ",
        "instance": instance,
        "share_string": share_string,
        "tags": tags
    }
    return render(request, "posts/post_detail.html", context)

Your template should be something like:

{% for tag in tags %}
      {{ tag }}
{% endfor %}

Upvotes: 1

Daniel Roseman
Daniel Roseman

Reputation: 599610

It would be better to do a single query for the posts you want.

links = Post.objects.filter(link__tag__instancemodel=instance)

where instancemodel is the name of whatever model instance is.

Upvotes: 0

alecxe
alecxe

Reputation: 473863

Why don't have an inner loop in the template:

{% for tag in instance.tags.all %}
      {% for post in tag.post_set.all %}
          {{ post }}
      {% endfor %}
{% endfor %}

Upvotes: 2

Related Questions