Search code examples
djangodjango-modelsdjango-templatesforeign-keys

Getting a specific field (e.g. name) instead of pk in object_list for rendering for a foreignkey


I have an app for example:

class example(models.Model, TemplateHelperClass):
    reviewer = CharField(max_length=255, verbose_name="Title")
    book = ForeignKey(books, on_delete=models.PROTECT)
    review = TextField()
...

class books(models.Model, TemplateHelperClass):
    author = CharField(max_length=255, verbose_name="Author")
    book_title = CharField(max_length=255, verbose_name="Title")
    publisher = CharField(max_length=255, verbose_name="Author")

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

class templateHelperClass():

    paginate_by = 15

    def get_fields(self):
        return [(field, field.value_to_string(self)) for field in self._meta.fields]

*views.py*

class bookReviewList(ListView):
    model = example
    template_name = "bookreviews.html"

...

*bookreviews.html*

{% extends "base.html" %}
{% block content %}
    <table class="table">
        <thead>
            <tr>
                {% for fld, val in object_list.0.get_fields %}
                <th>{{ fld.verbose_name |title  }}</th>
                {% endfor %}
                <th></th>
            </tr>
        </thead>
        <tbody>
            {% for object in object_list %}
            <tr>
                {% for fl1, val1 in object.get_fields %}
                <td>{{val1}}</td>
                {% endfor %}
                <td><a class="btn btn-dark" href='{{ object.get_absolute_url }}'>Update</a></td>
            </tr>
            {% endfor %}
        </tbody>
    </table>
{% endblock %}

The output html displays the pk for the book, and not the book title (the __str__ method) in this case. I'd like to display the __str__ method. Two questions, both related:

(1) Is there a more elegant way to represent the form with my attributes in table format. (I'm using bootstrap for some of the formatting)

(2) If not, how do I get the foreignkey field to display the __str__ return and not the pk?

The TemplateHelperClass is a MixIn for multiple models and the equivalent template for bookreview.html is likewise used for multiple views so I don't want to have to use specific field names in either if I can avoid it on the principle of DRY.


Solution

  • The easy solution is to use custom logic instead of field.value_to_string(...) method

    class templateHelperClass():
        paginate_by = 15
    
        def get_fields(self):
            return [(field, str(getattr(self, field.name))) for field in self._meta.fields]

    OR, use the custom logic only for FK field, as

    class templateHelperClass:
        paginate_by = 15
    
        def get_fields(self):
            return [
                (field, str(getattr(self, field.name)))
                if isinstance(field, models.ForeignKey)
                else (field, field.value_to_string(self))
                for field in self._meta.fields
            ]