我有两种模式:
class User(models.Model):
name = models.CharField(max_length=32)
class Referral(models.Model):
referring_user = models.ForeignKey(User, related_name="referrals")
referred_user = models.ForeignKey(User, related_name="referrers")
percentage = models.PositiveIntegerField()
这个想法是每个用户都有n
个推荐人,并且应该至少有一个。每个引荐来源都有一个percentage
值,当添加到其他引荐来源时,它应该加起来为100%。
所以用户" Alice"可能有推荐人" Bob" (50%)和" Cynthia" (50%),用户"唐纳德"可能有一个推荐人:" Erin" (100%)。
我遇到的问题是验证。有没有办法(最好是使用admin.TabularInline
与Django管理员合作的方式)我可以通过验证拒绝保存User
如果Refferrals != 100%
的总和?
理想情况下,我希望这种情况发生在表单/管理员级别,而不是覆盖User.save()
,但此时我不知道从哪里开始。大多数Django的验证代码似乎是原子的,并且我之前在Django中完成了多行验证。
答案 0 :(得分:1)
作为per the Django docs,clean()
是为您的目的实施的官方功能。你可以想象一个看起来像这样的函数:
from django.core.exceptions import ValidationError
def clean(self):
total_percentage = 0
for referrer in self.referrers.all():
total_percentage += referrer.percentage
if total_percentage !== 100:
raise ValidationError("Referrer percentage does not equal 100")
答案 1 :(得分:1)
在Jerry Meng建议我查看data
属性而不是cleaned_data
后,我开始探究admin.ModelAdmin
以了解我如何访问该方法。我发现get_form
似乎返回了一个表单类,所以我重写了该方法以捕获返回的类,将其子类化,并覆盖那里的.clean()
。
进入内部后,我循环使用正则表达式self.data
,找到相关字段然后进行数学计算。
import re
from django import forms
from django.contrib import admin
class UserAdmin(admin.ModelAdmin):
# ...
def get_form(self, request, obj=None, **kwargs):
parent = admin.ModelAdmin.get_form(self, request, obj=None, **kwargs)
class PercentageSummingForm(parent):
def clean(self):
cleaned_data = parent.clean(self)
total_percentage = 0
regex = re.compile(r"^referrers-(\d+)-percentage$")
for k, v in self.data.items():
match = re.match(regex, k)
if match:
try:
total_percentage += int(v)
except ValueError:
raise forms.ValidationError(
"Percentage values must be integers"
)
if not total_percentage == 100:
raise forms.ValidationError(
"Percentage values must add up to 100"
)
return cleaned_data
return PercentageSummingForm