Django - Форма с ModelMultipleChoiceField, как сгруппировать варианты выбора на основе их родительской модели? - PullRequest
0 голосов
/ 21 января 2019

Чего я хочу добиться, это:

Examples of how choices should be categorised

Category1
    Choice1
    Choice2
    Choice3
Category2
    Choice1
    Choice2
Category3
    Choice1
    Choice2
    Choice3

и т.д..

Я использую пользовательский ModelMultipleChoiceField. Проблема в моем шаблоне я не могу представить их в своих категориях. Вместо этого все они генерируются друг под другом.

my forms.py:

class CustomAmenitiesSelectMultiple(CheckboxSelectMultiple):
    """
    CheckboxSelectMultiple Parent: https://docs.djangoproject.com/en/2.1/_modules/django/forms/widgets/#CheckboxSelectMultiple
    checkbox_select.html: https://github.com/django/django/blob/master/django/forms/templates/django/forms/widgets/checkbox_select.html
    multiple_input.html: https://github.com/django/django/blob/master/django/forms/templates/django/forms/widgets/multiple_input.html
    checkbox_option.html: https://github.com/django/django/blob/master/django/forms/templates/django/forms/widgets/checkbox_option.html
    input_option.html: https://github.com/django/django/blob/master/django/forms/templates/django/forms/widgets/input_option.html

    """
    template_name = "forms/widgets/custom_checkbox_select.html"
    option_template_name = 'forms/widgets/custom_checkbox_option.html'


class AmenitiesForm(ModelForm):
    class Meta:
        model = Venue
        fields = ('choices',)

    choices = forms.ModelMultipleChoiceField(Amenity.objects.all(), widget=CustomAmenitiesSelectMultiple,)

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        if kwargs.get('instance'):
            initial = kwargs.setdefault('initial', {})
            initial['choices'] = [c.pk for c in kwargs['instance'].amenity_set.all()]

        forms.ModelForm.__init__(self, *args, **kwargs)

    def save(self, commit=True):
        instance = forms.ModelForm.save(self)
        instance.amenity_set.clear()
        instance.amenity_set.add(*self.cleaned_data['choices'])
        return instance

custom_checkbox_option.html:

{% if widget.wrap_label %}
<label{% if widget.attrs.id %} for="{{ widget.attrs.id }}"{% endif %}>{% endif %}{% include "django/forms/widgets/input.html" %}{% if widget.wrap_label %} {{ widget.label }}</label>
{% endif %}

custom_checkbox_select.html

{% with id=widget.attrs.id %}
<div class="inline field">
    <div {% if id %} id="{{ id }}" {% endif %}{% if widget.attrs.class %} class="{{ widget.attrs.class }}" {% endif %}>
        {% for group, options, index in widget.optgroups %}{% if group %}
        <div>
            {{ group }}
            <div>
                {% if id %} id="{{ id }}_{{ index }}" {% endif %}>{% endif %}{% for option in options %}
                <div class="checkbox">{% include option.template_name with widget=option %}</div>
                {% endfor %}{% if group %}
            </div>

        </div>
        {% endif %}{% endfor %}
    </div>
</div>

{% endwith %}

my models.py:

class AmenitiesCategory(TimeStampedModel):

    category = models.CharField(max_length=250)
    description = models.TextField()

    def __str__(self):
        return self.category


class Amenity(TimeStampedModel):
    category = models.ForeignKey(AmenitiesCategory, on_delete=models.CASCADE)
    venues = models.ManyToManyField(Venue, blank=True)
    space = models.ManyToManyField(Space, blank=True)
    name = models.CharField(max_length=250)
    description = models.TextField()

    def __str__(self):
        return self.name

    class Meta:
        ordering = ['category']

class Venue(TimeStampedModel):
    """
    Main Venue Model
    ################
    PhoneNumberField() is based on a 3rd-party-app called: Django-Phonenumber-Field
    """
    owner = models.ForeignKey(User, on_delete=models.CASCADE)
    name = models.CharField(max_length=250)
    type = models.ForeignKey(VenueType, on_delete=models.CASCADE)
    total_capacity = models.PositiveIntegerField(default=0)
    description = models.TextField(blank=False)
    contact_number = PhoneNumberField(blank=True)
    contact_email = models.EmailField(blank=True)
    published = models.BooleanField(default=False)

    def __str__(self):
        return self.name

В пользовательском шаблоне custom_checkbox_select.html я вижу весь цикл, используемый django для генерации выбора. Я также вижу {{group}} и widget.optgroups (я понятия не имею, откуда они берутся? Я также не смог найти другой ответ, который объясняет это), которые могут помочь решить эту проблему.

...