1

I have three models:

class Entity(models.Model):
    entity = models.CharField(primary_key=True, max_length=25)

class Report(models.Model):
    report = models.CharField(max_length=50)
    report_link = models.CharField(max_length=300)

class Item(models.Model):
    entities = models.ManyToManyField(Entity, related_name='entities')
    report = models.ForeginKey(Report)

A view is built off of the Item model:

def item_list(request):
    items = Item.objects.select_related('report').prefetch_related('entities')
    return render(request, 'items/item_list.html', {'items':items})

This view gets routed to a template:

{% for item in items %}
  <tr>
    <td>
        {% for entity in item.entities.all %}
          {{ entity }}{% if not forloop.last %}, {% endif %}
        {% endfor %}
    </td>
    <td>{{ item.report }}</td>
    <td>{{ item.report.report_link|urlize }}</td>
  </tr>
{% endfor %}

This line (<td>{{ item.report.report_link|urlize }}</td>) manifests like this in the browser:

https://server.domain/reports/specificReport?entity=

How would I pass the entities into the URL to filter the report? The desired result would look like this:

https://server.domain/reports/specificReport?entity=12345

...or if there are multiple entities for one item:

https://server.domain/reports/specificReport?entity=12345,56789

Each report in the Report model has a link, but the link does not necessarily take the entity parameter, so it wouldn't be ideal to globally change all links (i.e. through jQuery or some other JS). However, there is JS running on this page, so it is possible to use that...although I think a Django option might be best.

One thing I've thought about is adding an indicator to the Report model that flags whether entities should be added to the link...but this doesn't solve the main problem of attaching one model field to the end of another and "urlizing" both of them together.

1 Answer 1

2

How about a model method to create the link? The Django docs mention the following about using model methods, which is applicable to your use case

This is a valuable technique for keeping business logic in one place – the model.

Meaning you don't need to dig though your templates and template tags to see how an Item's report link is generated -- you can see it all in models.py

Something along the following could be a place to start

class Item(models.Model):
    entities = models.ManyToManyField(Entity, related_name='entities')
    report = models.ForeginKey(Report)

    def get_report_link(self):
        link_text = self.report.report_link
        if self.entities.count() > 0:
            link_text + "?entity={}".format(','.join([entity.id for entity in self.entities.all()]))
        return link_text

and then in your template: change item.report.report_link|urlize to item.get_report_link

Sign up to request clarification or add additional context in comments.

5 Comments

I like that - thank you! And if an item had an entity but the report_link didn't accept a parameter? Would that just be an if/else statement...like pseudocode if self.report.report_link ends in "="......else....."?
I'm getting a 'ManyRelatedManager' object is not iterable error that points to the template line
Yeah this is untested code, you will need self.entities.all() i believe
that is fantastic - i have been scared of diving into model methods too deeply for some reason...this is a good nudge to make sure i look at them for cases like this. thank you so much.
you will be glad you did, especially as your project grows!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.