ded824bddd
KFetGroup model - Provides a distinction from non-kfet Groups. - Convert code appropriately. - Initially filled from Groups containing K-Fêt (this was the previous distinction) in the kfetauth.0002 migration. Permission proxy model (kfetauth app) - Proxy of the django.contrib.auth Permission model. - Adds the 'kfet' manager which returns only kfet-related permissions. KeepUnselectableModelFormMixin - Helps to keep the unselectable items of many-to-many field for ModelForm. - 'kfetauth' forms (related to KFetGroup) use this mixin. Using KFetGroup allows to simplify the 'kfet/account_group_form.html' template. A bug is also fixed in 'kfet/form_field_snippet.html', which could lead to prevent field displays if they used CheckboxSelectMultiple widget.
63 lines
2.2 KiB
Python
63 lines
2.2 KiB
Python
class KeepUnselectableModelFormMixin:
|
|
"""
|
|
Keep unselectable items of queryset-based fields.
|
|
|
|
Mixin for 'ModelForm'.
|
|
|
|
Attribute
|
|
keep_unselectable_fields (list of field names)
|
|
|
|
This adding is performed in 'save' method. Specifically, if 'commit' arg
|
|
is False, it's done in 'save_m2m' method.
|
|
|
|
These fields must have a 'queryset' attribute (the selectable items), like
|
|
'ModelMultipleChoiceField' (default field for ManyToMany model fields).
|
|
"""
|
|
keep_unselectable_fields = []
|
|
|
|
def get_unselectable(self, field_name):
|
|
"""
|
|
Returns 'field_name' model field items of instance which can't be
|
|
selected with the corresponding form field.
|
|
|
|
Should be used before 'form.save' call, or 'form.save_m2m' call if
|
|
'commit=False' was passed as argument to 'form.save'.
|
|
"""
|
|
if self.instance.pk:
|
|
previous = getattr(self.instance, field_name).all()
|
|
selectable = self.fields[field_name].queryset
|
|
if callable(selectable):
|
|
selectable = selectable()
|
|
return previous.exclude(pk__in=[o.pk for o in selectable])
|
|
else:
|
|
# Instance is being created, there is no previous item.
|
|
return []
|
|
|
|
def save(self, commit=True):
|
|
# Use 'commit=False' to get the 'save_m2m' method.
|
|
instance = super().save(commit=False)
|
|
|
|
_save_m2m = self.save_m2m
|
|
|
|
def save_m2m():
|
|
# Get the unselectable items.
|
|
# Force evaluate because those items are going to change.
|
|
unselectable_f = {
|
|
f_name: list(self.get_unselectable(f_name))
|
|
for f_name in self.keep_unselectable_fields
|
|
}
|
|
# Default 'save_m2m' use 'set' method of m2m relationships with
|
|
# fields' cleaned data.
|
|
_save_m2m()
|
|
# Add the unselectable elements.
|
|
for f_name, unselectable in unselectable_f.items():
|
|
getattr(instance, f_name).add(*unselectable)
|
|
|
|
# Implement the default behavior of 'save' method, with our own
|
|
# 'save_m2m'.
|
|
if commit:
|
|
instance.save()
|
|
save_m2m()
|
|
else:
|
|
self.save_m2m = save_m2m
|
|
return instance
|