Search code examples
pythondjangogeneric-foreign-key

GenericForeignKey objects in list view


I am using a third-party app (https://github.com/bitmazk/django-review) to generate reviews for my model via a generic foreign key.

class Store(models.Model):
    bio = models.CharField(max_length=255, null=True, blank=True)
    full_name = models.CharField(max_length=100, blank=True, null=True)
    username = models.CharField(max_length=100, unique=True)

    website = models.URLField(null=True, blank=True)
    phone = models.CharField(null=True, blank=True, max_length=12)
    whatsapp = models.CharField(null=True, blank=True, max_length=12)

The view:

def store_list(request):
    stores = Store.objects.all()
    context['stores'] = stores
    return render(request, 'store_list.html', context)

How do I return the reviews for each store?

Edit: I should point out that I want do that without using template tags from django-review.


Solution

  • django-review uses Django's contenttypes and generic foreign keys to create database records for reviews outside of your own applications. In order to designate an object for review, the module passes the model name and integer of object pk to be reviewed through a url.

    So, in your template, creating a "Review This Item" button requires the model name and id of the object itself. This is how the generic foreign key can be implemented.

    {% for store in stores %}
        <a href="{% url "review_create" content_type='store' object_id=store.pk %}">
            Review our {{ store.name }} store
        </a>
    {% endfor %}
    

    In order to retrieve reviews, use the included template tags and django-review performs the lookups. Take a look below, it's all you need:

    {% load review_tags %}
    
    {% for store in stores %}
        {% get_reviews store as reviews %}
        {% for review in reviews|slice:"0:3" %} {# get the first three reviews #}
            <p>
                {{ review.get_average_rating }} 
            </p>
            <p>
                {% if review.content %}
                    {{ review.content|truncatewords:'70' }}
                {% else %}
                    Reviewed without description.
                {% endif %}
            </div>
            <a href="{% url "review_detail" pk=object.pk %}">Review details</a>
        {% endfor %}
    {% endfor %}