简体   繁体   中英

Python Meta class and inheritance — attributes not recognized (django-tables2)

I'm trying to write a UsersTable class with django-tables2 to be sub-classed by StudentsTable . This code works fine:

tables.py

import django_tables2 as tables
from django_tables2.utils import A # alias for accessor
from .models.environment import Student

def getEditColumn(accessor, kwargs):
    return tables.LinkColumn(
        viewname='wakemeup:edit_object',
        kwargs=kwargs,
        verbose_name='',
        text='Editar',
        accessor=accessor
    )

class UsersTable(tables.Table):

    # Define constructor    
    def __init__(self, *args, **kwargs):
        # Call base table class constructor
        super(UsersTable, self).__init__(data = kwargs['data'])

        objectid = kwargs['objectid']
        objecttype = kwargs['objecttype']

        # Create base attributes
        self.objectid = objectid
        self.objecttype = objecttype

        self.mykwargs={
            'objecttype': objecttype,
            'objectid': A(objectid)
        }

        self.edit_link = getEditColumn(objectid, self.mykwargs)

    class Meta:
        model = Student

class StudentsTable(UsersTable):

    # Call UsersTable constructor
    def __init__(self, *args, **kwargs):
        super(StudentsTable, self).__init__(*args, **kwargs)
        print(self.edit_link) # Verify edit_link has been generated

    class Meta:
        sequence = ('firstname','lastname','emailaddress','phonenumber','defaultsignaturescanfile','classid')

However, when I try to reference the edit_link column inherited from UsersTable , I get an error:

Modified StudentsTable

class StudentsTable(UsersTable):

    # Call UsersTable constructor
    def __init__(self, *args, **kwargs):
        super(StudentsTable, self).__init__(*args, **kwargs)
        print(self.edit_link) # Verify edit_link has been generated

    class Meta:
        exclude = ('studentuserid','reputationvalue','schoolid')
        sequence = ('firstname','lastname','emailaddress','phonenumber','defaultsignaturescanfile','classid','edit_link')

Error

Exception Type: KeyError
Exception Value: 'edit_link'

It seems like the Meta class info is being read before the inherited edit_link column is generated. The print(edit_link) line returns the expected object, so the field is available.

I tried all kinds of futzing around with the Meta class, but no luck.

Edit

Here's the trace:

Environment:


Request Method: GET
Request URL: http://127.0.0.1:8000/wakemeup/admin/student

Django Version: 2.0.1
Python Version: 3.6.4
Installed Applications:
['django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'users.apps.UsersConfig',
 'wakemeup.apps.WakemeupConfig',
 'crispy_forms',
 'django_tables2']
Installed Middleware:
('whitenoise.middleware.WhiteNoiseMiddleware',
 'django.middleware.security.SecurityMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.common.CommonMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware',
 'django.middleware.clickjacking.XFrameOptionsMiddleware')


Template error:
In template C:\Program Files (x86)\Python36-32\lib\site-packages\django_tables2\templates\django_tables2\bootstrap.html, error at line 11
   edit_link
   1 : {% load django_tables2 %}
   2 : {% load i18n %}
   3 : {% block table-wrapper %}
   4 : <div class="table-container">
   5 :     {% block table %}
   6 :         <table {% if table.attrs %} {{ table.attrs.as_html }}{% else %}class="table"{% endif %}>
   7 :             {% block table.thead %}
   8 :             {% if table.show_header %}
   9 :                 <thead>
   10 :                 <tr>
   11 :                  {% for column in table.columns %} 
   12 :                     {% if column.orderable %}
   13 :                         <th {{ column.attrs.th.as_html }}><a href="{% querystring table.prefixed_order_by_field=column.order_by_alias.next %}">{{ column.header }}</a></th>
   14 :                     {% else %}
   15 :                         <th {{ column.attrs.th.as_html }}>{{ column.header }}</th>
   16 :                     {% endif %}
   17 :                 {% endfor %}
   18 :                 </tr>
   19 :                 </thead>
   20 :             {% endif %}
   21 :             {% endblock table.thead %}


Traceback:

File "C:\Program Files (x86)\Python36-32\lib\site-packages\django\core\handlers\exception.py" in inner
  35.             response = get_response(request)

File "C:\Program Files (x86)\Python36-32\lib\site-packages\django\core\handlers\base.py" in _get_response
  128.                 response = self.process_exception_by_middleware(e, request)

File "C:\Program Files (x86)\Python36-32\lib\site-packages\django\core\handlers\base.py" in _get_response
  126.                 response = wrapped_callback(request, *callback_args, **callback_kwargs)

File "c:\Users\ravioli\eclipse-workspace\dcp\wakemeup\views.py" in admin_list
  100.     return render(request, 'wakemeup/admin/index.html', {'objects' : objectSet, 'objecttype': objecttype})

