Reputation: 1920
I'm building an e-commerce project in Django. Initially I had a naive Product model, which allowed me to move forward. But later, I've added ProductType, ProductSpecification (with a ForeignKey to Type), and ProductSpecificationValue classes/tables (with a ForeignKey to both Specification and Product). The use case should be obvious: say I have a Product of a shirt ProductType, which can come in different colors. That means a color Specification.
So first, I create two Product Types, say Shirt and Book. Each has a price spec and weight spec. In addition, Shirt has a color spec. The problem is, when I am creating a new Product, and select any type, the drop-down for selecting a spec has 5 values to chose from - two prices, two weights, and a color.
Now, I don't know if it's a real problem - but it sure is very confusing. I understand that before I save a Product, the Django Admin UI doesn't yet know what Type it is gonna be, so can't possibly limit the specs to those of a chosen type only. However, even after saving the Product (which demands a Type), and subsequently try to edit it, the Specs drop-down still presents me with all 5 choices. Database shows the likely cause:
sqlite> select * from inventory_productspecification;
1|price |1
2|weight|1
3|price |2
4|weight|2
5|color |2
this query is not filtering by Type id (1 vs 2 in here). My guess some change in the admin.py might take care of this? Mine is pretty bare-bones:
class ProductSpecificationInline(admin.TabularInline):
model = ProductSpecification
@ admin.register(ProductType)
class ProductTypeAdmin(admin.ModelAdmin):
inlines = [
ProductSpecificationInline,
]
class ProductSpecificationValueInline(admin.TabularInline):
model = ProductSpecificationValue
@admin.register(Product)
class ProductAdmin(admin.ModelAdmin):
inlines = [
ProductSpecificationValueInline,
]
(thank you for your time y'all)
Upvotes: 2
Views: 727
Reputation: 2269
So it seems like there's a couple things to solve: #1 is the object creation process, and #2 is showing ProductSpecificationValues
that are associated with the Product
's ProductType
.
#1: Don't show the ProductSpecificationValueInline
when the Product is being created. The user should only be able to set this value after they have created the product and set the ProductType.
@admin.register(Product)
class ProductAdmin(admin.ModelAdmin):
inlines = [
ProductSpecificationValueInline,
]
def get_inlines(self, request, obj):
if not obj.id or not obj.product_type:
return [] # ... then don't show any inlines
return self.inlines
#2: The ProductSpecificationValueInline
should only show specification values that are associated with the Product type.
class ProductSpecificationValueInline(admin.TabularInline):
model = ProductSpecificationValue
def get_formset(self, request, obj=None, **kwargs):
inline_formset = super().get_formset(request, obj, **kwargs)
# I don't know what you named your field(s), but this illustrates the concept
# of changing the queryset that is used to populate the choices for this field
qs = inline_formset.base_fields['product_specification'].queryset
qs = qs.filter(product_type=obj.product_type)
inline_formset.base_fields['product_specification'].queryset = qs
return inline_formset
Obviously this might not line up 100% with your models (for example, are you using a ManyToMany field for the Product's ProductSpecification values? And what are the field names in the models?), but the general principle remains the same: in your inline class, you would override the get_formset
method and alter the queryset for the form field(s) in question.
Glad to help you get a little closer if needed, but would need to see the code for your models.
Upvotes: 2