Search code examples
pythondjangodjango-modelsdjango-generic-viewsdjango-polymorphic

Controlling PolymorphicModel classed object as model in Generic view


I have a PolymorphicModel class named Vehicle, and I derived two class from this: Car and Truck.

I use UpdateView to update but it's getting vehicle_id from vehicle_list randomly. And I have to control which type of vehicle is this model. But I couldn't.

My classes:

class Vehicle(PolymorphicModel):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False, verbose_name="ID")


class Car(Vehicle):
    car_license = models.CharField(max_length=32)


class Truck(Vehicle):
    truck_license = models.CharField(max_length=32)

In view:

class VehicleUpdate(UpdateView):
    car = object
    if car.car_license is not None:
        model = Car
    else:
        model = Truck
    fields = '__all__'

    def get_success_url(self, **kwargs):
        return reverse_lazy('person-list')

But it's giving this error:

AttributeError: type object 'object' has no attribute 'tr_id'

By the way, I tried to use "isinstance()" but it didn't work. Maybe it's about being PolymorphicModel, I don't know.

class VehicleUpdate(UpdateView):
    if isinstance(object, Car):
        model = Car
    else:
        model = Truck
    fields = '__all__'

    def get_success_url(self, **kwargs):
        return reverse_lazy('person-list')

Solution

  • Code at the class top level (outside a function definition) is executed when the class statement is executed - which is, usually (=> when the class is defined at the module's top level), when the module is imported. This means that at this point, object is most probably the builtin object class, or whatever has been bound to the name "object" previously in the module, and definitly not a Vehicle instance.

    I seldom use class-based-views (most of the time a plain function view is by far easier to write / read / modify than a CBV) and never use generic CBVs so I can't tell for sure but from the doc it looks like trying to set the class's model attribute from the current instance (self.object - of course only available from with a method) is not going to work since the mechanism that gets this instance relies on the model attribute...

    As a side note, if the only difference between you Car and Truck classes is the name of the licence field, then really it's very poor design as it actually breaks liskov substitution principle for no good reason.