I'm trying to incorporate Select2 into my django form -- specifically ModelSelect2MultipleWidget -- so that the user can associate multiple event objects to another model (like CheckboxSelectMultiple). The associated models are:
from django.contrib.auth import get_user_model
from django.db import models
class F4Events(models.Model):
name = models.CharField(max_length=300)
handling_type = models.ManyToManyField(WaferHandlingType)
def __str__(self):
return self.name
class ToolPm(models.Model):
ceid = models.ForeignKey(CEID, on_delete=models.CASCADE)
name = models.CharField(max_length=250)
wafer_handling = models.BooleanField(default=True)
wafer_based = models.BooleanField(default=False)
frequency = models.FloatField(blank=True, null=True)
handling_type = models.ManyToManyField(WaferHandlingType, blank=True)
user_edited = models.BooleanField(default=False)
pm_f4_events = models.ManyToManyField('F4Events', blank=True)
def __str__(self):
return str(self.name) if self.name else ''
class Meta:
ordering = ('ceid', 'name')
My forms.py file is:
from django import forms
from .models import Entity, ToolPm, CEID, PDL, F4Events, WaferHandlingType
from django_select2 import forms as s2forms
class F4EventWidget(s2forms.ModelSelect2MultipleWidget):
search_fields = [
'name__icontains',
]
attrs = {'data-placeholder': 'Please Choose F4 Events'}
class PMForm(forms.ModelForm):
class Meta:
model = ToolPm
fields = ['wafer_handling', 'wafer_based', 'handling_type', 'pm_f4_events']
widgets = {'handling_type': forms.CheckboxSelectMultiple,
'pm_f4_events': F4EventWidget
}
my view.py is:
from datetime import datetime, timedelta
from django.db.models import Sum
from django.http import JsonResponse, HttpResponseRedirect
from django.http.response import HttpResponse
from django.shortcuts import render, get_object_or_404, redirect
from django.views import View
from django.views.generic import ListView
from django_filters.views import FilterView
from pages.filter import CeidFilter, PmRunDateFilter
from tools.forms import EntityForm, PMForm, CEIDForm, PDLAddForm
from tools.models import CEID, Entity, F4Events, ToolPm, WaferHandlingType, PmRunDate
from django.urls import reverse
class UserCeidPMUpdate(View):
template_name = 'tools/update_pm_attributes.html'
def get(self, request, username, pk, pm_id):
pm = ToolPm.objects.get(pk=pm_id)
form = PMForm(request.GET or None, instance=pm)
return render(request, self.template_name, {'form': form, 'pm': pm, })
def post(self, request, username, pk, pm_id):
pm = ToolPm.objects.get(pk=pm_id)
pm.user_edited = True
pm.save()
form = PMForm(request.POST or None, instance=pm)
if form.is_valid():
form.save()
return HttpResponseRedirect(reverse('pm_view', kwargs={'username': username, 'pk': pm.ceid.id}))
return render(request, self.template_name, {'form': form, 'pm': pm, })
lastly, my .html file is:
{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% block content %}
<form method="post">
<p>Process: {{ pm.ceid.process }}</p>
<p>CEID: {{ pm.ceid.ceid }}</p>
<p>Name: {{ pm.name }}</p>
<p>Frequency: {{ pm.frequency }}{% if pm.wafer_based %} wafers {% else %} days {% endif %}</p>
<p>Score: {{ pm.score }}</p>
{% csrf_token %}
{{ form }}
<input type="submit" class="btn btn-success" value="Update PM"><a href="{% url 'pm_view' user.username pm.ceid.id %}"><button type="button" class="btn btn-primary">Go Back</button></a>
</form>
{% endblock content %}
If I switch the pm_f4_events
widget to a CheckboxSelectMultiple
or a ModelSelect2Widget
, the code works.
However, when I try to use a ModelSelect2MultipleWidget
, the form continually tries to load but cannot and eventually just times out.
There are ~5000 items within the F4Events
model, so that may have something to do with it. Any help to point me in the right direction would be greatly appreciated!
You can empty the pm_f4_events
field's choices in the __init__
method:
class PMForm(forms.ModelForm):
class Meta:
model = ToolPm
fields = ['wafer_handling', 'wafer_based', 'handling_type', 'pm_f4_events']
widgets = {
'handling_type': forms.CheckboxSelectMultiple,
'pm_f4_events': s2forms.ModelSelect2MultipleWidget(
model=F4Events,
search_fields=["name__icontains",],
attrs = {'data-placeholder': 'Please Choose F4 Events'}
)
}
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
choices_F4Events = []
pm_f4_events_field = self.fields["pm_f4_events"]
# selected values
selected_F4Events = self.data.getlist("pm_f4_events") or self.initial.get("pm_f4_events")
if selected_F4Events:
# check of selected values not object
if not isinstance(selected_F4Events[0], F4Events):
selected_F4Events = pm_f4_events_field.queryset.filter(pk__in=selected_F4Events)
choices_F4Events = [(item.pk, item.name) for item in selected_F4Events]
# assign selected values or empty list
pm_f4_events_field.choices = choices_F4Events
Has been tested on my server, works well.