【问题标题】:how to update an object when several other related objects get created创建其他几个相关对象时如何更新对象
【发布时间】:2022-01-24 15:10:28
【问题描述】:

我必须在我的用户模型中添加一个 progress_level 字段,以显示该用户目前所处的位置,因此我向用户模型添加了一个字段,如下所示:

progress_level = models.CharField(max_length=25, null=True, choices=USER_PROGRESS_LEVELS)

我希望该字段在用户完成操作时自动更新。例如,如果用户完成了他们的联系信息和文档信息并提交了他们的表单,则进度级别应该更改为 [1][0]。我真的不知道该怎么做,但我创建了一个这样的信号:

@receiver(pre_save, sender=User, dispatch_uid='progress_change')
def progress(sender, instance, **kwargs):
    user = instance
    if DocumentInfo.objects.filter(user=user).exists() and ContactInfo.objects.filter(user=user).exists():
        user.progress_level = USER_PROGRESS_LEVELS[1][0]

它工作正常,但只有在我保存用户模型时才会激活。我该如何防止呢?每当该陈述为真时,我如何激活此信号?如果有更好的方法来做到这一点,请帮助我。我真的不知道信号是否是正确的方法。 这些是我的模型:

class User(AbstractUser):
    id = models.AutoField(primary_key=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    isPreRegistered = models.BooleanField(default=False)
    username = models.CharField(unique=True, max_length=13)
    first_name = models.CharField(max_length=32, null=True, default=None)
    last_name = models.CharField(max_length=64, null=True, default=None)
    gender = models.CharField(max_length=10, null=True, choices=GENDER)
    progress_level = models.CharField(max_length=25, null=True, choices=USER_PROGRESS_LEVELS)
    isDetailViewed = models.BooleanField(default=False)

class DocumentInfo(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    certificate = models.FileField(upload_to="documents")
    id_card = models.FileField(upload_to="documents")
    service_certificate = models.FileField(upload_to="documents")
    educational_certificate = models.FileField(upload_to="documents")

############EDIT############## 我将此保存方法添加到我的用户模型中。它有效,但我希望它更新用户模型而不保存它。我的意思是我希望它检查文档和联系信息模型,如果它们存在,请更新该 progress_level。我必须从管理页面手动保存用户模型才能发生这种情况。我该如何解决它

def save(self, *args, **kwargs):
    if self.documentinfo and self.contactinfo:
        self.progress_level = USER_PROGRESS_LEVELS[4][0]
    return super(User, self).save(*args, **kwargs)

【问题讨论】:

    标签: python django


    【解决方案1】:

    更新模型保存方法怎么样?

    models.py

    class User(...):
    
        ...
        document_info = models.OneToOneField(DocumentInfo, ...)
        contact_info = models.OneToOneField(ContactInfo, ...)
    
        def save(self, *args, **kwargs):
    
            if self.document_info and self.contact_info:
                self.progress_level = USER_PROGRESS_LEVELS[1][0]
    
            return super().save(*args, **kwargs)
    

    【讨论】:

    • 但是怎么做呢?如果我在save方法中添加这条语句,用户模型如何识别其他模型?联系信息和文档信息与具有外键关系的用户模型相关。
    • 有很多方法可以实现您的目标-我认为您在问题中提出的方法是最好的-如果您不想使用您的方法,您可以覆盖保存方法(或使用信号) ContactInfoDocumentInfo 模型中的一个,它们检查适当的条件,但这可能比您当前的方法管理起来更麻烦。
    • 编辑:假设 User 模型与 DocumentInfoContactInfo 有外键关系,您可以像我在回答中所做的那样缩短您的代码 - 也许您可以分享您的 models.py 代码?
    • 我添加了我的模型,请查看它们。这不起作用,因为我将这些模型连接到用户而不是其他方式。用户模型中没有 document_info 或 contact_info 字段
    • 那么 - 可以肯定 - 一个用户可以拥有许多文档和许多联系信息?
    【解决方案2】:

    您想更改添加一些文档或完整联系人的progress_level值...您如何在文档模型或联系人模型的保存或更新方法中执行此操作...与特定用户相关的联系人或文档模型已保存或更新方法可以通过用户实例影响用户模型的“progress_level”值。 您可以在保存方法上从文档模型中获取用户实例(因为您有外键)并检查进程是否已完成...通过用户实例增加“progress_level”。 如果你不知道如何在代码中让我知道用示例代码解释一下

    【讨论】:

    • 我不知道如何通过在另一个模型中创建保存方法来更新模型中的字段。我将关系编辑为一对一关系。你能帮我写代码吗
    • 我将示例代码放在新帖子中...希望有用。
    【解决方案3】:

    我假设你的模型是这样的:

    class User(AbstractUser):
        progress_level = models.IntegerField(null=True, default=0) 
        // some other field 
    
    class DocumentInfo(models.Model):
        user = models.ForeignKey(User, on_delete=models.CASCADE)
        // some other field
    

    您为这样的文档设置序列化程序:

    class DocumentInfoSerializer(serializers.ModelSerializer):
    
        user = UserSerializer(many=False, write_only=True)
    
        class Meta:
            model = DocumentInfo
            fields = ('id', 'user', /* some other fields */)
            read_only_fields = ('id',)
    

    现在在 DocumentInfo 模型中,您应该像这样编写保存方法:

    class DocumentInfoManager(models.Manager):
        
        def create(self, user, **kwargs):
            user_obj = User.objects.get(id=user.id)            
            user_obj.progress_level = 1 // set progress_level here 
            user.save()                 // user instance update here
    
            document_obj = DocumentInfo(user=user, **kwargs)
            document_obj.save()
    
            return document_obj 
    
    class DocumentInfo(models.Model):
        user = models.ForeignKey(User, on_delete=models.CASCADE)
        // some other field
        objects = DocumentInfoManager() // this line is necessary
    

    您在用户模型中定义 id。 请注意,在模型中没有必要使用增量参数定义 id (primary_key) 字段... django 自动为每个模型创建 id

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-08-08
      • 1970-01-01
      • 2015-03-31
      • 1970-01-01
      • 2020-02-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多