2017-10-17 6 views
0

J'ai un modèle simple maître/détail de Citation (Master) contenant les informations d'en-tête et les totaux, et QuotationDetail (détail) contenant les articles de devis, ce modèle enfant a un champ PriceLevel FK utilisé pour calculer le balisage pour chaque article individuel. Je suis en train de mettre en œuvre une action d'administration de Django si l'administrateur peut modifier ce pricelevel sur plusieurs éléments à la fois, mais je reçois l'erreur:Python Django 1.11 "ValueError Format incomplet" dans l'action admin lorsque vous essayez de mettre à jour le terrain FK

[myProjectPath]\lib\site-packages\django\contrib\admin\options.py", line 812, in get_action_choices 
    choice = (name, description % model_format_dict(self.opts)) 
ValueError: incomplete format 

Ceci est mon models.py (sur les modèles concernés):

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) 

Ceci est mon admin.py: (J'ai aussi essayé la version commentée de l'action avec la même erreur résultant). Ce serait bien de pouvoir choisir des options pour ce changement du modèle FK, mais je vais me contenter de le faire en ayant deux actions: une pour augmenter la valeur de balisage de .05% et une autre pour diminuer la marge de .05% dans dans quels cas j'aurais besoin de mettre à jour le champ de balisage à la place.

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) 

Mise à jour:

... essayé ceci:

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

comme suit dans mon 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()) 

Mais je reçois la même erreur, retraçage montré ici: http://dpaste.com/360GEJY

Le même extrait fonctionne très bien lorsque le champ de mise à jour n'est pas un champ de clé étrangère . Je l'ai utilisé dans un autre modèle et fonctionne très bien:

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) 

Répondre

0

J'ai trouvé l'erreur, après de nombreux essais, le problème est dans l'utilisation du symbole % de à l'intérieur du contenu d'un champ de description, Apparemment, lors de la création dynamique d'actions , la chaîne short_description générée est réutilisée et si elle comporte un signe%, elle renvoie l'erreur de format Incomplet.

La solution était de construire la chaîne short_description comme ceci:

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

... notez le (échappé) signe double%