2017-05-07 69 views
2

我有一個藝術家和軌道類的模型,當軌道的標題字段有大括號時,我得到一個KeyError異常。 (例如曲目標題「Beat It {Freestyle}」)。看起來像django_tables2傳遞我的曲目標題字段值string.format()。我如何防止在django_tables2?Django-tables2 KeyError當字段有{花括號}

models.py
class Artist (models.Model): 
    name = models.CharField(max_length=100) 
    slug = AutoSlugField(populate_from='name', unique=True, editable=True, slugify=custom_slugify) 


class Track (models.Model):  
    artist = models.ForeignKey(Artist, blank=True, null=True, on_delete=models.SET_NULL, verbose_name="Artist") 
    user = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True, on_delete=models.SET_NULL, verbose_name="Submitted by", default=1) 
    title = models.CharField(max_length=100, verbose_name="Title") 
    timestamp = models.DateTimeField(default=timezone.now) 

tables.py
class TrackTable(tables.Table): 
    def __init__(self, *args, **kwargs): 
     self.user = kwargs.pop('user', None) 
     self.artistlink = kwargs.pop('artistlink', None) 
     super(TrackTable, self).__init__(*args, **kwargs) 

def render_artist(self, value): 
    if self.artistlink == True: 
     return format_html('<a href="/music/by/{}">{}</a>', value.slug, value) 
    else: 
     return value 

def render_user(self, value): 
    return format_html('<a href="https://stackoverflow.com/users/{}">{}</a>', value, value) 

download = DownloadColumn(empty_values=(), orderable=False) 

track_id = tables.CheckBoxColumn(accessor="pk", 
          attrs = {"th__input": {"id": "checkAll"}}, 
          orderable=False) 

class Meta: 
    model = Track 
    attrs = {"class": "table table-bordered table-condensed table-striped", "id": "track-table",} 
    fields = ('track_id', 'artist', 'title', 'user', 'download') 

views.py
def profile_detail(request, slug=None): 
    alpha_list = ['0-9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']   

    playlist_list = Playlist.objects.filter(user=request.user.id) 

    track_list = Track.objects.filter(artist__slug=slug) 
    ltr = slug[0].upper() 
    artist = get_object_or_404(Artist, slug=slug) 

    table = TrackTable(track_list, user=request.user, artistlink=False) 

    RequestConfig(request, paginate={"per_page": 15}).configure(table) 

    context = { 
     "playlist_list": playlist_list, 
     "track_list": track_list, 
     "table": table, 
     "alpha_list": alpha_list, 
     "artist": artist, 
    } 
    return render(request, "profile_detail.html", context) 

profile_detail.html
<form method='POST' id="add-track-form" action='{% url "playlists:playlist_addtrack" %}'>{% csrf_token %} 
... 
     {% render_table table "django_tables2/bootstrap3.html" %} 
... 
</form> 

bootstrap3.html

% load querystring from django_tables2 %} 
{% load trans blocktrans from i18n %} 
{% load bootstrap3 %} 

{% if table.page %} 
    <div class="table-responsive"> 
{% endif %} 

