Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to filter through Model of a many-to-many field?

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!

like image 470
Du D. Avatar asked Jun 10 '16 14:06

Du D.


People also ask

How do you use ManyToMany fields?

A ManyToMany field is used when a model needs to reference multiple instances of another model. Use cases include: A user needs to assign multiple categories to a blog post. A user wants to add multiple blog posts to a publication.

How fetch data from ManyToMany field in Django?

A ManyToManyField in Django is a field that allows multiple objects to be stored. This is useful and applicable for things such as shopping carts, where a user can buy multiple products. To add an item to a ManyToManyField, we can use the add() function.

What is through in Django models?

The through attribute/field is the way you customize the intermediary table, the one that Django creates itself, that one is what the through field is changing.

How do I create a many-to-many relationship in Django?

To define a many-to-many relationship, use ManyToManyField . What follows are examples of operations that can be performed using the Python API facilities. You can't associate it with a Publication until it's been saved: >>> a1.


1 Answers

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 a ManyToManyField with a custom intermediate table specified using the through 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:

  1. 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()
    
  2. Have through='VehicleBounddaryMapProxy' on your ManyToManyField:

     class Vehicle(SoftDeleteModel):
        routes = models.ManyToManyField('RouteBoundary', 
                                         through='VehicleBoundaryMapProxy', 
                                         verbose_name=_('routes'))
    
like image 148
Louis Avatar answered Nov 06 '22 16:11

Louis