Home > Software design >  TabularInline for through Model not showing on Django 3
TabularInline for through Model not showing on Django 3

Time:08-02

First off, I am using Django 3.2.9. Here are my models, pretty straightforward:

class AChallenge(models.Model):
    name = models.CharField(max_length=255, unique=True)

class SubAdvanced(models.Model):
    name: str = models.CharField(max_length=255, unique=True)
    challenges = models.ManyToManyField(
        AChallenge, related_name = 'challenge', through='SubAdvancedChallenge')

class SubAdvancedChallenge(models.Model):
    sub_advanced = models.ForeignKey(
        SubAdvanced, on_delete=models.CASCADE)
    challenge = models.ForeignKey(
        AChallenge, on_delete=models.CASCADE)
    percentage = models.FloatField(
        validators=[MinValueValidator(0), MaxValueValidator(1)])

Here is my admin :

class AChallengeAdmin(MyAppAdmin):
    pass

admin.site.register(AChallenge, AChallengeAdmin)

class SubAdvancedChallengeInline(admin.TabularInline):
    model = SubAdvancedChallenge
    extra = 1

class SubAdvancedAdmin(MyAppAdmin):
    inlines = (SubAdvancedChallengeInline,)

admin.site.register(SubAdvanced, SubAdvancedAdmin)

According to Screenshot

Despite all this, I am only getting this:

enter image description here

If I try to force the inclusion of the "challenges" field, like this:

class SubAdvancedAdmin(BelleEmpreinteAdmin):
    fields = ("name", "challenges")
    inlines = (SubAdvancedChallengeInline,)

I will get the following error:

(admin.E013) The value of 'fields' cannot include the ManyToManyField 'challenges', because that field manually specifies a relationship model.

The fact that my TabularInline simply does not appear definitely seems like a bug, but it seems too crazy that this slipped through the cracks for so long. Anybody else met this issue?

CodePudding user response:

I am not sure, but what if you write it

@admin.register(SubAdvanced)
class SubAdvancedAdmin(BelleEmpreinteAdmin):
    inlines = (SubAdvancedChallengeInline,)

CodePudding user response:

So as some may have guessed, and as I realized while re-reading my question, the issue was with permissions, since I am browsing my admin site as a non-superuser.

My modelAdmins are inherited from an override, that adds users with is_staff set to True into superadmin permissions, like this:

from django.contrib import admin

class MyAppAdmin(admin.ModelAdmin):
    def _allow(self, user):
        return user.is_staff or user.is_superuser

    def has_change_permission(self, request, obj=None):
        return self._allow(request.user)

    def has_delete_permission(self, request, obj=None):
        return self._allow(request.user)

    def has_add_permission(self, request):
        return self._allow(request.user)

    def has_view_permission(self, request, obj=None):
        return self._allow(request.user)

    def has_module_permission(self, request):
        return self._allow(request.user)

But I did not create such permissions for TabularInline! So doing this did the trick:

class MyAppTabularInlineAdmin(admin.TabularInline):
    def _allow(self, user):
        return user.is_staff or user.is_superuser

    def has_change_permission(self, request, obj=None):
        return self._allow(request.user)

    def has_delete_permission(self, request, obj=None):
        return self._allow(request.user)

    def has_add_permission(self, request, obj=None):
        return self._allow(request.user)

    def has_view_permission(self, request, obj=None):
        return self._allow(request.user)

    def has_module_permission(self, request):
        return self._allow(request.user)

I then use this as my TabularInline and voila:

class SubAdvancedChallengeInline(MyAppTabularInlineAdmin):
    model = SubAdvancedChallenge
    extra = 1
  • Related