如何获取管理员内联名称或如何定义哪个内联更改?

时间:2016-10-25 18:19:01

标签: django django-admin

我有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

1 个答案:

答案 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)