DRF polymorphic many-to-many with extra fields

172 Views Asked by At

I'm tinkering around with Django Rest Framework to build an api that can handle Bills of Materials (BoM) of electronic components.

I'm using django-polymorphic and django-rest-polymorphic so I can use polymorphic models for the components (they have shared attributes, but I still want to handle them in much the same way. The polymorphic models are great for this purpose).

All is well and good until I introduce many-to-many relations with a 'through' attribute. What I would like is a BoM that has several different components, each with a quantity, e.g. BoM1 has 2x470k resistor & 3x 100uF capacitor.

models.py: (pruned a bit to keep this post from being an epic novel)

class BoM(models.Model):
    """Bill of Materials: a list of all parts and their quantities for a given pedal"""
    pedal = models.ForeignKey(Pedal, on_delete=models.CASCADE)
    variant = models.CharField(max_length=100, blank=True)
    electronic_components = models.ManyToManyField(
        'ElectronicComponent', through='ElectronicComponentQty', blank=True)

    class Meta:
        verbose_name = 'Bill of materials'
        verbose_name_plural = 'Bills of materials'

    def __str__(self):
        return str(self.pedal)


class ElectronicComponent(PolymorphicModel):
    """Shared data model for electronic components"""
    value = models.CharField(max_length=20)
    datasheet = models.FileField(upload_to='uploads/components', blank=True)

    def __str__(self):
        return self.value


class ElectronicComponentQty(models.Model):
    """Combination of resistor and quantity"""
    bom = models.ForeignKey(BoM, on_delete=models.CASCADE)
    component = models.ForeignKey(
        ElectronicComponent, on_delete=models.CASCADE)
    quantity = models.PositiveIntegerField(default=1)

    class Meta:
        verbose_name = 'Elecronic component quantity'
        verbose_name_plural = 'Electronic component quantities'


class Resistor(ElectronicComponent):
    """Resistor data model"""
    WATTAGES = [('1/4w', '1/4w'), ('1/8w', '1/8w')]

    wattage = models.CharField(max_length=4, choices=WATTAGES, default='1/4w')



class Capacitor(ElectronicComponent):
    """Capacitors (all kinds)"""
    VOLTAGE_RATINGS = [
        ('16V', '16V'),
        ('35V/50V', '35V/50V'),
    ]

    CAP_TYPES = [
        ('ceramic disk', 'ceramic disk'),
        ('film', 'film'),
        ('electrolytic', 'electrolytic'),
        ('tantalum', 'tantalum'),
        ('other', 'other'),
    ]

    capacitor_type = models.CharField(
        max_length=20, choices=CAP_TYPES, default='film')
    voltage_rating = models.CharField(
        max_length=10, choices=VOLTAGE_RATINGS, blank=True)

serializers.py:

class ElectronicComponentSerializer(serializers.ModelSerializer):
    class Meta:
        model = ElectronicComponent
        fields = '__all__'


class ElectronicComponentQtySerializer(serializers.ModelSerializer):
    class Meta:
        model = ElectronicComponentQty
        fields = '__all__'


class BoMSerializer(serializers.ModelSerializer):
    electronic_components = ElectronicComponentQtySerializer(
        many=True, read_only=True)

    class Meta:
        model = BoM
        fields = '__all__'

class ResistorSerializer(serializers.ModelSerializer):
    class Meta:
        model = Resistor
        fields = '__all__'


class CapacitorSerializer(serializers.ModelSerializer):
    class Meta:
        model = Capacitor
        fields = '__all__'


class ElectronicComponentPolySerializer(PolymorphicSerializer):
    model_serializer_mapping = {
        Resistor: ResistorSerializer,
        Capacitor: CapacitorSerializer,
    }

With this code I can create EletronicComponentQty objects no problem. However, when I try to list the BoM (through the serializer), I get: AttributeError at /pedalparts/boms/ Got AttributeError when attempting to get a value for field bom on serializer ElectronicComponentQtySerializer. The serializer field might be named incorrectly and not match any attribute or key on the Capacitor instance. Original exception text was: 'Capacitor' object has no attribute 'bom'.

Anyone know how I can solve this? I'm open to any changes that make this work.

1

There are 1 best solutions below

0
On

As electronic_components on the BoM model refers to the ElectronicComponent model it should not use the ElectronicComponentQtySerializer but one that can serialize the right instances, most likely the ElectronicComponentSerializer or the ElectronicComponentPolySerializer.