File "C:\Program Files (x86)\Python36-32\lib\site-packages\django\shortcuts.py" in render
  36.     content = loader.render_to_string(template_name, context, request, using=using)

File "C:\Program Files (x86)\Python36-32\lib\site-packages\django\template\loader.py" in render_to_string
  62.     return template.render(context, request)

File "C:\Program Files (x86)\Python36-32\lib\site-packages\django\template\backends\django.py" in render
  61.             return self.template.render(context)

File "C:\Program Files (x86)\Python36-32\lib\site-packages\django\template\base.py" in render
  175.                     return self._render(context)

File "C:\Program Files (x86)\Python36-32\lib\site-packages\django\template\base.py" in _render
  167.         return self.nodelist.render(context)

File "C:\Program Files (x86)\Python36-32\lib\site-packages\django\template\base.py" in render
  943.                 bit = node.render_annotated(context)

File "C:\Program Files (x86)\Python36-32\lib\site-packages\django\template\base.py" in render_annotated
  910.             return self.render(context)

File "C:\Program Files (x86)\Python36-32\lib\site-packages\django\template\loader_tags.py" in render
  155.             return compiled_parent._render(context)

File "C:\Program Files (x86)\Python36-32\lib\site-packages\django\template\base.py" in _render
  167.         return self.nodelist.render(context)

File "C:\Program Files (x86)\Python36-32\lib\site-packages\django\template\base.py" in render
  943.                 bit = node.render_annotated(context)

File "C:\Program Files (x86)\Python36-32\lib\site-packages\django\template\base.py" in render_annotated
  910.             return self.render(context)

File "C:\Program Files (x86)\Python36-32\lib\site-packages\django\template\loader_tags.py" in render
  67.                 result = block.nodelist.render(context)

File "C:\Program Files (x86)\Python36-32\lib\site-packages\django\template\base.py" in render
  943.                 bit = node.render_annotated(context)

File "C:\Program Files (x86)\Python36-32\lib\site-packages\django\template\base.py" in render_annotated
  910.             return self.render(context)

File "C:\Program Files (x86)\Python36-32\lib\site-packages\django\template\loader_tags.py" in render
  67.                 result = block.nodelist.render(context)

File "C:\Program Files (x86)\Python36-32\lib\site-packages\django\template\base.py" in render
  943.                 bit = node.render_annotated(context)

File "C:\Program Files (x86)\Python36-32\lib\site-packages\django\template\base.py" in render_annotated
  910.             return self.render(context)

File "C:\Program Files (x86)\Python36-32\lib\site-packages\django_tables2\templatetags\django_tables2.py" in render
  169.             return template.render(context={'table': table}, request=request)

File "C:\Program Files (x86)\Python36-32\lib\site-packages\django\template\backends\django.py" in render
  61.             return self.template.render(context)

File "C:\Program Files (x86)\Python36-32\lib\site-packages\django\template\base.py" in render
  175.                     return self._render(context)

File "C:\Program Files (x86)\Python36-32\lib\site-packages\django\template\base.py" in _render
  167.         return self.nodelist.render(context)

File "C:\Program Files (x86)\Python36-32\lib\site-packages\django\template\base.py" in render
  943.                 bit = node.render_annotated(context)

File "C:\Program Files (x86)\Python36-32\lib\site-packages\django\template\base.py" in render_annotated
  910.             return self.render(context)

File "C:\Program Files (x86)\Python36-32\lib\site-packages\django\template\loader_tags.py" in render
  155.             return compiled_parent._render(context)

File "C:\Program Files (x86)\Python36-32\lib\site-packages\django\template\base.py" in _render
  167.         return self.nodelist.render(context)

File "C:\Program Files (x86)\Python36-32\lib\site-packages\django\template\base.py" in render
  943.                 bit = node.render_annotated(context)

File "C:\Program Files (x86)\Python36-32\lib\site-packages\django\template\base.py" in render_annotated
  910.             return self.render(context)

File "C:\Program Files (x86)\Python36-32\lib\site-packages\django\template\loader_tags.py" in render
  67.                 result = block.nodelist.render(context)

File "C:\Program Files (x86)\Python36-32\lib\site-packages\django\template\base.py" in render
  943.                 bit = node.render_annotated(context)

File "C:\Program Files (x86)\Python36-32\lib\site-packages\django\template\base.py" in render_annotated
  910.             return self.render(context)

File "C:\Program Files (x86)\Python36-32\lib\site-packages\django\template\loader_tags.py" in render
  67.                 result = block.nodelist.render(context)

File "C:\Program Files (x86)\Python36-32\lib\site-packages\django\template\base.py" in render
  943.                 bit = node.render_annotated(context)

