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 选择不允许选择

实现select2与jqGrid联动动态重新加载数据

实现select2与jqGrid联动动态重新加载数据

Select2:如何允许用户从默认列表中选择但接受新字符串?

模板结果和模板选择的Select2参数不同(django)

python 多选择器django select2