我正在将遗留项目从Django 2.2升级到Django 4.2。除了使用ManyToMany字段的模型之外,其他一切都正常。
型号:
# models.py
class AccessPolicy(TimeStampedModel):
name = models.CharField(max_length=255, null=False, blank=False)
external_id = models.CharField(max_length=255, unique=True, null=True)
version_hash = models.CharField(max_length=255, null=False, blank=False)
read_only = models.BooleanField(default=False, help_text=('Some text'))
users = models.ManyToManyField(User, blank=True)
class Meta:
verbose_name = 'Access Policy'
verbose_name_plural = 'Access Policies'
def __str__(self):
return f'{self._meta.object_name} Object ({self.pk})'
形式:
# forms.py
class AccessPolicyForm(forms.ModelForm):
external_id = forms.CharField(disabled=True, required=False)
rules = forms.CharField(widget=QueryBuilderWidget)
class Meta:
model = AccessPolicy
fields = 'name', 'external_id', 'read_only', 'rules', 'users',
def clean_external_id(self):
external_id = self.cleaned_data.get('external_id')
if not external_id:
return md5(f"{str(self.instance.created)} {self.cleaned_data.get('name')} {self.data.get('rules')}")
return external_id
def clean_rules(self) -> CleanedRules:
raw_rules: RawRules = json.loads(self.cleaned_data.get('rules'))
conditional_serializer = RulesSerializer(data=raw_rules)
if not conditional_serializer.is_valid():
raise ValidationError(conditional_serializer.errors)
return conditional_serializer.validated_data
def save(self, commit=True):
self.instance.version_hash = hash_dict(self.cleaned_data.get('rules'))
return super().save(commit)
def _save_m2m(self):
self.instance.rules.all().delete()
self._save_condition()
self._save_users()
def _save_users(self):
self.instance.users.clear()
self.instance.users.add(*self.cleaned_data.get('users'))
def _save_condition(self):
root_condition = RulesSerializer().create(self.cleaned_data.get('rules'))
root_condition.access_policy = self.instance
root_condition.save()
admin文件:
# admin.py
class AccessPolicyAdmin(admin.ModelAdmin):
form = AccessPolicyForm
list_display = 'name',
search_fields = 'name',
formfield_overrides = {
models.ManyToManyField: {
'widget': FilteredSelectMultiple(attrs={'size': 20},
verbose_name='linked users',
is_stacked=False)
},
}
def get_form(self, request, obj: AccessPolicy = None, change=False, **kwargs):
form = super().get_form(request, obj, change, **kwargs)
data = self._get_form_data(obj or AccessPolicy())
form.declared_fields[AUTHORIZATION_CONDITION_CHILDREN].initial = json.dumps(data)
return form
def _get_form_data(self, access_policy: AccessPolicy):
return pipe(access_policy,
AccessRulesGenerator.get_root_rule,
RulesSerializer,
extract_data)
这段代码在Django 2.2下运行良好,没有错误,但在Django 4.2下会出现错误:
'AccessPolicy' instance needs to have a primary key value before this relationship can be used.
我知道在添加任何m2m
字段之前需要保存模型的示例,并且必须使用.add()
方法添加m2m
字段。我尝试了对save()
和_save_m2m()
方法进行一些修改,但没有成功。我应该在哪里做?
1条答案
按热度按时间bgibtngc1#
我决定创建
AccessPolicy
的临时示例,那么缺少pk
的问题不再存在。在我看来,这个解决方案不是最好的,因为我生成了几个同名的策略,然后我必须删除它们。但是主键的问题消失了。