Question

I have 2 django models - main (product) and linked details (PhysicalProperty are many-to-many link through additional model ProductMetricals).

In main model Product I wrote the post_save reciever, where I check and clean the data in details.

If I try

  Product.save()

from IDLE, it works fine.

But if I change and save main Product in Admin form, I've got the exception

Select a valid choice. That choice is not one of the available choices

enter image description here

I've try to debug it, but steel have no idea - why Admin raise exception?

Here is a code

models.py

from django.db import models

# Create your models here.

class PhysicalProperty(models.Model):
    shortname = models.CharField(max_length=255)    
    def __str__(self):
        return self.shortname

class Product(models.Model):
    shortname = models.CharField(max_length=255)

    product_metricals = models.ManyToManyField( PhysicalProperty, through = 'ProductMetricals' )    

    def __str__(self):
        return self.shortname

from django.db.models.signals import post_save
from django.dispatch import receiver

@receiver(post_save, sender=Product)
def product_post_save(sender, instance, **kwargs):
    ProductMetricals.objects.filter( product = instance ).delete()

class ProductMetricals(models.Model):
    amount=models.FloatField()
    product=models.ForeignKey( Product )
    physicalproperty = models.ForeignKey(PhysicalProperty )

    class Meta:
        unique_together = ("product", "physicalproperty")

admin.py

from django.contrib import admin

# Register your models here.

from product.models import Product, ProductMetricals, PhysicalProperty

from django import forms

class PhysicalPropertyAdmin(admin.ModelAdmin):
    list_display = ['shortname']

admin.site.register(PhysicalProperty, PhysicalPropertyAdmin)

class ProductMetricalsInline(admin.TabularInline):
    model = ProductMetricals
    fieldsets = [
        (None, {'fields': ['physicalproperty','amount']}),
    ]
    extra = 2

class ProductAdmin(admin.ModelAdmin):
    fieldsets = [
        (None,               {'fields': ['shortname']}),
    ]
    inlines = [ProductMetricalsInline]
    list_display = ['shortname']

admin.site.register(Product, ProductAdmin)

If I create the some property, create product, add a one property to product, then change the name of product and save it - I'v got the exception

Exception come (I think) from ProductMetricals.objects.filter( product = instance ).delete()

Was it helpful?

Solution

Your issue lies in your post_save hook on Product. When you save a Product in your ProductAdmin, save_model() is called and then save_related(). This in turn calls save_formset with a formset for ProductMetricals that contains a key to a ProductMetricals that is now deleted. It is now invalid (since you deleted it with your save on Product).

I ran into a similar issue with deleting on an inline that had a relationship with another inline in the admin view. I ended up setting on_delete=models.SET_NULL for my foreign key relationship since by default Django cascade deletes. Another option would be to manually override the formset.

It looks similar to what was discussed in bug #11830

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top