samedi 29 novembre 2014

python - Django : inclure un champ de clé primaire dans un enregistrement de M2M inline - Stack Overflow


I have a Product model that includes an M2M reference to an Option model, using an intermediate model, OptionPrice, which lets me override the base values of the option with product-specific values.


here are the three models:


    #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class Product(models.Model):
productid = UUIDField(db_column='ProductID', editable=False, primary_key=True, auto=True, hyphenate=True)
productname = models.CharField(db_column='ProductName', max_length=100, verbose_name='name', default='')
slug = AutoSlugField(populate_from='productname',unique=True, max_length=100, always_update=True)
productnumber = models.CharField(db_column='ProductNumber', blank=True, max_length=50, null=True, verbose_name='number', default='')
cost = models.DecimalField(decimal_places=4, max_digits=19, db_column='Cost', default=0)
priceperitem = models.DecimalField(decimal_places=4, max_digits=19, db_column='PricePerItem', verbose_name='price per item', default=0)
onspecial = models.BooleanField(db_column='OnSpecial', verbose_name='on special', default=False)
discount = models.FloatField(null=True, db_column='Discount', blank=True, verbose_name='discounted', default=0)

#connections to other models
options = models.ManyToManyField(Option, null=True, through='OptionPrice', verbose_name='product options', blank=True)
optiongroups = models.ManyToManyField(OptionGroup, null=True, verbose_name='product option groups', blank=True)

package = models.ForeignKey(ShippingPackage, verbose_name='shipping container', default=1)
categories = models.ManyToManyField(Category, verbose_name='product categories')
cross_sell = models.ManyToManyField('Product', verbose_name='cross-sell items', blank=True)


#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class Option(models.Model):
optionid = UUIDField(db_column='OptionID', editable=False, primary_key=True, auto=True, hyphenate=True)
title = models.CharField(db_column='Title', max_length=500)
price = models.DecimalField(decimal_places=4, max_digits=19, db_column='Price')
pricemodstyle = models.CharField(db_column='PriceModStyle', max_length=50, verbose_name='price modification style', choices=PRICE_MOD_CHOICES)
displayrank = models.IntegerField(db_column='DisplayRank', verbose_name='sort order')
optiongroup = models.ForeignKey('OptionGroup', verbose_name='option group')



#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class OptionPrice(models.Model):
optionpriceid = UUIDField(db_column='OptionPriceID', editable=False, primary_key=True, auto=True, hyphenate=True)
option = models.ForeignKey(Option)
product = models.ForeignKey(Product)
price = models.DecimalField(decimal_places=4, max_digits=19, db_column='Price')
pricemodstyle = models.CharField(db_column='PriceModStyle', max_length=50, verbose_name='price modification style', choices=PRICE_MOD_CHOICES)

, and for the admin.py, I have the product options defined as being inline


#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class ProductAdmin(ImportExportModelAdmin):
resource_class = ProductResource
model=Product
ordering = ['categories__categoryname','productname']
save_on_top = True
save_as = True
inlines = [OptionPriceAdminInline]

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class OptionPriceAdminInline(admin.TabularInline):
model=OptionPrice
extra = 0
save_on_top = True

My issue is that when I load a product in the administrator, the inlines show up beautifully, with every field represented except the primary key (optionpriceid). Consequently, the first time I add options to this product, they save properly (new id is created automagically). If I then attempt to reload the product and edit the saved options, I get a MultiValueDictKeyError because these inlined items don't actually have their primary key values included in the rows emitted by the admin.


What am I doing wrong?




The issue turned out to be a django bug, solved by this pull request. The problem is that I was using a custom UUIDField as the primary key - to quote the ticket:



It seems to be that this this problem happens for models which have a primary key field that is not based on the AutoField (such as a CharField).


When the primary key field is not based on an AutoField 'has_auto_field' is not set to True, therefore it will not output the primary key in the form.




I have a Product model that includes an M2M reference to an Option model, using an intermediate model, OptionPrice, which lets me override the base values of the option with product-specific values.


here are the three models:


    #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class Product(models.Model):
productid = UUIDField(db_column='ProductID', editable=False, primary_key=True, auto=True, hyphenate=True)
productname = models.CharField(db_column='ProductName', max_length=100, verbose_name='name', default='')
slug = AutoSlugField(populate_from='productname',unique=True, max_length=100, always_update=True)
productnumber = models.CharField(db_column='ProductNumber', blank=True, max_length=50, null=True, verbose_name='number', default='')
cost = models.DecimalField(decimal_places=4, max_digits=19, db_column='Cost', default=0)
priceperitem = models.DecimalField(decimal_places=4, max_digits=19, db_column='PricePerItem', verbose_name='price per item', default=0)
onspecial = models.BooleanField(db_column='OnSpecial', verbose_name='on special', default=False)
discount = models.FloatField(null=True, db_column='Discount', blank=True, verbose_name='discounted', default=0)

#connections to other models
options = models.ManyToManyField(Option, null=True, through='OptionPrice', verbose_name='product options', blank=True)
optiongroups = models.ManyToManyField(OptionGroup, null=True, verbose_name='product option groups', blank=True)

package = models.ForeignKey(ShippingPackage, verbose_name='shipping container', default=1)
categories = models.ManyToManyField(Category, verbose_name='product categories')
cross_sell = models.ManyToManyField('Product', verbose_name='cross-sell items', blank=True)


#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class Option(models.Model):
optionid = UUIDField(db_column='OptionID', editable=False, primary_key=True, auto=True, hyphenate=True)
title = models.CharField(db_column='Title', max_length=500)
price = models.DecimalField(decimal_places=4, max_digits=19, db_column='Price')
pricemodstyle = models.CharField(db_column='PriceModStyle', max_length=50, verbose_name='price modification style', choices=PRICE_MOD_CHOICES)
displayrank = models.IntegerField(db_column='DisplayRank', verbose_name='sort order')
optiongroup = models.ForeignKey('OptionGroup', verbose_name='option group')



#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class OptionPrice(models.Model):
optionpriceid = UUIDField(db_column='OptionPriceID', editable=False, primary_key=True, auto=True, hyphenate=True)
option = models.ForeignKey(Option)
product = models.ForeignKey(Product)
price = models.DecimalField(decimal_places=4, max_digits=19, db_column='Price')
pricemodstyle = models.CharField(db_column='PriceModStyle', max_length=50, verbose_name='price modification style', choices=PRICE_MOD_CHOICES)

, and for the admin.py, I have the product options defined as being inline


#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class ProductAdmin(ImportExportModelAdmin):
resource_class = ProductResource
model=Product
ordering = ['categories__categoryname','productname']
save_on_top = True
save_as = True
inlines = [OptionPriceAdminInline]

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class OptionPriceAdminInline(admin.TabularInline):
model=OptionPrice
extra = 0
save_on_top = True

My issue is that when I load a product in the administrator, the inlines show up beautifully, with every field represented except the primary key (optionpriceid). Consequently, the first time I add options to this product, they save properly (new id is created automagically). If I then attempt to reload the product and edit the saved options, I get a MultiValueDictKeyError because these inlined items don't actually have their primary key values included in the rows emitted by the admin.


What am I doing wrong?



The issue turned out to be a django bug, solved by this pull request. The problem is that I was using a custom UUIDField as the primary key - to quote the ticket:



It seems to be that this this problem happens for models which have a primary key field that is not based on the AutoField (such as a CharField).


When the primary key field is not based on an AutoField 'has_auto_field' is not set to True, therefore it will not output the primary key in the form.



Related Posts:

0 commentaires:

Enregistrer un commentaire