使用Django提供可用选项时,如何要求从属下拉菜单?

时间:2019-12-04 15:48:42

标签: python django

我是Django / Python的新手,所以提前致歉。我有一个带有依赖项下拉列表的表格。目前,我已对其进行设置,以便仅在其中有可用选项时才显示第二个下拉菜单,否则将被隐藏。我遇到的麻烦是,每当您选择具有次要(Station)下拉菜单的主要(工作区)选项时,都可以提交表单,而无需从从属(次要)下拉列表中选择选项,只要其中有选项,就应该有此要求。

我该如何修改它,以便无论何时出现依赖下拉列表都是必需的?

models.py

class WorkArea(models.Model):
    name = models.CharField(max_length=50)

    def __str__(self):
        return self.name


class Station(models.Model):
    work_area = models.ForeignKey(WorkArea, on_delete=models.CASCADE, related_name="stations")
    name = models.CharField(max_length=50)

    def __str__(self):
        return self.name


class EmployeeWorkAreaLog(TimeStampedModel, SoftDeleteModel, models.Model):
    employee_number = models.ForeignKey(Salesman, on_delete=models.SET_NULL, help_text="Employee #", null=True, blank=False)
    work_area = models.ForeignKey(WorkArea, on_delete=models.SET_NULL, null=True, blank=False, help_text="Work Area", related_name="work_area")
    station_number = models.ForeignKey(Station, on_delete=models.SET_NULL, null=True, help_text="Station", related_name="stations", blank=True)

forms.py

class WarehouseForm(AppsModelForm):
    class Meta:
        model = EmployeeWorkAreaLog
        widgets = {
            'employee_number': ForeignKeyRawIdWidget(EmployeeWorkAreaLog._meta.get_field('employee_number').remote_field, site, attrs={'id':'employee_number_field'}),
        }
        fields = ('employee_number', 'work_area', 'station_number')


    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['station_number'].queryset = Station.objects.none()

        if 'work_area' in self.data:
            try:
                work_area_id = int(self.data.get('work_area'))
                self.fields['station_number'].queryset = Station.objects.filter(work_area_id=work_area_id).order_by('name')
            except (ValueError, TypeError):
                pass
        elif self.instance.pk:
            self.fields['station_number'].queryset = self.instance.work_area.stations.order_by('name')

views.py

def enter_exit_area(request):
    enter_without_exit = None
    exit_without_enter = None

    if request.method == 'POST':
        # Form handling...

def load_stations(request):
    work_area_id = request.GET.get('work_area')
    stations = Station.objects.filter(work_area_id=work_area_id).order_by('name')
    return render(request, 'operations/station_number_dropdown_options.html', {'stations': stations})

urls.py

urlpatterns = [
    url(r'enter-exit-area/$', views.enter_exit_area, name='enter_exit_area'),

    path('ajax/load-stations/', views.load_stations, name='ajax_load_stations'),
]

station_number_dropdown_options.html

<option value="">---------</option>
{% for station in stations %}
<option value="{{ station.pk }}">{{ station.name }}</option>
{% endfor %}

我尝试将其添加到forms.py

    def clean(self):
        work_area = self.cleaned_data['work_area']
        station = self.cleaned_data['station_number']

        if work_area in ('3', '4', '5', '6', '1') and station is None:
            raise forms.ValidationError("You must select a station")
        return work_area

但是我明白了 AttributeError: 'WorkArea' object has no attribute 'get'

如何解决此错误?还是有更好的方法来解决这个问题?

1 个答案:

答案 0 :(得分:1)

尝试使用干净的方法

def clean(self):
    cleaned_data = super().clean()
    work_area = cleaned_data['work_area']
    station = cleaned_data['station_number']
    if work_area in ('3', '4', '5', '6', '1') and station is None:
        text = f'You must select a station for work area {work_area}!'
        self.add_error('station_number', text)

在主要的clean方法中,您不应返回任何内容。 通常,当您需要依赖多个值时,应该使用通用的clean方法。如果您需要清除单个值,则应使用类似以下内容的

def clean_work_area(self):
    work_area = self.cleaned_data['work_area']
    if [condition]:
        raise ValidationError(
            _('%(area)s failed condition!'),
            params={'area': work_area},
        )
    return work_area

在这种情况下,您应该始终返回要清除的值。