Faisal Karim
Faisal Karim

Reputation: 985

Django Admin: create button for foreign key of a foreign key

Sorry, for the bad title. I was not sure how to phrase it.

Background:

So mainly I am creating this eCommerce website which has a model called product:

class Product(models.Model):
    name                = models.CharField(max_length=80)
    price               = models.DecimalField(decimal_places=2, max_digits=6)
    on_sale             = models.BooleanField(default=False)
    sale_price          = models.DecimalField(decimal_places=2, max_digits=6)
    short_description   = models.TextField()
    description         = models.TextField()
    in_stock            = models.BooleanField(default=True)
    category            = models.ForeignKey(Category, on_delete=models.SET_NULL, null=True)
    tags                = models.ManyToManyField(Tag)  
    def __str__(self):
        return self.name

This model is linked to by an attribute model using foreign key as so:

class Attribute(models.Model):
    product             = models.ForeignKey(Product, on_delete=models.CASCADE)
    title               = models.CharField(max_length=20)
    def __str__(self):
        return self.title

finally, the attributes model is linked to by AttributesOption model using a foreign key as so:

class AttributeOption(models.Model):
    value               = models.CharField(max_length=20)
    attr                = models.ForeignKey(Attribute, on_delete= models.CASCADE)
    price               = models.DecimalField(decimal_places=2, max_digits=6, null=True)
    on_sale             = models.BooleanField(default=False)
    sale_price          = models.DecimalField(decimal_places=2, max_digits=6, null=True)
    short_description   = models.TextField(null=True)
    description         = models.TextField(null=True)
    in_stock            = models.BooleanField(default=True)

    def __str__(self):
        return self.value

So essentially, a product can have multiple attributes such as colour, size, type etc. Similarly, an attribute can have multiple values such as pink, blue, red, green etc. (I'll later code it so that if there is a value for on_sale, price etc. in the attribute value it will override the main product value.)

Now to the main problem.

I want to allow the admin to create an attribute and it's set of values from the create product page. [![Picture of the create product page currently][1]][1]

I want to have it so that there is a list of attribute options under each attribute. I have been able to get this far using admin.TabiularInline however, I don't know where to go next.

Things I have tried.

I tried to add an inline to the inline but as expected that didn't work. I tried changing show_change_link = True but that makes a form pop up only when editing. I tried changing the structure of the models but that ruined the logic/flow of data.

Here's how the admin.py looks like if currently if that helps.

from django.contrib import admin
from . import models

admin.site.register(models.Tag)
admin.site.register(models.Category)
admin.site.register(models.Attribute)
admin.site.register(models.AttributeOption)

class InlineProductImages(admin.TabularInline):
    model =  models.ProductImage

class InlineAttributeOption(admin.StackedInline):
    model =  models.AttributeOption

    fieldsets = (
        (None, {
            'fields': ('attr', 'value',)
        }),
        ('Advanced options', {
            'classes': ('collapse',),
            'fields': ('price', 'on_sale', 'sale_price', 'short_description', 'description', 'in_stock',),
        }),
    )

class InlineAttribute(admin.TabularInline):
    model =  models.Attribute
    show_change_link = True

@admin.register(models.Product)
class ProductAdmin(admin.ModelAdmin):
    inlines = [InlineProductImages, InlineAttribute]

If nothing works, I feel like recreating the entire admin site will be the only way for me to go. But recreating the entire app, with its filters, amend and create pages, security/validation will require a lot of work. I feel like there should be an easier way than to recreate the entire app just because one page is not ideal.

Thanks for the help in advance.

(P.S: completely new to Django. This is my first app. If the answer is super simple that's why I can't find anything on this on the internet, most likely that's the reason behind my ignorance)

Upvotes: 0

Views: 119

Answers (1)

Faisal Karim
Faisal Karim

Reputation: 985

Finally figured out a way to get an inline form of an inline. I had to use a library called, "django-nested-admin". With some amendments to my admin.py, it seems to work fine.

Upvotes: 1

Related Questions