Python Django 1.11 在尝试更新 FK 字段时在管理员操作中"ValueError Incomplete format"



我有一个简单的主/细节模型,包含标题信息和总计的Quotation(master)和包含报价项目的QuotationDetail1(detail),此子模型有一个PriceLevel FK字段用于计算每个单独项目的标记。我正在尝试实现Django管理员操作,这样管理员就可以同时更改几个项目的价格级别,但我得到了错误:

[myProjectPath]libsite-packagesdjangocontribadminoptions.py", line 812, in get_action_choices
choice = (name, description % model_format_dict(self.opts))
ValueError: incomplete format

这是我的型号。py(在相关型号上):

class NivelDePrecio(models.Model):    # PriceLevel
# Fields
nombre = models.CharField(max_length=50)
slug = extension_fields.AutoSlugField(populate_from='nombre', blank=True)
valor = models.DecimalField(max_digits=7, decimal_places=4)
factor = models.DecimalField(max_digits=7, decimal_places=6, null=True, blank=True)
class Meta:
ordering = ('-valor',)
def __str__(self):
return self.nombre
def save(self, *args, **kwargs):
self.factor = 1 / (1 - self.valor)
super(NivelDePrecio, self).save()

class Cotizacion(models.Model):   # Quotation (master)
# Fields
nombre = models.CharField(max_length=100)
slug = extension_fields.AutoSlugField(populate_from='nombre', blank=True, overwrite=True)
fecha_ida = models.DateField(default=date.today)
fecha_regreso = models.DateField(default=date.today)
# Relationship Fields
itinerario = models.ForeignKey(Itinerario, on_delete=CASCADE, verbose_name='itinerario')
nivel_de_precio = models.ForeignKey(NivelDePrecio, verbose_name='nivel de precio',
on_delete=models.PROTECT, null=True, blank=True)
class Meta:
ordering = ('itinerario__cliente__codigo', '-fecha_ida')
def __str__(self):
return str(self.nombre)

class CotizacionDetalle(models.Model):  # QuotationDetail (detail)
# Fields
descripcion = models.CharField(max_length=100, null=True, blank=True)
cantidad = models.DecimalField(max_digits=10, decimal_places=2)
costo = models.DecimalField(max_digits=10, decimal_places=2, default=0, editable=False)
monto = models.DecimalField(max_digits=10, decimal_places=2, default=0, editable=False)
markup = models.DecimalField(max_digits=6, decimal_places=4, default=0, editable=False)
utilidad = models.DecimalField(max_digits=6, decimal_places=4, default=0, editable=False)
total = models.DecimalField(max_digits=10, decimal_places=2, default=0, editable=False)
slug = extension_fields.AutoSlugField(populate_from='item', blank=True)
# Relationship Fields
cotizacion = models.ForeignKey(Cotizacion, on_delete=CASCADE, verbose_name='cotizacion', related_name='lineas')
item = models.ForeignKey(Item, verbose_name='item', related_name='item')
nivel_de_precio = models.ForeignKey(NivelDePrecio, verbose_name='nivel de precio',
on_delete=models.PROTECT, null=True, blank=True)
class Meta:
ordering = ('id',)
def save(self, *args, **kwargs):
self.descripcion = self.item.descripcion_venta
self.costo = self.item.costo
self.monto = self.cantidad * self.costo
if self.nivel_de_precio is None:
self.nivel_de_precio = self.cotizacion.nivel_de_precio
self.markup = Decimal(round(self.nivel_de_precio.factor - 1, 4)).quantize(Decimal("0.0000"))
self.utilidad = Decimal(self.nivel_de_precio.valor).quantize(Decimal("0.0000"))
self.total = Decimal(self.monto) * (1 + Decimal(self.markup))
super(CotizacionDetalle, self).save(*args, **kwargs)
def __str__(self):
return str(self.descripcion)

这是我的admin.py:(我也尝试过该操作的注释版本,但出现了相同的错误)。如果能够从FK模型中选择此更改的选项,那将是一件好事,但我将通过两个操作来实现它:一个是将标记值增加.05%,另一个是减少.05%,在这种情况下,我需要更新标记字段。

class CotizacionDetalleAdminForm(forms.ModelForm):
class Meta:
model = CotizacionDetalle
fields = ['item', 'cotizacion', 'cantidad', 'nivel_de_precio']

def cambiar_utilidad(modeladmin, request, queryset):
from .models import NivelDePrecio
ndp = NivelDePrecio.objects.get(id=5)
queryset.update(nivel_de_precio_id=ndp.id)
# for cd in queryset:
#     cd.nivel_de_precio_id = ndp.id
#     cd.save()

cambiar_utilidad.short_description = "Cambiar Utilidad 25%"

class CotizacionDetalleAdmin(admin.ModelAdmin):
# save_as = True
form = CotizacionDetalleAdminForm
list_display = ['cliente', 'itinerario', 'cotizacion', 'descripcion',
'cantidad', 'costo', 'monto', 'utilidad', 'markup', 'total']
list_display_links = ['descripcion']
readonly_fields = ['descripcion', 'costo', 'monto', 'utilidad', 'markup', 'total', 'slug', 'creado', 'actualizado']
search_fields = ['descripcion']
list_filter = (('cotizacion__itinerario__cliente', DropdownFilterRelated),
('cotizacion__itinerario', DropdownFilterRelated),
('cotizacion', DropdownFilterRelated),)
ordering = ['cotizacion__itinerario__cliente__codigo', 'cotizacion__fecha_ida', 'id']
actions = [cambiar_utilidad]

admin.site.register(CotizacionDetalle, CotizacionDetalleAdmin)

更新:

试过这个:

https://djangosnippets.org/snippets/1836/

如下所示,在我的admin.py

def create_action_nivel(nivel):
def action(modeladmin, request, queryset):
queryset.update(nivel_de_precio=nivel)
name = "change_to_%s" % (nivel.slug,)
return (name, (action, name, "Cambiar Nivel de Precio a: %s" % (nivel,)))

class CotizacionDetalleAdmin(admin.ModelAdmin):
def get_actions(self, request):
return dict(create_action_nivel(n) for n in NivelDePrecio.objects.all())

但我得到了同样的错误,这里显示了回溯:http://dpaste.com/360GEJY

当要更新的字段不是外键字段时,相同的代码段也可以正常工作。我在另一个模型中使用了它,效果很好:

def create_action_estatus(estatus):
def action(modeladmin, request, queryset):
queryset.update(estatus=estatus)
name = "mark_%s" % (estatus,)
return name, (action, name, "Cambiar Estatus: %s " % (estatus,))

class ItinerarioAdmin(admin.ModelAdmin):
def get_actions(self, request):
statuses= [ "Solicitado", "Cotizado", "Confirmado", "Facturado", "Cerrado"]
return dict(create_action_estatus(e) for e in statuses)

我发现了这个错误,经过多次尝试,问题是在描述字段的内容中使用%符号,显然是在创建时管理员动态操作short_description生成的字符串将被重用,如果其中有一个%符号,则会抛出不完整格式错误。

解决方案是构建short_description字符串,如下所示:

cambiar_nivel.short_description = "Cambiar Nivel de Precio a {0:.1f}%%".format(nivel.valor * 100)

注意(转义的)双%符号

最新更新