1

I am trying to show a list of associated "cliqueclasses" to a given "Item", but am just not able to get the template for the loop right. I'd also like to take this one step further and attach only the classes associated to the item (based on the foreign key)

I have been trying for a while and haven't had any luck so far particularly with the template!

Models.py

class Item(models.Model):
    title = models.CharField(max_length=100)
    price = models.FloatField()
    discount_price = models.FloatField(blank=True, null=True)
    category = models.CharField(choices=CATEGORY_CHOICES, max_length=2)
    label = models.CharField(choices=LABEL_CHOICES, max_length=1)
    slug = models.SlugField()
    description = models.TextField()
    image = models.ImageField()

    def save(self, *args, **kwargs):
    ...

    def __str__(self):
        return self.title
    ...

class CliqueClass(models.Model):
    title = models.CharField(max_length=100)
    start_date = models.DateTimeField(auto_now_add=True)
    end_date = models.DateTimeField(auto_now_add=True)
    item = models.ForeignKey(Item, related_name='items',
                             on_delete=models.CASCADE)
    description = models.TextField()
    plan = models.TextField()
    slug = models.SlugField()
    image = models.ImageField()

    def save(self, *args, **kwargs):
    ...

    def __str__(self):
    ...

My Views.py

class ItemDetailView(DetailView):
    model = Item
    template_name = "clique.html"
    # queryset = CliqueClass.objects.filter(title=Item.title)

    def get_context_data(self, **kwargs):
        """
        This has been overridden to add `cliqueclass` to the template context,
        now you can use {{ cliqueclass }} within the template
        """
        context = super().get_context_data(**kwargs)
        context['cliqueclass'] = CliqueClass.objects.all()
        return context

My URL's.py

path('clique/<slug>/', ItemDetailView.as_view(), name='clique'),

My clique.html template:

 {% for class in object.cliqueclass_set.all %}
  <!--Look through all cliques classes-->
  <div class="mb-3">
    <a href="">
      <span>{{ class }}</span>
      <span class="badge purple mr-1">{{ class.title }}</span>

      <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Natus suscipit modi sapiente illo soluta odit
        voluptates,
        quibusdam officia. Neque quibusdam quas a quis porro? Molestias illo neque eum in laborum.</p>

    </a>
  </div>

  <hr class="solid">
  {% endfor %}

Any help would be really appreciated :)

Danie
  • 45
  • 6
  • are you new to django? – ino Aug 18 '20 at 03:46
  • @djangotic yes relatively new! – Danie Aug 18 '20 at 03:50
  • didn't the `{% for class in object.cliqueclass_set.all %}` loop work for you? – JPG Aug 18 '20 at 04:05
  • @ArakkalAbu unfortunately not, the HTML page is loading and I am able to call attributes of the Item model on the template - but can't seem to enter the for loop of the clique class – Danie Aug 18 '20 at 04:12
  • What do you see when you execute the following statement, `print(context['object'].cliqueclass_set.all().count())` just top of the `return context`? – JPG Aug 18 '20 at 04:17
  • @ArakkalAbu An error came up: _print(context['object'].cliqueclass_set.all().count()) AttributeError: 'Item' object has no attribute 'cliqueclass_set' [18/Aug/2020 14:20:11] "GET /clique/danie-camp/ HTTP/1.1" 500 94884_ – Danie Aug 18 '20 at 04:22
  • Bingo...thats why it is not rendering in the template. The template will simply ignore the execution if it encounters any error during the process – JPG Aug 18 '20 at 04:23
  • Brilliant thank you @ArakkalAbu - thanks for walking me through the debug process lol! this did the job: print(context['cliqueclass'].all().count())_ You're a legend :) – Danie Aug 18 '20 at 04:31

1 Answers1

1

First, you need to change the related_name of the FK

class CliqueClass(models.Model):
    # rest of your code
    item = models.ForeignKey(Item, related_name='clique_classes',
                             on_delete=models.CASCADE)

related_name can be any arbitrary name, But, I think clique_classes is the more suitable name.

If you're not familiar with the related_name, read more

  1. What is related_name in Django -- (SO Post)

  2. Following backwards relationship -- (Django doc)

  3. ForeignKey.related_name -- (Django doc)

After changing the related_name, you need to migrate the database by executing the following commands,

  1. python manage.py makemigrations
  2. python manage.py migrate

Then, in your view, remove the get_context_data(...) method, as it is not relevant to this particular issue.

class ItemDetailView(DetailView):
    model = Item
    template_name = "clique.html"

Then, change the template code to

{% for clique_class in object.clique_classes.all %}
    {{ clique_class.title }}
{% endfor %}
JPG
  • 82,442
  • 19
  • 127
  • 206