Select2 与 Django 不接受选择
Posted
技术标签:
【中文标题】Select2 与 Django 不接受选择【英文标题】:Select2 with Django not accepting selections 【发布时间】:2021-08-03 22:52:17 【问题描述】:我已经在这个问题上工作了几天了,但我很困惑。尝试在不使用 django-select2 应用程序的情况下集成 Select2.js。 我的模型:
from django.contrib.auth import get_user_model
from django.db import models
import datetime as dt
from WHST.settings import PROCESS_LEVELS
class CEID(models.Model):
process = models.CharField(max_length=4,
choices=PROCESS_LEVELS)
ceid = models.CharField(max_length=6)
representative = models.ManyToManyField(get_user_model(), blank=True)
functional_area = models.CharField(max_length=200)
score = models.IntegerField(null=True, blank=True)
ceid_is_production = models.BooleanField(default=True)
ceid_is_front_end = models.BooleanField(default=True)
ceid_is_hidden = models.BooleanField(default=False)
ceid_pdl = models.ManyToManyField('PDL', blank=True)
user_edited = models.BooleanField(default=False)
def __str__(self):
return str(self.process) + ' ' + str(self.ceid) if self.ceid else ''
def __unicode__(self):
return str(self.process) + ' ' + str(self.ceid) if self.ceid else ''
class Meta:
ordering = ('process', 'ceid', 'process',)
def calculate_ceid_score(self):
entities = Entity.objects.filter(
ceid__id=self.id).filter(production=True)
score = 0
for entity in entities:
score += entity.score if entity.score else 0
self.score = score / len(entities) if len(entities) > 0 else 0
self.save()
return
我的看法:
from datetime import datetime, timedelta
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
from django.db.models import Sum, Q
from django.http import JsonResponse, HttpResponseRedirect
from django.shortcuts import render
from django.urls import reverse
from django.views import View
from django.views.generic import ListView, TemplateView, FormView, UpdateView
from django_filters.views import FilterView
from django.contrib.auth import get_user_model
from dal import autocomplete
from pages.filter import CeidFilter, PmRunInformationFilter, HomePageFilter
from pages.forms import PDLAddForm, PagesAdminSetCeidUserAssociationForm, AreaAutofillSearchForm
from tools.models import CEID, Entity, WaferHandlingType, PmRunInformation, ToolPm
class PagesAdminSetCeidUserAssociation(LoginRequiredMixin, View, UserPassesTestMixin):
template_name = 'pages/pages_admin_set_ceid_user_association.html'
login_url = '/login/'
def test_func(self):
return self.request.user.is_superuser
def get(self, request):
form = PagesAdminSetCeidUserAssociationForm()
if request.is_ajax():
if request.GET.get('dat_type') == 'representatives':
representatives = get_user_model().objects.filter(
username__icontains=request.GET.get('term')
)
representative_response_content = list(
representatives.values())
return JsonResponse(representative_response_content, safe=False)
elif request.GET.get('dat_type') == 'ceids':
ceids = CEID.objects.filter(
ceid__icontains=request.GET.get('term')
)
ceid_response_content = list(ceids.values())
return JsonResponse(ceid_response_content, safe=False)
return render(request, self.template_name, 'form': form)
def post(self, request):
form = PagesAdminSetCeidUserAssociationForm(request.POST or None)
if form.is_valid():
print(form)
pass
# form.save()
return HttpResponseRedirect(reverse('pages_home_page'))
return render(request, self.template_name, 'form': form)
我的表格:
from django import forms
from tools.models import PDL, CEID
from django.contrib.auth import get_user_model
from django.conf import settings
class PagesAdminSetCeidUserAssociationForm(forms.ModelForm):
representative = forms.MultipleChoiceField(label='WHST Representative')
ceid = forms.MultipleChoiceField(label='CEID')
class Meta:
model = CEID
fields = ['representative', 'ceid']
def __init__(self, *args, **kwargs):
super(PagesAdminSetCeidUserAssociationForm, self).__init__(*args, **kwargs)
# self.fields['representative'].queryset = get_user_model().objects.none()
# self.fields['ceid'].queryset = CEID.objects.none()
for field in self.fields:
self.fields[field].widget.attrs = 'class': 'form-control'
if 'ceid' in self.data:
ceid = self.data.get('ceid')
self.fields['ceid'].queryset = CEID.objects.filter(ceid__in=ceid).order_by()
if 'representative' in self.data:
rep = self.data.get('representative')
self.fields['representative'].queryset = get_user_model().objects.filter(username__in=rep)
最后,我的模板:
% extends 'base.html' % % load crispy_forms_tags %
% block title %User CEID Association% endblock %
% block content %
<form novalidate method="post" action="% url 'pages_admin_set_ceid_user_association' %" >
% csrf_token % form|crispy
<input type="submit" class="btn btn-success" value="Update" /><a
href="% url 'pages_home_page' %"
><button type="button" class="btn btn-primary">Go Back</button></a
>
</form>
<script>
$('#id_representative').select2(
ajax:
url: '% url 'pages_admin_set_ceid_user_association' %',
dataType: 'json',
data: function(params)
return
q: params.term,
term: params.term,
_type: params._type,
dat_type: 'representatives'
,
processResults: function(data)
return
results: $.map(data, function(item)
return id: item.id, text: item.username + ' (' + item.first_name + ' ' + item.last_name + ')';
)
;
,
minimumInputLength: 3
);
$('#id_ceid').select2(
ajax:
url: '% url 'pages_admin_set_ceid_user_association' %',
dataType: 'json',
data: function(params)
return
q: params.term,
term: params.term,
_type: params._type,
dat_type: 'ceids'
,
processResults: function(data)
return
results: $.map(data, function(item)
console.log(item)
return id: item.id, text: item.process + ' ' + item.ceid;
)
;
,
minimumInputLength: 3
);
</script>
% endblock content %
当我尝试提交时,这是我得到的错误:
枚举是:
PROCESS_LEVELS = [('1270', '1270'), ('1272', '1272'), ('1274', '1274'), ('1222', '1222')]
我尝试为我的 forms.MultipleChoiceField 设置选项,但这并不能解决问题。我尝试将字段切换到 CharField 和 ChoiceField,但这也没有解决问题。我也尝试在表单中删除和添加 novalidate ,但这没有任何作用。任何帮助将不胜感激!
【问题讨论】:
你能像 PROCESS_LEVELS 一样分享你的枚举吗? 用枚举和导入更新了代码——忘了把它们放在第一个循环中。谢谢。 【参考方案1】:想出了解决问题的方法: 在我的表单中,我创建了一个自定义多项选择字段:
class CustomMultipleChoiceField(forms.MultipleChoiceField):
"""This field is a MultipleChoiceField designed to override the validation method of a default MultipleChoiceField
"""
def validate(self, value):
return value
绕过了常规的表单验证程序。然后我将该自定义字段设置为表单中的字段,并将其从 ModelForm 转换为常规表单:
class PagesAdminSetCeidUserAssociationForm(forms.Form):
representative = CustomMultipleChoiceField(label='WHST Representative')
ceid = CustomMultipleChoiceField(label='CEID')
class Meta:
model = CEID
fields = ['representative', 'ceid']
def __init__(self, *args, **kwargs):
super(PagesAdminSetCeidUserAssociationForm,
self).__init__(*args, **kwargs)
# self.fields['representative'].queryset = get_user_model().objects.none()
# self.fields['ceid'].queryset = CEID.objects.none()
for field in self.fields:
self.fields[field].widget.attrs = 'class': 'form-control'
if 'ceid' in self.data:
ceid = self.data.get('ceid')
self.fields['ceid'].queryset = CEID.objects.filter(
ceid__in=ceid).order_by()
if 'representative' in self.data:
rep = self.data.get('representative')
self.fields['representative'].queryset = get_user_model(
).objects.filter(username__in=rep)
之后,编写我的发布请求以按每个输入的 ID 进行过滤是一件简单的事情:
class PagesAdminSetCeidUserAssociation(LoginRequiredMixin, View, UserPassesTestMixin):
template_name = 'pages/pages_admin_set_ceid_user_association.html'
login_url = '/login/'
def test_func(self):
return self.request.user.is_superuser
def get(self, request):
form = PagesAdminSetCeidUserAssociationForm()
if request.is_ajax():
if request.GET.get('dat_type') == 'representatives':
representatives = get_user_model().objects.filter(
username__icontains=request.GET.get('term')
)
representative_response_content = list(
representatives.values())
return JsonResponse(representative_response_content, safe=False)
elif request.GET.get('dat_type') == 'ceids':
ceids = CEID.objects.filter(
ceid__icontains=request.GET.get('term')
)
ceid_response_content = list(ceids.values())
return JsonResponse(ceid_response_content, safe=False)
elif request.GET.get('dat_type') == 'user-ceid-association-container':
representative = get_user_model().objects.get(id=request.GET.get('term[]'))
ceids = list(CEID.objects.filter(representative=representative))
print(ceids)
ceid_name_list = []
for ceid in ceids:
ceid_name_list.append(ceid.__str__())
print(ceid_name_list)
response =
'representative': representative.username + ' ( ' + representative.first_name + ' ' + representative.last_name + ' )',
'ceids': ceid_name_list,
return JsonResponse(response, safe=False)
return render(request, self.template_name, 'form': form)
def post(self, request):
form = PagesAdminSetCeidUserAssociationForm(request.POST or None)
if form.is_valid():
for ceid in CEID.objects.filter(id__in=form.cleaned_data['ceid']):
ceid.representative.set(get_user_model().objects.filter(id__in=form.cleaned_data['representative']))
return render(request, self.template_name, 'form': form)
还有我的html代码:
% extends 'base.html' % % load crispy_forms_tags % % block title %User
CEID Association% endblock % % block content %
<h3>Please note, submitting associate will reset assignment of CEIDs</h3>
<form method="post" action="% url 'pages_admin_set_ceid_user_association' %">
% csrf_token % form|crispy
<input type="submit" class="btn btn-success" value="Update" /><a
href="% url 'pages_home_page' %"
><button type="button" class="btn btn-primary">Go Back</button></a
>
</form>
<div
id="user-ceid-association-container"
class="container"
style="display: none"
>
<div class="card mb-4 shadow-sm">
<div class="card-body">
<h6 class="card-text" id="User"></h6>
<ul class="card-text" id="ceids"></ul>
</div>
</div>
</div>
<script>
$('#id_representative').select2(
ajax:
url: '% url 'pages_admin_set_ceid_user_association' %',
dataType: 'json',
data: function(params)
return
q: params.term,
term: params.term,
_type: params._type,
dat_type: 'representatives'
,
processResults: function(data)
return
results: $.map(data, function(item)
return id: item.id, text: item.username + ' (' + item.first_name + ' ' + item.last_name + ')';
)
;
,
minimumInputLength: 3
);
$('#id_representative').change(function ()
let representative_value = $(this).val();
$.ajax(
url: '% url 'pages_admin_set_ceid_user_association' %',
data:
'term': representative_value,
'dat_type': 'user-ceid-association-container',
,
success: function(result)
$('#user-ceid-association-container').css('display', 'block');
$('#User').text(result.representative);
$('#ceids').empty();
if (result.ceids.length > 0)
for(let i=0; i < result.ceids.length; i++)
$('#ceids').append('<li class="card-text">' + result.ceids[i] + '</li>');
else
$('#ceids').append('<li class="card-text">This user has no CEIDs associated to them</li>');
return
,
);
);
$('#id_ceid').select2(
ajax:
url: '% url 'pages_admin_set_ceid_user_association' %',
dataType: 'json',
data: function(params)
return
q: params.term,
term: params.term,
_type: params._type,
dat_type: 'ceids'
,
processResults: function(data)
return
results: $.map(data, function(item)
console.log(item)
return id: item.id, text: item.process + ' ' + item.ceid;
)
;
,
minimumInputLength: 3
);
</script>
% endblock content %
这似乎已经做到了!
【讨论】:
以上是关于Select2 与 Django 不接受选择的主要内容,如果未能解决你的问题,请参考以下文章
Select2 4.0 和 Knockout 3.1 选择不允许选择