{% block table %} 
    <table{% if table.attrs %} {{ table.attrs.as_html }}{% endif %}> 
     {% block table.thead %} 
      <thead> 
      <tr> 
       {% for column in table.columns %} 
        {% if column.orderable %} 
         <th {{ column.attrs.th.as_html }}><a href="{% querystring table.prefixed_order_by_field=column.order_by_alias.next %}">{{ column.header }}</a></th> 
        {% else %} 
         <th {{ column.attrs.th.as_html }}>{{ column.header }}</th> 
        {% endif %} 
       {% endfor %} 
      </tr> 
      </thead> 
     {% endblock table.thead %} 
     {% block table.tbody %} 
      <tbody> 
      {% for row in table.page.object_list|default:table.rows %} {# support pagination #} 
       {% block table.tbody.row %} 
        <tr class="{% cycle "odd" "even" %}"> 
         {% for column, cell in row.items %} 
          <td {{ column.attrs.td.as_html }}>{{ cell }}</td> 
         {% endfor %} 
        </tr> 
       {% endblock table.tbody.row %} 
      {% empty %} 
       {% if table.empty_text %} 
        {% block table.tbody.empty_text %} 
         <tr><td colspan="{{ table.columns|length }}">{{ table.empty_text }}</td></tr> 
        {% endblock table.tbody.empty_text %} 
       {% endif %} 
      {% endfor %} 
      </tbody> 
     {% endblock table.tbody %} 
     {% block table.tfoot %} 
      <tfoot></tfoot> 
     {% endblock table.tfoot %} 
    </table> 
    </div> <!-- table-responsive --> 
{% endblock table %} 

回溯:

Template error: 
In template /Users/will/bpmdata/bpmdb/templates/django_tables2/bootstrap3.html, error at line 29 
    Freestyle 19 :      {% endif %} 
    20 :     {% endfor %} 
    21 :    </tr> 
    22 :    </thead> 
    23 :   {% endblock table.thead %} 
    24 :   {% block table.tbody %} 
    25 :    <tbody> 
    26 :    {% for row in table.page.object_list|default:table.rows %} {# support pagination #} 
    27 :     {% block table.tbody.row %} 
    28 :      <tr class="{% cycle "odd" "even" %}"> 
    29 :       {% for column, cell in row.items %} 
    30 :        <td {{ column.attrs.td.as_html }}>{{ cell }}</td> 
    31 :       {% endfor %} 
    32 :      </tr> 
    33 :     {% endblock table.tbody.row %} 
    34 :    {% empty %} 
    35 :     {% if table.empty_text %} 
    36 :      {% block table.tbody.empty_text %} 
    37 :       <tr><td colspan="{{ table.columns|length }}">{{ table.empty_text }}</td></tr> 
    38 :      {% endblock table.tbody.empty_text %} 
    39 :     {% endif %} 

Traceback: 

File "/Users/will/.virtualenvs/bpmdb/lib/python3.5/site-packages/django/core/handlers/exception.py" in inner 
    41.    response = get_response(request) 

File "/Users/will/.virtualenvs/bpmdb/lib/python3.5/site-packages/django/core/handlers/base.py" in _legacy_get_response 
    249.    response = self._get_response(request) 

File "/Users/will/.virtualenvs/bpmdb/lib/python3.5/site-packages/django/core/handlers/base.py" in _get_response 
    187.     response = self.process_exception_by_middleware(e, request) 

File "/Users/will/.virtualenvs/bpmdb/lib/python3.5/site-packages/django/core/handlers/base.py" in _get_response 
    185.     response = wrapped_callback(request, *callback_args, **callback_kwargs) 

File "/Users/will/bpmdata/bpmdb/profiles/views.py" in profile_detail 
    136. return render(request, "profile_detail.html", context) 

File "/Users/will/.virtualenvs/bpmdb/lib/python3.5/site-packages/django/shortcuts.py" in render 
    30.  content = loader.render_to_string(template_name, context, request, using=using) 

File "/Users/will/.virtualenvs/bpmdb/lib/python3.5/site-packages/django/template/loader.py" in render_to_string 
    68.  return template.render(context, request) 

File "/Users/will/.virtualenvs/bpmdb/lib/python3.5/site-packages/django/template/backends/django.py" in render 
    66.    return self.template.render(context) 

File "/Users/will/.virtualenvs/bpmdb/lib/python3.5/site-packages/django/template/base.py" in render 
    207.      return self._render(context) 

File "/Users/will/.virtualenvs/bpmdb/lib/python3.5/site-packages/django/template/base.py" in _render 
    199.   return self.nodelist.render(context) 

File "/Users/will/.virtualenvs/bpmdb/lib/python3.5/site-packages/django/template/base.py" in render 
    990.     bit = node.render_annotated(context) 

File "/Users/will/.virtualenvs/bpmdb/lib/python3.5/site-packages/django/template/base.py" in render_annotated 
    957.    return self.render(context) 

File "/Users/will/.virtualenvs/bpmdb/lib/python3.5/site-packages/django/template/loader_tags.py" in render 
    177.    return compiled_parent._render(context) 

File "/Users/will/.virtualenvs/bpmdb/lib/python3.5/site-packages/django/template/base.py" in _render 
    199.   return self.nodelist.render(context) 

File "/Users/will/.virtualenvs/bpmdb/lib/python3.5/site-packages/django/template/base.py" in render 
    990.     bit = node.render_annotated(context) 

File "/Users/will/.virtualenvs/bpmdb/lib/python3.5/site-packages/django/template/base.py" in render_annotated 
    957.    return self.render(context) 

File "/Users/will/.virtualenvs/bpmdb/lib/python3.5/site-packages/django/template/loader_tags.py" in render 
    72.     result = block.nodelist.render(context) 

File "/Users/will/.virtualenvs/bpmdb/lib/python3.5/site-packages/django/template/base.py" in render 
    990.     bit = node.render_annotated(context) 

File "/Users/will/.virtualenvs/bpmdb/lib/python3.5/site-packages/django/template/base.py" in render_annotated 
    957.    return self.render(context) 

File "/Users/will/.virtualenvs/bpmdb/lib/python3.5/site-packages/django/template/defaulttags.py" in render 
    322.     return nodelist.render(context) 

File "/Users/will/.virtualenvs/bpmdb/lib/python3.5/site-packages/django/template/base.py" in render 
    990.     bit = node.render_annotated(context) 

File "/Users/will/.virtualenvs/bpmdb/lib/python3.5/site-packages/django/template/base.py" in render_annotated 
    957.    return self.render(context) 

File "/Users/will/.virtualenvs/bpmdb/lib/python3.5/site-packages/django_tables2/templatetags/django_tables2.py" in render 
    154.    return template.render(context.flatten()) 

File "/Users/will/.virtualenvs/bpmdb/lib/python3.5/site-packages/django/template/backends/django.py" in render 
    66.    return self.template.render(context) 

File "/Users/will/.virtualenvs/bpmdb/lib/python3.5/site-packages/django/template/base.py" in render 
    207.      return self._render(context) 

File "/Users/will/.virtualenvs/bpmdb/lib/python3.5/site-packages/django/template/base.py" in _render 
    199.   return self.nodelist.render(context) 

File "/Users/will/.virtualenvs/bpmdb/lib/python3.5/site-packages/django/template/base.py" in render 
    990.     bit = node.render_annotated(context) 

File "/Users/will/.virtualenvs/bpmdb/lib/python3.5/site-packages/django/template/base.py" in render_annotated 
    957.    return self.render(context) 

File "/Users/will/.virtualenvs/bpmdb/lib/python3.5/site-packages/django/template/loader_tags.py" in render 
    63.     result = self.nodelist.render(context) 

File "/Users/will/.virtualenvs/bpmdb/lib/python3.5/site-packages/django/template/base.py" in render 
    990.     bit = node.render_annotated(context) 

File "/Users/will/.virtualenvs/bpmdb/lib/python3.5/site-packages/django/template/base.py" in render_annotated 
    957.    return self.render(context) 

File "/Users/will/.virtualenvs/bpmdb/lib/python3.5/site-packages/django/template/loader_tags.py" in render 
    63.     result = self.nodelist.render(context) 

File "/Users/will/.virtualenvs/bpmdb/lib/python3.5/site-packages/django/template/base.py" in render 
    990.     bit = node.render_annotated(context) 

File "/Users/will/.virtualenvs/bpmdb/lib/python3.5/site-packages/django/template/base.py" in render_annotated 
    957.    return self.render(context) 

File "/Users/will/.virtualenvs/bpmdb/lib/python3.5/site-packages/django/template/defaulttags.py" in render 
    216.      nodelist.append(node.render_annotated(context)) 

File "/Users/will/.virtualenvs/bpmdb/lib/python3.5/site-packages/django/template/base.py" in render_annotated 
    957.    return self.render(context) 

File "/Users/will/.virtualenvs/bpmdb/lib/python3.5/site-packages/django/template/loader_tags.py" in render 
    63.     result = self.nodelist.render(context) 

File "/Users/will/.virtualenvs/bpmdb/lib/python3.5/site-packages/django/template/base.py" in render 
    990.     bit = node.render_annotated(context) 

File "/Users/will/.virtualenvs/bpmdb/lib/python3.5/site-packages/django/template/base.py" in render_annotated 
    957.    return self.render(context) 

File "/Users/will/.virtualenvs/bpmdb/lib/python3.5/site-packages/django/template/defaulttags.py" in render 
    172.     values = list(values) 

File "/Users/will/.virtualenvs/bpmdb/lib/python3.5/site-packages/django_tables2/rows.py" in items 
    229.    yield (column, self.get_cell(column.name)) 

File "/Users/will/.virtualenvs/bpmdb/lib/python3.5/site-packages/django_tables2/rows.py" in get_cell 
    180.    default=self.table.columns[name].default 

File "/Users/will/.virtualenvs/bpmdb/lib/python3.5/site-packages/django_tables2/rows.py" in _get_and_render_with 
    155.   return render_func(bound_column, value) 

File "/Users/will/.virtualenvs/bpmdb/lib/python3.5/site-packages/django_tables2/rows.py" in _call_render 
    189.    self._optional_cell_arguments(bound_column, value) 

File "/Users/will/.virtualenvs/bpmdb/lib/python3.5/site-packages/django_tables2/utils.py" in call_with_appropriate 
    511.  return fn(**kwargs) 

File "/Users/will/bpmdata/bpmdb/profiles/tables.py" in render 
    42.   return format_html(referral_url, artist=artist1, title=record.title) 

File "/Users/will/.virtualenvs/bpmdb/lib/python3.5/site-packages/django/utils/html.py" in format_html 
    100.  return mark_safe(format_string.format(*args_safe, **kwargs_safe)) 

Exception Type: KeyError at /music/by/michael-jackson/ 
Exception Value: 'Freestyle' 

回答

2

考慮到在串花括號不能默默傳遞時str.format被調用,除非你控制的格式是怎麼做的(你不能在這裏) ,你可以用另一個字符替換大括號,比如一個雙人字母((..))或者預期str.format;但後者是更脆弱的,因爲該字段的值取決於以後致電str.format

>>> '{{Freestyle}}'.format() 
'{Freestyle}' 
+0

這真的是唯一的解決方案嗎?這似乎是一個相當明顯的限制,因爲如你所說,它使數據依賴於這個特定的後續處理。看起來圖書館應該在嘗試格式化數據之前逃避數據。 – BrenBarn

+0

@BrenBarn我認爲這些調整最終要比圖書館的做得更好,因爲圖書館只是簡單地調用一些任意參數的「格式」 –

+0

但是這看起來不對嗎?曲目的標題是「Beat It {Freestyle}」,而不是「Beat It {{Freestyle}}」。將它存儲爲後者將數據綁定到這個特定的輸出機制。圖書館正在對它可能不應該做的數據做出假設(即它不包含大括號)。 – BrenBarn