File "C:\Program Files (x86)\Python36-32\lib\site-packages\django\template\base.py" in render_annotated
  910.             return self.render(context)

File "C:\Program Files (x86)\Python36-32\lib\site-packages\django\template\base.py" in render
  993.             output = self.filter_expression.resolve(context)

File "C:\Program Files (x86)\Python36-32\lib\site-packages\django\template\base.py" in resolve
  676.                 obj = self.var.resolve(context)

File "C:\Program Files (x86)\Python36-32\lib\site-packages\django\template\base.py" in resolve
  802.             value = self._resolve_lookup(context)

File "C:\Program Files (x86)\Python36-32\lib\site-packages\django\template\base.py" in _resolve_lookup
  864.                             current = current()

File "C:\Program Files (x86)\Python36-32\lib\site-packages\django\template\loader_tags.py" in super
  81.             return mark_safe(self.render(self.context))

File "C:\Program Files (x86)\Python36-32\lib\site-packages\django\template\loader_tags.py" in render
  67.                 result = block.nodelist.render(context)

File "C:\Program Files (x86)\Python36-32\lib\site-packages\django\template\base.py" in render
  943.                 bit = node.render_annotated(context)

File "C:\Program Files (x86)\Python36-32\lib\site-packages\django\template\base.py" in render_annotated
  910.             return self.render(context)

File "C:\Program Files (x86)\Python36-32\lib\site-packages\django\template\loader_tags.py" in render
  67.                 result = block.nodelist.render(context)

File "C:\Program Files (x86)\Python36-32\lib\site-packages\django\template\base.py" in render
  943.                 bit = node.render_annotated(context)

File "C:\Program Files (x86)\Python36-32\lib\site-packages\django\template\base.py" in render_annotated
  910.             return self.render(context)

File "C:\Program Files (x86)\Python36-32\lib\site-packages\django\template\defaulttags.py" in render
  314.                 return nodelist.render(context)

File "C:\Program Files (x86)\Python36-32\lib\site-packages\django\template\base.py" in render
  943.                 bit = node.render_annotated(context)

File "C:\Program Files (x86)\Python36-32\lib\site-packages\django\template\base.py" in render_annotated
  910.             return self.render(context)

File "C:\Program Files (x86)\Python36-32\lib\site-packages\django\template\defaulttags.py" in render
  168.             len_values = len(values)

File "C:\Program Files (x86)\Python36-32\lib\site-packages\django_tables2\columns\base.py" in __len__
  686.         return len(self.visible())

File "C:\Program Files (x86)\Python36-32\lib\site-packages\django_tables2\columns\base.py" in visible
  643.         return list(self.itervisible())

File "C:\Program Files (x86)\Python36-32\lib\site-packages\django_tables2\columns\base.py" in <genexpr>
  640.         return (x for x in self.iterall() if x.visible)

File "C:\Program Files (x86)\Python36-32\lib\site-packages\django_tables2\columns\base.py" in <genexpr>
  597.         return (column for name, column in self.iteritems())

File "C:\Program Files (x86)\Python36-32\lib\site-packages\django_tables2\columns\base.py" in iteritems
  614.                 yield (name, self.columns[name])

Exception Type: KeyError at /wakemeup/admin/student
Exception Value: 'edit_link'

I believe you have two issues with your code. Firstly the Meta attribute class on StudentsTable needs to inherit the UserTable.Meta attribute, or else it will not have model defined:

class StudentsTable(UsersTable):

    # Call UsersTable constructor
    def __init__(self, *args, **kwargs):
        super(StudentsTable, self).__init__(*args, **kwargs)
        print(self.edit_link) # Verify edit_link has been generated

    class Meta(UsersTable.Meta):
        sequence = ('firstname','lastname','emailaddress','phonenumber','defaultsignaturescanfile','classid')

Secondarily, the docs for django-tables2 says that sequence enumerates columns. Columns are either fields on the underlying model or column attributes of the table class :

class StudentsTable(UsersTable):
    edit_link = tables.LinkColumn(viewname='wakemeup:edit_object', text='Editar')

Rather than defining editLink on the instance in the __init__ method.

To load keyword arguments for the link from the model and table instance, you'll need to pass accessor instances to the Column rather than the literal kwarg values. The docs for LinkColumn indicate that should be done like this :

from django_tables2.utils import A 

class StudentsTable(UsersTable):
    edit_link = tables.LinkColumn(viewname='wakemeup:edit_object', text='Editar', kwargs={"name": A("name"))

This means you'll need to define which kwargs you need explicitly, rather than dynamically, which should not be a problem for you given that these are URL arguments that are defined as a contract somewhere.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM