1

Django アプリケーション用のカスタム ウィジェットを作成して、Twitter Bootstrap のボタン グループと複数選択ウィジェットのインターフェイスを作成しました (これらのウィジェットは好きではありませんでした)。データベース オブジェクトからフォームをインスタンス化すると、値が入力されません。

本当に困惑しているのは、request.POST をコンストラクターに渡すフォームを作成するときに、これらのウィジェットに値が入力されることです。データベース オブジェクトと POST オブジェクトからのデータまたはフォームへの入力方法の違いのようですが、そこからどこへ行くべきかわかりません。

ウィジェットは次のとおりです。

from itertools import chain
from django.forms.util import flatatt
from django.forms.widgets import CheckboxSelectMultiple
from django.utils.encoding import force_unicode
from django.utils.html import conditional_escape
from django.utils.safestring import mark_safe

# todo-devon Values are not preserved with object instances
class BootstrapButtonSelect(CheckboxSelectMultiple):

    def __init__(self, attrs=None, all=False, none=False, classes=[], layout='horizontal'):
        """
        Optional arguments for creating a BootstrapButtonSelect widget. Default settings are in brackets.

        all=True/[False]
        Adds a button to select all options when set to True.

        none=True[False]
        Adds a button to select none of the options when set to True.

        classes=[]
        A list of strings which adds CSS classes to the buttons making up the button select widget. The btn class is already included. Examples: 'btn-large', 'btn-primary'

        layout=['horizontal']
        Sets the layout of the button select widget to 'horizontal' or 'vertical' (Not yet implemented. All groups are currently vertical.)
        """
        super(BootstrapButtonSelect, self).__init__(attrs)
        self.all = all
        self.none = none
        self.layout = layout

        if classes:
            self.classes = u' %s' % u' '.join(classes)
        else:
            self.classes = u''


    def render(self, name, value, attrs=None, choices=()):
        """
        Builds button group and select list for widget
        """
        # todo-devon Add code for horizontal layout
        if value is None: value = []
        has_id = attrs and 'id' in attrs
        final_attrs = self.build_attrs(attrs, name=name)

        # Create the select multiple widget
        select_output = [u'<select class="button-toggles" id="%s" multiple="multiple"%s>' % (name, flatatt(final_attrs),)]
        for i, (option_value, option_label) in enumerate(chain(self.choices, choices)):
            # If an ID attribute was given, add a numeric index as a suffix,
            # so that the checkboxes don't all have the same ID attribute.
            if has_id:
                final_attrs = dict(final_attrs, id='%s_%s' % (attrs['id'], i,))
            option_value = force_unicode(option_value)
            option_label = conditional_escape(force_unicode(option_label))
            if option_value in value:
                select_output.append(u'<option value="%s" selected="selected">%s</label>' % (option_value, option_label))
            else:
                select_output.append(u'<option value="%s">%s</label>' % (option_value, option_label))
        select_output.append('</select>')
        select_output = u'\n'.join(select_output)

        # Create the button group
        button_output = [u'<div class="btn-select-vertical span3 hidden-phone" id="%s" data-toggle="buttons-checkbox">' % name]
        for i, (option_value, option_label) in enumerate(chain(self.choices, choices)):
            # If an ID attribute was given, add a numeric index as a suffix,
            # so that the checkboxes don't all have the same ID attribute.
            if has_id:
                final_attrs = dict(final_attrs, id='%s_%s' % (attrs['id'], i,))
                label_for = u' for="%s"' % final_attrs['id']
            else:
                label_for = ''
            option_value = force_unicode(option_value)
            option_label = conditional_escape(force_unicode(option_label))
            button_output.append(u'<label%s class="btn%s" id="btn-%s-%s" data-name="%s,%s">%s</label>' % (label_for, self.classes, name, option_value, name, option_value, option_label))
        button_output.append(u'</div>')
        button_output = u'\n'.join(button_output)

        # Buttons for select all or none
        if self.all or self.none:
            select_all_none_button_output = [u'<div class="btn-group all-none-buttons" data-toggle="buttons-radio" data-name="%s">' % name]
            if self.all:
                select_all_none_button_output.append(u'<button class="select-all btn%s" type="button" data-name="%s">All</button>' % (self.classes, name,))
            if self.none:
                select_all_none_button_output.append(u'<button class="select-none btn%s" type="button" data-name="%s">None</button>' % (self.classes, name,))
            select_all_none_button_output.append(u'</div>')
            select_all_none_button_output = u'\n'.join(select_all_none_button_output)

        # Full output
        if select_all_none_button_output:
            output = "%s\n%s\n%s" % (select_output, button_output, select_all_none_button_output)
        else:
            output = "%s\n%s" % (select_output, button_output)

        return mark_safe(output)

    class Media:
        js = ('/static/bootstrap-button-multiselect.js',)
        css = {
            'all': ('/static/bootstrap-button-multiselect.css',)
        }

混乱している場合は、CSS を使用して大きな画面にボタンを表示してから、携帯電話やタブレットの複数選択ウィジェットに戻します。私のビュー機能:

from django.http import HttpResponseRedirect
from django.shortcuts import render_to_response
from django.template.context import RequestContext
from tickets.forms import TicketForm
from tickets.models import Ticket

def addEditTicket(request, op='add', encrypted_pk=None, cipher=None):
    """
    Form and processing for new tickets
    """
    if encrypted_pk is not None:
        pk = int(encrypted_pk) ^ cipher
        ticket  = Ticket.objects.get(pk=pk)
        form = TicketForm(instance=ticket)
        initialData = {'form': form, 'form_action': '/ticket/' + op + '/', 'title': op.capitalize() + ' a ticket'}
        csrfContext = RequestContext(request, initialData)              # adds CSRF token to form context
        return render_to_response('form.html', csrfContext)             # pass context with token to form

    if request.method == 'POST':
        form = TicketForm(request.POST)
        if form.is_valid():
            new_ticket = form.save()
            form = TicketForm(instance=new_ticket)
            # todo-devon Notify user in new form that object was saved
            # Context includes form object, URL for form action (dynamically generated from argument passed as op),
            # and a title dynamically generated from operation combined with the object type in question.
            initialData = {'form': form, 'form_action': '/ticket/edit/', 'title': 'Edit a ticket'}
            csrfContext = RequestContext(request, initialData)      # adds CSRF token to form context
            return render_to_response('form.html', csrfContext)     # pass context with token to form
    else:
        form = TicketForm()

    # Context includes form object, URL for form action (dynamically generated from argument passed as op),
    # and a title dynamically generated from operation combined with the object type in question.
    initialData = {'form': form, 'form_action': '/ticket/' + op + '/', 'title': op.capitalize() + ' a ticket'}
    csrfContext = RequestContext(request, initialData)              # adds CSRF token to form context
    return render_to_response('form.html', csrfContext)             # pass context with token to form

このコードをすべてここにダンプして申し訳ありません。前もって感謝します。

編集:Javascriptを取り出しました。それは質問とはあまり関係がありませんでした。残念ながら、私の質問はより困難に見えました。

4

1 に答える 1

0

解決策を見つけました、そして、私はそれがなぜうまくいくのかわかりません、と言うことを誇りに思っていません。選択した値を繰り返し処理し、それぞれにUnicodeを強制する必要がありました。データベースのオブジェクトはUnicodeではないと思います。ウィジェットが初期化されたときに、なぜこれらが一致して設定されないのかわかりませんが、機能することを嬉しく思います。この解決策を見つけるために、Djangoのデフォルトの選択ウィジェットを調べました。

みなさん、ありがとうございました。

于 2012-05-14T11:12:14.673 に答える