Opened 18 years ago

Closed 15 years ago

#2583 closed defect (worksforme)

can't use ForeignKey in list view (class Admin: list_display)

Reported by: 235 Owned by: nobody
Component: contrib.admin Version: dev
Severity: normal Keywords:
Cc: jos@… Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

If we'll use next code:

class Articles(models.Model):
    ....
    author = models.ForeignKey(Authors, blank=True, null=True, verbose_name='Автор статьи') #models.CharField('Автор статьи', maxlength=100, blank=True)
    ....
    class Admin:
        list_display = ('pub_date', ... 'author')

The list view of objects will be broken in header - there would be no header for this ForeignKey. In django/contrib/admin/templates/admin/change_list_result.html defined:

   <th{{ header.class_attrib }}>

and actualy it renders into (with TEMPLATE_STRING_IF_INVALID = "TEMPLATE_STRING_IF_INVALID" in settings.py):

   <thTEMPLATE_STRING_IF_INVALID>

ForeignKey field lacks this attribute

Change History (15)

comment:1 by anonymous, 18 years ago

Version: SVN

comment:2 by Adrian Holovaty, 18 years ago

Resolution: wontfix
Status: newclosed

I can't reproduce this error. Including the name of a ForeignKey field in list_display works just fine for me.

comment:3 by Adrian Holovaty, 18 years ago

Resolution: wontfix
Status: closedreopened

Whoop, should be marked as a "worksforme," not "wontfix."

comment:4 by Adrian Holovaty, 18 years ago

Resolution: worksforme
Status: reopenedclosed

comment:5 by Rob, 18 years ago

Resolution: worksforme
Status: closedreopened

Same problem here, an exmaple

class Content(models.Model):
    body        = models.CharField(maxlength=1024)

class Rating(models.Model):
    body        = models.CharField(maxlength=1024)
    severity    = models.IntegerField()
    type        = models.CharField(maxlength=128)
    application = models.CharField(maxlength=128)
    
    class Admin:
        list_display = ('type', 'severity', 'body', 'application')

    def __str__(self):
        return "%s" % (self.type)
        
    class Meta:
        verbose_name_plural = "Ratings"

class Message(models.Model):
    content     = models.ForeignKey(Content)
    rating      = models.ForeignKey(Rating)
    body        = models.CharField(maxlength=1024)
    date        = models.DateTimeField(auto_now=True)
    errclass    = models.CharField(maxlength=128)
    
    class Admin:
        list_display = ('errclass', 'body')

    def __str__(self):
        return "%s" % (self.body)
        
    class Meta:
        verbose_name_plural = "Messages"

When adding 'content' or 'rating' to the list_display of Messages, the admin view is empty, i.e. no list is generated. Maybe something to do with the fact that the Message model contains TWO foreign keys?

comment:6 by Russell Keith-Magee, 18 years ago

Resolution: worksforme
Status: reopenedclosed

I've loaded this exact model, tried it with and without TEMPLATE_STRING_IF_INVALID set, and the list of Messages on the admin site renders fine. If I add content and rating to list_display, I get two extra columns in the table as expected.

comment:7 by Bram.Dejong+django@…, 18 years ago

Resolution: worksforme
Status: closedreopened

I've just started a clean django project + app (django SVN trunk) and I can reproduce this bug on both windows and linux. The code to reproduce is as follows:

models.py

from django.db import models
from django.contrib.contenttypes.models import ContentType

class Tag(models.Model):
    name = models.SlugField(unique=True, maxlength=80)
    
    class Admin:
        pass

    def __str__(self):
        return self.name

class DaoTag(models.Model):
    tag = models.ForeignKey(Tag)
    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField()
    content_object = models.GenericForeignKey()
    
    class Admin:
        list_display = ('tagged_on', 'content_type', 'tag')
    
    def tagged_on(self):
        return str(self.content_type.model_class().objects.get(id=self.object_id))

Relevant parts of settings.py:

TEMPLATE_STRING_IF_INVALID = 'XXX MISSING VARIABLE XXX'

INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.sites',
    'django.contrib.admin',
    'missing_var',
)

Resulting HTML code:

<table cellspacing="0">
<thead>
<tr>
<thXXX MISSING VARIABLE XXX> <-----------------------!

Tagged on
</th><th>
<a href="?ot=asc&amp;o=1">
Content type

</a></th><th>
<a href="?ot=asc&amp;o=2">
Tag
</a></th>
</tr>
</thead>
<tbody>

Screenshot of admin:
http://bram.smartelectronix.com/tmp/admin.png

As the original poster mentioned, it's header.class_attrib which is missing...

comment:8 by Bram.Dejong+django@…, 17 years ago

( I just saw that it's even easier to reproduce this bug: it happens in the flatpages admin. )

comment:9 by James Bennett, 17 years ago

Am I missing something here, or is this just an instance of the (documented) fact that TEMPLATE_STRING_IF_INVALID breaks various parts of the admin? So long as TEMPLATE_STRING_IF_INVALID is an empty string, everything works fine. If you set it to anything else you start seeing weird stuff in places that rely on the silent failure of non-existent variables (and the docs recommend using TEMPLATE_STRING_IF_INVALID only as a temporary debugging measure for this very reason).

comment:10 by jos@…, 17 years ago

Cc: jos@… added

I have this same problem, the admin page remains blank when using a foreignkey in list_display AND there are multiple foreignkey's.
I have TEMPLATE_STRING_IF_INVALID unset.

My problem can be triggered with the following model.

class Function(models.Model):
    description = models.CharField(maxlength=255)
    subdescription = models.CharField(maxlength=255, blank=True)
    version = models.CharField(maxlength=20)
    functionclass = models.ForeignKey(Functionclass, db_column='servermanagmentApp_functionclass_id')
#    loadbalanceIpAddress = models.ForeignKey(Loadbalanceipaddress, db_column='servermanagmentApp_loadbalanceipaddress_id')
#    logicalvolume = models.ForeignKey(Logicalvolume, db_column='servermanagmentApp_logicalvolume_id')

    def __str__(self):
#        if hasattr(self, "loadbalanceIpAddress") and str(self.loadbalanceIpAddress) != "0.0.0.0:0":
#          return "%s %s (%s)" % (self.description, self.subdescription, self.loadbalanceIpAddress)
#        else:
          return "%s %s" % (self.description, self.subdescription)

    class Meta:
        ordering = ('description', )

    class Admin:
        pass
        list_display = ('description', 'subdescription', 'version', 'functionclass')
        list_filter = ('functionclass', )

class Functionclass(models.Model):
    description = models.CharField(maxlength=255, core=True)

    def __str__(self):
        return self.description

    class Admin:
        pass

class Loadbalanceipaddress(models.Model):
    ipaddress = models.IPAddressField()
    port = models.PositiveSmallIntegerField()

    class Meta:
        ordering = ('ipaddress', 'port', )

    class Admin:
        pass

As long as i keep either loadbalanceIpAddress or logicalvolume commented everything works.
But when either of those are uncommented (creating multiple foreignkeys) a blank list is generated by the admin.

As can be seen in the provided screenshots, the header and contents of the list fall away, the footer is still there.
http://brick29.hyves.org/86450001-86500000/86474901-86475000/86474961_6_c6aH.jpeg
http://brick29.hyves.org/86450001-86500000/86474901-86475000/86474962_6_keG9.jpeg

Following is the html source of the page with the empty list.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en-us" xml:lang="en-us" >
<head>
<title>Select function to change | Django site admin</title>
<link rel="stylesheet" type="text/css" href="/media/css/changelists.css" />



</head>


<body class="change-list">

<!-- Container -->
<div id="container">

    
    <!-- Header -->
    <div id="header">
        <div id="branding">
        
<h1 id="site-name">Django administration</h1>

        </div>
        
        <div id="user-tools">Welcome, <strong>root</strong>. <a href="../../doc/">Documentation</a> / <a href="../../password_change/">Change password</a> / <a href="../../logout/">Log out</a></div>

        
        
    </div>
    <!-- END Header -->
    <div class="breadcrumbs"><a href="../../">Home</a> &rsaquo; Functions</div>
    

        

    <!-- Content -->
    <div id="content" class="flex">
        
        <h1>Select function to change</h1>

        
<div id="content-main">

<ul class="object-tools"><li><a href="add/" class="addlink">Add function</a></li></ul>

<div class="module filtered" id="changelist">








<div id="changelist-filter">
<h2>Filter</h2>

   
<h3> By functionclass </h3>
<ul>

    <li class="selected">
    <a href="?">All</a></li>

    <li>
    <a href="?functionclass__id__exact=1">MySql</a></li>

    <li>
    <a href="?functionclass__id__exact=2">www</a></li>

    <li>
    <a href="?functionclass__id__exact=3">daemons</a></li>

    <li>
    <a href="?functionclass__id__exact=4">squid</a></li>

    <li>
    <a href="?functionclass__id__exact=5">chat</a></li>

    <li>
    <a href="?functionclass__id__exact=6">loadbalancer</a></li>

    <li>
    <a href="?functionclass__id__exact=7">storage</a></li>

    <li>
    <a href="?functionclass__id__exact=8">sysadmin</a></li>

    <li>
    <a href="?functionclass__id__exact=9">ip-telephony</a></li>

    <li>
    <a href="?functionclass__id__exact=10">brick</a></li>

    <li>
    <a href="?functionclass__id__exact=11">mail</a></li>

    <li>
    <a href="?functionclass__id__exact=12">bricksbackuphead</a></li>

</ul>

</div>




<p class="paginator">


    <span class="this-page">1</span> 

    <a href="?p=1" class="end">2</a> 


182 functions
&nbsp;&nbsp;<a href="?all=" class="showall">Show all</a>
</p>

</div>
</div>

        
        <br class="clear" />
    </div>
    <!-- END Content -->

    <div id="footer"></div>
</div>
<!-- END Container -->

</body>
</html>

comment:11 by jos@…, 17 years ago

Above problem as described by me was the result of errors in the consistency of the loaded dataset.
The database query therefor generated an empty result set when the loadbalancerip table was included in the join.

Still i think this should have generated a message, informing that there where no results to display.

Iam sorry for the false report

comment:12 by Jacob, 17 years ago

Resolution: worksforme
Status: reopenedclosed

worksforme -- all the reported cases are either TEMPLATE_STRING_IF_INVALID or messed up data.

comment:13 by James Bennett, 16 years ago

This is definitely fixed in trunk now, but for anyone stumbling across it on older Django: another way to trigger this is to have two foreign keys to the same table, one of them with null=True and the other set in list_display (older versions of Django will not do the proper join to make this work).

comment:14 by attila_forgacs, 15 years ago

Resolution: worksforme
Status: closedreopened

Reproducible in Django 1.1.1.
Just to be sure :
TEMPLATE_STRING_IF_INVALID =
Model works perfect.
If I refer a FK in list_display
the whole row is gone !
Nothing is displayed. Screen sais i should see 15 records,
there ain't any not even in the HTML.
So i had to reopen ticket.

in reply to:  14 comment:15 by Karen Tracey, 15 years ago

Resolution: worksforme
Status: reopenedclosed

Replying to attila_forgacs:

The original problem here was apparently due to having TEMPLATE_STRING_IF_INVALID set to something other than an empty string, and it involved incorrect display, not all of the entries that should be there not being displayed. Thus, you seem to be having a different problem, not this one.

Plenty of people use ForeignKeys in list_display; this feature is not fundamentally broken. There is something particular to your models, your configuration, or possibly even the data in your database that is causing the problem you are seeing. Since you have provided no information about any of that, it's rather difficult to help diagnose. Also, this is not the right place for it. I suggest posting more information on django-users and someone may be able to help. At this point a ticket is premature because we have no idea whether the problem is in your setup or in Django itself.

Note: See TracTickets for help on using tickets.
Back to Top