我有2个相同型号的内联。
class UsersInlineAdmin(GenericTabularInline):
model = CTSportsToCriterias
class TeamsInlineAdmin(GenericTabularInline):
model = CTSportsToCriterias
class CTSportsToCriterias(models.Model):
user_use = models.BooleanField(verbose_name=_('is available to users?'), default=False)
team_use = models.BooleanField(verbose_name=_('is available to teams?'), default=False)
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey()
criteria_group = models.ForeignKey(CriteriaGroups, verbose_name=_('criteria group'))
当我从UsersInlineAdmin
移除某个项目时(所以在这种情况下user_use
为True),如果此项目也存在于TeamsInlineAdmin
中(team_use
也为True), django会自动从TeamsInlineAdmin
内联中删除此项,因为根据Django文档,代码:
def save_formset(self, request, form, formset, change):
for obj in formset.deleted_objects:
...
提供模型的对象。
所以,因为在我的情况下,模型可以有一些选项(user_use
\ team_use
),是否可以在inline
中获取save_formset
名称类似的东西:
if (inline_name == 'UsersInlineAdmin' and not obj.team_use) or \
(inline_name == 'TeamsInlineAdmin' and not obj.user_use):
obj.delete()
修改
如果我添加form
并覆盖clean()
,当我添加user
项时team
项已存在,则Django不会在数据库user_use
中更新真的。相反,Django创造了一个新的记录。
# admin
class UsersInlineAdmin(GenericTabularInline):
model = CTSportsToCriterias
form = UserFieldForm
# form
class UserFieldForm(forms.ModelForm):
class Meta:
model = CTSportsToCriterias
def clean(self):
m = super(UserFieldForm, self).clean()
# This trick works ok in case when I want to DELETE user's item,
# so the trick changes in DB 'user_use' to False, if 'team_use' already exists
if m['DELETE'] is True:
try:
qs = CTSportsToCriterias.objects.get(object_id=object_id,
content_type=content_type,
criteria_group=criteria_group,
team_use=True)
m['id'] = qs.pk
m['DELETE'] = m['user_use'] = False
except ObjectDoesNotExist:
pass
# Can not repeate the same trick as above.
# When 'team_use' already exists, I want to change the value 'user_use' of this team's obj to True,
# but the trick as above does not work in this case - Django adds a new row to DB, instead of update
# the existing one.
elif m['DELETE'] is False:
try:
qs = CTSportsToCriterias.objects.get(object_id=object_id,
content_type=content_type,
criteria_group=criteria_group,
team_use=True)
m['id'] = qs.pk
m['DELETE'] = m['user_use'] = False
except ObjectDoesNotExist:
pass
return m
答案 0 :(得分:1)
# forms
class UserFieldForm(forms.ModelForm):
user_use = forms.BooleanField(widget=forms.HiddenInput(), initial=True, required=True)
def clean(self):
m = super(UserFieldForm, self).clean()
if m['DELETE'] is True:
m['user_use'] = False
return m
class TeamFieldForm(forms.ModelForm):
team_use = forms.BooleanField(widget=forms.HiddenInput(), initial=True, required=True)
def clean(self):
m = super(TeamFieldForm, self).clean()
if m['DELETE'] is True:
m['team_use'] = False
return m
# admin
class UsersInlineAdmin(GenericTabularInline):
model = CTSportsToCriterias
form = UserFieldForm
class TeamsInlineAdmin(GenericTabularInline):
model = CTSportsToCriterias
form = TeamFieldForm
class CriteriaGroupsAdmin(admin.ModelAdmin):
inlines = [CriteriaTranslationsInlineAdmin, UsersInlineAdmin, TeamFieldForm]
def save_formset(self, request, form, formset, change):
instances = formset.save(commit=False)
for obj in formset.deleted_objects:
if isinstance(instance, CTSportsToCriterias):
is_user_use_form = obj.user_use
is_team_use_form = obj.team_use
# There is just one option in DB (user_use or team_use), so delete obj from DB
if not is_user_use_form and not is_team_use_form:
obj.delete()
else:
user_n_team = CTSportsToCriterias.objects.get(
object_id=obj.object_id, content_type=obj.content_type, criteria_group=obj.criteria_group)
# Means 'user_use' exists and we need to change 'team_use' to False
if is_user_use_form:
user_n_team.team_use = False
# Means 'team_use' exists and we need to change 'user_use' to False
elif is_team_use_form:
user_n_team.user_use = False
user_n_team.save()
# Saves user_use + team_use in one row as there is no need to use 2 DB rows for each case (user\team)
# if user_use or team_use already exists in DB, or just creates a new row.
for instance in instances:
if isinstance(instance, CTSportsToCriterias):
content_type = ContentType.objects.get(id=instance.content_type_id)
criteria_group = CriteriaGroups.objects.get(id=instance.criteria_group_id)
qs_kwargs = dict(content_type=content_type, object_id=instance.object_id, criteria_group=criteria_group)
is_user_use = instance.user_use
is_team_use = instance.team_use
if is_user_use:
qs_kwargs.update(defaults=dict(user_use=is_user_use))
if is_team_use:
qs_kwargs.update(defaults=dict(team_use=is_team_use))
CTSportsToCriterias.objects.update_or_create(**qs_kwargs)