Django Admin&Django2.0:如何禁止患者自身作为其责任人?
解决Django中患者不能设置自身为责任人的问题
嘿,作为Django 2.0的新手碰到这种关联逻辑的限制需求很正常,我给你几个实用的方案,都是在Django 2.0里能直接落地的:
方案1:模型层添加clean方法(最推荐)
模型层的验证是最底层的,不管你是通过admin后台、表单提交还是代码直接修改数据,都会触发这个验证,能从根源上保证数据的合法性。
假设你的模型结构是基于User多表继承的,修改Patient模型如下:
from django.db import models from django.contrib.auth.models import User from django.core.exceptions import ValidationError class Patient(User): # 你的自定义字段,比如病历号 medical_record_no = models.CharField(max_length=20, unique=True) # 关联责任人:一个Patient对应一个Responsible,一个Responsible对应多个Patient responsible = models.ForeignKey('Responsible', on_delete=models.CASCADE, related_name='patients') def clean(self): # 先调用父类的clean方法,保留原有验证逻辑 super().clean() # 检查当前患者和选中的责任人是否为同一用户 # 多表继承下,User子类会有user_ptr字段关联到父类User if self.responsible.user_ptr == self.user_ptr: raise ValidationError("患者不能将自身设置为责任人") class Responsible(User): # 你的自定义字段,比如联系电话 contact_phone = models.CharField(max_length=11)
当你尝试保存不符合规则的Patient实例时,Django会抛出ValidationError,不管是在admin操作还是代码里创建对象,都会拦截不合法的数据。
方案2:表单层添加字段验证
如果你主要通过表单来创建/编辑患者信息,可以在表单里针对responsible字段做验证:
from django import forms from .models import Patient class PatientForm(forms.ModelForm): class Meta: model = Patient fields = ['username', 'email', 'medical_record_no', 'responsible'] def clean_responsible(self): selected_responsible = self.cleaned_data.get('responsible') # 分两种情况:创建新患者/编辑已有患者 if self.instance.pk: # 编辑模式:直接对比当前患者和选中的责任人 if self.instance.user_ptr == selected_responsible.user_ptr: raise forms.ValidationError("不能选择自己作为责任人") else: # 创建模式:对比表单提交的用户名和责任人的用户名 if self.cleaned_data.get('username') == selected_responsible.username: raise forms.ValidationError("不能选择自己作为责任人") return selected_responsible
这种方法的缺点是:如果有人通过代码直接修改数据库(比如shell里操作),这个验证不会触发,所以只适合纯表单驱动的场景。
方案3:使用pre_save信号拦截
如果你不想修改模型或表单,可以用Django的信号机制在保存前拦截不合法数据:
from django.db.models.signals import pre_save from django.dispatch import receiver from django.core.exceptions import ValidationError from .models import Patient @receiver(pre_save, sender=Patient) def check_responsible_self(sender, instance, **kwargs): if instance.responsible.user_ptr == instance.user_ptr: raise ValidationError("患者不能设置自身为责任人")
信号会在模型实例保存前自动触发,同样能拦截不合法数据,但相比模型层的clean方法,它的逻辑分散在模型外,可读性稍差,优先级不如方案1。
小提示
如果你用Django Admin管理患者,模型的clean方法会自动被调用,当你在后台选择自己作为责任人时,页面会直接弹出错误提示,非常直观。
内容的提问来源于stack exchange,提问作者ebmm01
相关产品推荐
相关产品推荐

