How to filter many-to-many fields through a model?

I’m trying to implement a geoprocessing for a truck fleet. I need to associate a border list with a vehicle. In addition, one of the requirements is everything, even when it is removed for audit purposes. Therefore, we must implement soft removal in everything. This is where the problem lies. My many field does not correspond to the soft deletion manager, it includes both active and inactive entries in the search 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 that the default manager is the soft deletion manager (i.e. the filter is only for active records), and also try to use limit limit_choices_to, but this goes beyond the foreign model, the model I wanted . If you have any suggestions or recommendations that I would like to hear from you.

Thanks!

+6
source share
2 answers

First problem: using limit_choices_to will not work, because the documentation says:

limit_choices_to does not work when used in ManyToManyField with a custom staging table specified using the through parameter.

You use through , so limit_choices_to has no effect.

Second problem: your use of use_for_related_fields = True also inefficient. The documentation says about this attribute:

If this attribute is set in the default manager for the model (only the default manager is considered in these situations), Django will use this class whenever it needs to automatically create a manager for this class.

Your user manager is assigned to the alive VehicleBoundaryMap attribute, not objects , so it is ignored.

One way that I see may work:

  • Create a proxy model for VehicleBoundaryMap . Let me call it VehicleBoundaryMapProxy . Set it so that its default manager is SoftDeleteManager() Something like:

     class VehicleBoundaryMapProxy(VehicleBoundaryMap): class Meta: proxy = True objects = SoftDeleteManager() 
  • You have through='VehicleBounddaryMapProxy' on ManyToManyField :

      class Vehicle(SoftDeleteModel): routes = models.ManyToManyField('RouteBoundary', through='VehicleBoundaryMapProxy', verbose_name=_('routes')) 
+5
source

How about if you just do:

 class Vehicle(SoftDeleteModel): #you can even remove that field #routes = models.ManyToManyField('RouteBoundary', through='VehicleBoundaryMap', verbose_name=_('routes'), # limit_choices_to={'active': True}) @property def routes(self): return RouteBoundary.objects.filter( vehicleboundarymap__active=True, vehicleboundarymap__vehicle=self, ) 

Now instead of vehicle.routes.clear() use vehicle.vehicleboundarymap_set.delete() . You will lose the inverse relation ( RouteBoundary.vehicles ), but you can implement it using the same method.

Other functions of the M2M field disabled in any case due to the intermediate model.

+1
source

All Articles