I'm trying to implement a geofencing for a fleet of trucks. I have to associate a list of boundaries to a vehicle. On top of that one of the requirements is keep everything even once it is deleted for audit purposes. Therefore we have to implement soft delete on everything. This is where the problem lies. My many to many field does not conform to the soft delete manager, it includes both the active and the inactive records in the lookup dataset.
class Vehicle(SoftDeleteModel):
routes = models.ManyToManyField('RouteBoundary', through='VehicleBoundaryMap', verbose_name=_('routes'),
limit_choices_to={'active': True})
class VehicleBoundaryMap(SoftDeleteModel):
vehicle = models.ForeignKey(Vehicle, verbose_name="vehicle")
route_boundary = models.ForeignKey(RouteBoundary, verbose_name="route boundary")
# ... more stuff here
alive = SoftDeleteManager()
class SoftDeleteManager(models.Manager):
use_for_related_fields = True
def get_queryset(self):
return SoftDeleteQuerySet(self.model).filter(active=True)
As you see above I tried to make sure the default manager is a soft delete manager (ie. filter for active records only) and also try use limit limit_choices_to but that turn out to field the foreign model only not the "through" model I wanted. If you have any suggestions or recommendation I would love to hear from you.
Thanks!
First problem: your use of limit_choices_to
won't work because as the documentation says:
limit_choices_to
has no effect when used on aManyToManyField
with a custom intermediate table specified using thethrough
parameter.
You are using through
so limit_choices_to
has no effect.
Second problem: your use of use_for_related_fields = True
is also ineffective. The documentation says about this attribute:
If this attribute is set on the default manager for a model (only the default manager is considered in these situations), Django will use that class whenever it needs to automatically create a manager for the class.
Your custom manager is assigned to the alive
attribute of VehicleBoundaryMap
rather than objects
so it is ignored.
The one way I see which may work would be:
Create a proxy model for VehicleBoundaryMap
. Let's call it VehicleBoundaryMapProxy
. Set it so that its default manager is SoftDeleteManager()
Something like:
class VehicleBoundaryMapProxy(VehicleBoundaryMap):
class Meta:
proxy = True
objects = SoftDeleteManager()
Have through='VehicleBounddaryMapProxy'
on your ManyToManyField
:
class Vehicle(SoftDeleteModel):
routes = models.ManyToManyField('RouteBoundary',
through='VehicleBoundaryMapProxy',
verbose_name=_('routes'))