【问题标题】:How to set default value for a ManyToManyField in Django如何在 Django 中为 ManyToManyField 设置默认值
【发布时间】:2021-01-22 12:32:48
【问题描述】:

编辑-更新的models.py models.py:

from django.db import models
from django.db.models.signals import post_save
from django.dispatch import receiver

class Department(models.Model):
    departmentName = models.CharField(max_length=100)

    def __str__(self):
        return self.departmentName

class Designation(models.Model):
    designationName = models.CharField(max_length=100, null=True)

    def __str__(self):
        return self.designationName
 
class Employee(models.Model):
    name = models.CharField(max_length=100)
    email = models.EmailField(unique=True, blank=False)
    department = models.ManyToManyField(Department, blank=True)
    designation = models.ForeignKey(Designation, null=True, on_delete=models.SET_NULL)

    def __str__(self):
        return self.name
    
    def departments(self):
        return ",".join([d.departmentName for d in self.department.all()])

#Using post receiver signal as suggested by @Daniel in answer and comments

@receiver(post_save, sender=Employee, dispatch_uid='set_department')
def SetDefaultDeparment(**kwargs):

    employee = kwargs['instance']
       
    if not employee.department.all(): 

        resource_pool = Department.objects.get(departmentName="RP")

        employee.department.add(resource_pool)
        employee.save()
                 

我的查询/要求: 员工和部门通过 M2M 链接。我设置 blank=True 来克服没有选择部门的表单验证。 (null=True 似乎不适用于 M2M)

比方说,

场景一:在新建 Emp 时,如果没有提供部门,则默认设置为 RP(Resource pool)。

场景 2: 现有 Emp 来自 HR 部门;假设由于某种原因 HR 部门被删除或 Emp 被踢出,现在 Emp 没有与之关联的部门,它应该默认移动到 RP(资源池)!

如何在 Django 中安排默认的部门-RP 以使两个场景都通过!?

提前致谢:)

应酬

【问题讨论】:

    标签: python django django-models default-value manytomanyfield


    【解决方案1】:

    正如此处The right way to set the default value of a ManyToMany field in django 所建议的那样,您有几个选择。

    下面是如何通过覆盖保存方法来做到这一点:

    class Employee(models.Model):
    
        ...
        
        def save(self): 
    
            # set department if field is empty:        
            if not self.department.all(): 
    
                # get the resource pool department:
                resource_pool = Department.objects.get(name='Resource Pool')
    
                # add to instance:
                self.department.add(resource_pool)
            
            super(Employee, self).save(*args, **kwargs)
    

    以下是使用 post_save 接收器的方法:

    from django.db.models.signals import post_save
    from django.dispatch import receiver
    
    # this decorator will execute the function after an Employee is saved:
    @receiver(post_save, sender=Employee, dispatch_uid='set_department')
    def SetDefaultDeparment(**kwargs):
        
        ''' sets a default department for an Employee where needed '''
        
        # unpack kwargs:
        employee = kwargs['instance']
    
        # set department if field is empty:        
        if not employee.department.all(): 
    
             # get the resource pool department:
             resource_pool = Department.objects.get(name='Resource Pool')
    
             # add to instance:
             employee.department.add(resource_pool)
             employee.save()
    

    【讨论】:

    • 异常值:“”需要字段“id”的值才能使用这种多对多关系。
    • 伟大的捕获 - 这发生在新员工身上,因为 id 仅在保存新员工实例之后创建(而不是之前,因此错误)。在这种情况下(以及所有情况),我们可以使用 post_save 接收器添加默认部门 - 请参阅我更新的答案。
    • 嘿@Daniel,我尝试了更新。现在也不例外,但不幸的是,该部门仍然没有被添加! (因为没有创建新的 M2M 关系)在调试时发现这个-'Manager 不能通过 Employee 实例访问'。在 save() 之前添加了这一行 - print(employee.department),它打印 employee_app.Department.None
    • 你能分享你编辑的代码吗?你在使用 post save 接收器吗?
    • 对于没有任何部门的员工,它应该作为一个空查询集出现并像False一样工作 - 对于至少有一个部门的员工,它不应该是一个空查询集并且像True一样工作
    猜你喜欢
    • 2012-05-02
    • 1970-01-01
    • 1970-01-01
    • 2014-03-27
    • 2016-05-04
    • 2012-11-18
    • 1970-01-01
    • 1970-01-01
    • 2021-09-21
    相关资源
    最近更新 更多