Подтвердить что ты не робот

Django - Render CheckboxSelectMultiple() виджет индивидуально в шаблоне (вручную)

У меня есть две модели:

models.py

class App(models.Model):
    app_name = models.SlugField(max_length=50)
    options_loaded = models.ManyToManyField(Option)
    created_by = models.ForeignKey(User)

    def __unicode__(self):
        return self.name

class Option(models.Model):
    option_name = models.SlugField(max_length=50)
    condition = models.BooleanField('Enable condition')
    option = models.BooleanField('Enable option1')
    created_by = models.ForeignKey(User)

    def __unicode__(self):
        return self.option_name

Я бы хотел отобразить форму, которая будет выглядеть так: где флажки из разных моделей (первый столбец из поля M2M с виджем CheckboxSelectMultiple()), а имя_параметра может быть <a href="/link/">Option_name</a>

enter image description here

Возможно ли это?

4b9b3361

Ответ 1

Это мое простое решение: визуализировать CheckboxSelectMultiple() вручную в шаблоне

<table>
<thead>
  <tr>
    <td>&nbsp;</td>
    <td>V</td>
    <td>S</td>
  </tr>
</thead>    
{% for pk, choice in form.options.field.widget.choices %}
<tr>
  <td><a href="/link/{{ choice }}">{{ choice }}</a></td>
  <td>
    <label for="id_options_{{ forloop.counter0 }}">
      <input {% for m2moption in model.m2moptions.all %}{% if option.pk == pk %}checked="checked"{% endif %}{% endfor %} type="checkbox" id="id_options_{{ forloop.counter0 }}" value="{{ pk }}" name="options" />
    </label>
  </td>
</tr>
{% endfor %}                
</table>

Ответ 2

http://dev.yaconiello.com/playground/example/one/

Во-первых, я бы реструктурировал ваши модели. То, как вы в настоящее время настроены, отношение флажка опции/приложения будет вести себя плохо. Каждый параметр мог бы иметь только одно логическое проверочное значение, которое было передано всем объектам приложения.

Модели

from django.db import models
from django.utils.translation import ugettext as _

class Option(models.Model):
    condition = models.CharField(
        verbose_name = _(u'Condition Text'),
        max_length = 255,
    )
    option = models.CharField(
        verbose_name = _(u'Option Text'),
        max_length = 255,
    )

    def __unicode__(self):
        return self.condition


class App(models.Model):
    title = models.CharField(
        verbose_name = _(u'App Name'), 
        max_length = 255
    )
    slug = models.SlugField(
        max_length = 50,
        unique = True
    )
    activated = models.BooleanField(
        verbose_name = _(u'Activated'),
        default = False,
    )
    options = models.ManyToManyField(
        Option,
        through="AppOption"
    )

    def __unicode__(self):
        return self.title


class AppOption(models.Model):
    app = models.ForeignKey(
        App,
        verbose_name = _(u'App'), 
    )
    option = models.ForeignKey(
        Option,
        verbose_name = _(u'Option'), 
    )
    condition_activated = models.BooleanField(
        verbose_name = _(u'Condition Activated'),
        default = False,
    )
    option_activated = models.BooleanField(
        verbose_name = _(u'Option Activated'),
        default = False,
    )

    class Meta:
        unique_together = (("app", "option"),)

    def __unicode__(self):
        return "%s %s (%s | %s | %s)" % (self.app, self.option, self.app.activated, self.option_activated, self.condition_activated)

во-вторых, вы должны использовать модельные формы и формы моделей с пользовательскими логиками внутри...

формы

from django.forms.models import modelformset_factory
from django import forms

class AppOptionForm(forms.ModelForm):
    class Meta:
        model = AppOption
        fields = ("app", "option", "condition_activated", "option_activated")

AppOptionFormSet = modelformset_factory(AppOption, form=AppOptionForm)

class AppForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super(AppForm, self).__init__(*args, **kwargs)

        if self.instance:
            self.appoptions_prefix = "appoptions-%s"%self.instance.pk
            self.appoptions_formset = AppOptionFormSet(prefix=self.appoptions_prefix, 
                queryset=AppOption.objects.filter(app=self.instance).order_by('option'))

    class Meta:
        model = App
        fields = ("id", "activated",)

AppFormSet = modelformset_factory(App, form=AppForm)

Хорошо, так что только что произошло, мы создали модельную модель для AppOption, а затем превратили ее в модельный набор.

Затем мы создали модельную модель для App, которая имеет переопределенный метод init, который создает экземпляр формы приложения AppOption для экземпляра формы модели App.

Наконец, мы создали модельную форму, используя модель модели App.

Это представление, которое сохраняет все приложения и приложения

def one(request):
    if request.method == 'POST':
        formset = AppFormSet(request.POST, prefix="apps") # do some magic to ALSO apply POST to inner formsets
        if formset.is_valid(): # do some magic to ALSO validate inner formsets
            for form in formset.forms:
                # saved App Instances
                form.save()
                for innerform in form.appoptions_formset:
                    # saved AppOption instances
                    innerform.save()
    else:
        formset = AppFormSet(prefix="apps")

    options = Option.objects.all()

    return render(
        request,
        "playground/example/one.html",
        {
            'formset' : formset,
            'options' : options,
        }
    )

шаблон

this is a test
<style>
thead td {
    width: 50px;
    height: 100px;
}
.vertical {
    -webkit-transform: rotate(-90deg);
    -moz-transform: rotate(-90deg);
    -ms-transform: rotate(-90deg);
    -o-transform: rotate(-90deg);
    filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=3);
}
</style>
<form>
<table>
<thead>
    <tr>
        <td>&nbsp;</td>
        <td><p class="vertical">Activate App</p></td>
        {% for option in options %}
        <td><p class="vertical">{{ option.condition }}</p></td>
        <td><p class="vertical">{{ option.option }}</p></td>
        {% endfor %}
    </tr>
</thead>
{% for form in formset.forms %}
    {% if form.instance.pk %}
    <tr>
        <td align="center">{{ form.instance.title }}{{ form.id.as_hidden }}</td>
        <td align="center">{{ form.activated }}</td>
        {% for optionform in form.appoptions_formset.forms %}
        {% if optionform.instance.pk %}
        <td align="center">
            {{ optionform.app.as_hidden }}
            {{ optionform.app.as_hidden }}
            {{ optionform.condition_activated }}
        </td>
        <td align="center">{{ optionform.option_activated }}</td>
        {% endif %}
        {% endfor %}
    </tr>
    {% endif %}
{% endfor %}
</table>
</form>

Ответ 3

Для тех, кто пришел сюда, чтобы визуализировать CheckBoxMultipleSelect вручную, но стандартным способом (как это делает Django, используя списки HTML), следующее: я придумал (решение @ниже-радара помогло мне это достичь)

<ul id="id_{{field.name}}">
  {% for pk, choice in field.field.widget.choices %}
    <li>
      <label for="id_{{field.name}}_{{ forloop.counter0 }}">
      <input id="id_{{field.name}}_{{ forloop.counter0 }}" name="{{field.name}}" type="checkbox" value="{{pk}}" />
      {{ choice }}
      </label>
    </li>
  {% endfor %}
</ul>