在Django中自定义验证ModelForm

问题描述 投票:0回答:1

我正在开发一个Django应用程序来注册销售。我创建了三个模型:项目,员工和销售。

项目和员工模型如下:

class Project(models.Model):
    project_id = models.IntegerField(primary_key = True)
    name = models.CharField(max_length = 100, unique = True)

    class Meta:
        ordering = ['name']

    def __str__(self):
        return self.name

class Employee(models.Model):
    employee_id = models.IntegerField(primary_key = True)
    name = models.CharField(max_length = 50)
    email = models.CharField(max_length = 40)

class Meta:
    ordering = ['name']

def __str__(self):
    return self.name

然后销售模型:

class Sale(models.Model):
    sale_name = models.CharField(max_length = 30)
    project = models.ForeignKey('Project', on_delete = models.CASCADE)

    proactive_seller = models.ManyToManyField(Employee, related_name = 'proactive')

    participants = models.ManyToManyField(Employee, related_name = 'participant')

    doers = models.ManyToManyField(Employee, related_name = 'doer')

    start_date = models.DateField()
    end_date = models.DateField()

    def __str__(self):
        return self.sale_name

因此,每个销售对象包含有关销售与哪个项目相关的信息,哪个员工是主动/主要卖家,哪些员工参与销售,以及哪些员工将执行实际项目。

在我的forms.py中,我想确保销售是唯一的,因为如果用户试图进入已经拥有相同项目,相同日期和相同实施者的销售,即我想提出错误,即实施者不能一次多次分配给项目。

我的forms.py目前看起来像这样:

class SaleForm(ModelForm):
    class Meta:
        model = Sale
        widgets = {
        'start_date': DatePickerInput(), 
        'end_date': DatePickerInput(), 
    }

我尝试了以下方法:

    def clean(self):
        cleaned_data = super.clean()
        start = cleaned_data.get('start_date')
        end = cleaned_data.get('end_date')
        doers = cleaned_data.get('doers')
        project = cleaned_data.get('project')
        if start and end and doers and project:
            queryset = Sale.objects.all()
            # Filter based on project
            q = queryset.filter(project__name=project, start_date = start, end_date = end)
            for employee in doers:
                q = q.filter(doers__name=employee)
            if q.count() > 1:
                raise forms.ValidationError('Sale has already been registered.')

但是,验证不能按预期工作:我仍然可以同时将“员工”分配到同一个“项目”(即开始日期和结束日期)。

非常感谢帮助。

django django-models django-forms
1个回答
0
投票

您要做的是验证给定实例的M2M关系的每个实例。这可能相当困难。什么应该足以用相同数量的实施者过滤销售,并筛选出包含不同实施者的销售。

from django.db.models import F, OuterRef, Exists, Q

q = queryset.filter(project__name=project, start_date=start, end_date = end)
other_doers = Employee.objects.filter(
     # Exclude any employee with the name of the doers on this project.
     # We only want other doers.
     ~Q(name__in=[e.name for e in doers]),
     # This links the subquery to the main query (Sale)
     doer=OuterRef('id'),
)
q = q.annotate(
    # Get the count of doers per sale
    doer_count=Count('doers__id', distinct=True),
    # Check if other doers are in the project
    has_other_doer=Exists(other_doers)
).filter(
    # Only look for sales with the same number of doers
    doer_count=len(doers),
    # Filter out sales that contain other doers
    has_other_doer=False,
)
© www.soinside.com 2019 - 2024. All rights reserved.