How do I display a related object set in django?

1.6k views Asked by At

I know the question seems simple to answer, and that the answer would be in the API ref somewhere, but I'm a bit new to django and have poured through the API for days trying to get this done. Any help would be highly appreciated!

I'm creating a basic blogging app for my University's computer labs, and in this app you have two relevant pages. A locations page which displays information about each lab on campus (hours, location/building), and a resources page which displays information about the equipment in each lab.

I have my models.py file set up as shown (there are other models but these are the only relevant ones:

class Location(models.Model):
    name = models.CharField(max_length=100)
    computer = models.ForeignKey('Computer')
    printer = models.ForeignKey('Printer')

class Computer(models.Model):
    computer_location = models.ForeignKey('Location', related_name='lab_computers')
    computer_model = models.ForeignKey('HardwareModel')

class Printer(models.Model):
    printer_location = models.ForeignKey('Location', related_name='lab_printers')
    printer_model = models.ForeignKey('HardwareModel')

class HardwareModel(models.Model):
    brand = models.CharField(max_length = 100)
    model_num = models.CharField(max_length = 30)

My views.py file:

class LocationsView(generic.ListView): #This isn't the view to be concerned with
    template_name = 'blog/location_list.html'
    context_object_name = 'locations'
    queryset = Location.objects.all()

#This is commented out because i was trying to modify the view to allow extra context
#I'm aware that you can't have 2 views with the same name. Just assume only one is active
#class ResourcesView(generic.ListView):
#    context_object_name = 'locations'
#    queryset = Location.objects.all()

def ResourcesView(request):
    locations = Location.objects.prefetch_related('lab_printers').all()
    return render_to_response('blog/resource_list.html',
          {'locations': locations})

The template that I need to display this in is like this:

<table>
    <tr>
        <th>Lab</th>
        <th>Device</th>
        <th>Type</th>
        <th>Model</th>
    </tr>
    {% for location in locations %}
    <tr>
        <td rowspan="{{ location.lab_printers.count }}">{{ location.name }}</td>
        <td>Computer</td>
        <td>{{ location.computer.computer_model.brand }}</td>
        <td>{{ location.computer.computer_model.model_num }}</td>
    </tr>
    <tr>
        <td>Printer</td>
        <td>{{ location.printer.printer_model.brand }}</td>
        <td>{{ location.printer.printer_model.model_num }}</td>
    </tr>
{% endfor %}
</table>

The point of displaying it like this is the the University has strict guidelines on how information on the web pages are presented and they want everything in neat organized tables. The table needs to have a dynamic rowspan on the first column to support people adding or deleting computer/printer types through django admin.

I searched through StackOverflow and found a few issues similar to mine and they said to use prefetch_related to get the related objects in one batch query, however when I did this I began to get a TypeError "RelatedManager" is not an iterable when trying to access the printers in the template. I understand why this is happening. It's because the RelatedManager class handling the query does not return a list/array/tuple. I just don't know how in the heck I can access the information I need in the way I need it.

I did have it partially working with the commented-out Generic View, however when I use location.lab_printers.count The values came back inconsistent and didn't reflect the actual objects in the database, messing up the formatting, and resulting in missing td elements and inaccurate display.

Sorry if I'm rambling, this is just a complex problem and I have absolutely run out of ideas on how I should go about doing this.

Any and all help would be so very greatly appreciated. Thank you for your time!

1

There are 1 answers

0
f43d65 On BEST ANSWER

Not the answer, but use ManyToManyField for Location-Computer and Location-Printer relations. Docs link1, link2.