Model method to get related objects from manytomany relationship

Hi, i have a model with a manytomany relationship to another and i would like to know if it is possible to set a method to get all of these related objects (If possible with attribute filtering to get only certain fields in the results).

I have this model: 

class Pedido(models.Model):
    """Clase que crea instancias de pedidos en la base de datos"""
    ESTATUS_PEDIDO= [
        ('ENPROCESO', 'Pedido en Proceso'),
        ('CANCELADO', 'Pedido Cancelado'), 
        ('COMPLETADO','Pedido Completado'),
    ]
    cliente = models.ForeignKey(User, related_name='cliente', on_delete=models.CASCADE)
    repartidor = models.ForeignKey(User, related_name='repartidor', on_delete=models.CASCADE, blank=True, null=True)
    direccion_de_recogida = models.CharField(max_length=50)
    direccion_de_entrega = models.CharField(max_length=50)
    hora_de_recogida = models.TimeField(auto_now=False)
    estado = models.CharField(max_length=15, choices=ESTATUS_PEDIDO, default='ENPROCESO')
    informacion_extra = models.TextField(max_length=50, blank=True, null=True)
    tiempo_de_reparto = models.CharField(max_length=10, blank=True, null=True)
    fecha_creacion = models.DateTimeField(auto_now_add=True)
    costo_pedido = models.FloatField(blank=True, null=True)

And this other with a manytomany relationship:
class OrdenDeServicio(models.Model):
    """Clase que crea la orden del servicio. Incluye una relaciĂłn many to many a los pedidos y una foreignk key al cliente"""
    ESTATUS_ORDEN = [
        ('ENPROCESO', 'Orden en Proceso'),
        ('ENREPARTO', 'Orden en Reparto'),
        ('CANCELADA', 'Orden Cancelada'),
        ('COMPLETADA','Orden Completada'),
    ]
    cliente = models.ForeignKey(User, related_name='orden_cliente', on_delete=models.CASCADE)
    **pedido = models.ManyToManyField(Pedido, related_name='pedidos')**
    estado = models.CharField(max_length=10, choices=ESTATUS_ORDEN, default='ENPROCESO')
    payment_intent_id= models.CharField(max_length=300, blank=True, null=True)
    total_a_pagar = models.FloatField(max_length=4, blank=True, null=True)
    forma_de_pago = models.CharField(max_length=30, blank=True, null=True)
    creada = models.DateTimeField(auto_now=True)
    pagada = models.DateTimeField(auto_now_add=False, blank=True, null=True)

    def __str__(self):
        return f'Cliente: {self.cliente} - NĂşmero de Orden: {self.id} '

I would like to create a function in OrdenDeServicio which makes what i’ve mentioned above, let’s say i want to get all the related Pedido instances “direccion_de_entrega” to put them into a list and use them in a view.

Thans, i appreciate your help.
Cheers.

You filter through a ManyToMany relationship the same way as you filter any other foreign key related table - using the “double underscore” notation to follow the references.

So for example, you could create a query like this:

orden_de_servicio = OrdenDeServicio.objects.filter(pedido__direccion_de_entrega = "Some value to match")

That will give you all OrdenDeServicio objects relating to a Pedido object with a direccion_de_entrega attribute that equals “Some value to match”.

Or, if you want the Pedido objects having a direccion_de_entrega attribute that equals “Some value to match” and that are related to a specific OrdenDeServicio, your query could be:

Pedido.objects filter(direccion_de_entrega="Some value to match", pedidos=a_orden_de_servicio_object_id)

(This uses the related name attribute you specified in the field definition since you’re following the ForeignKey “backwards”.)

1 Like

Amazing!!
Actually what i’ve done is:

Get the active  order

 orden_activa = OrdenDeServicio.objects.filter(cliente=request.user.id, estado='ENPROCESO').first()
(Would it work the same if i use "get" above  and not writing .first??)

Then i get all Pedidos for that order:

pedidos_detalle = orden_activa.pedido.all()

I have a last question (and sorry for being so newbie), what if i would like to get from these “pedidos” a couple of fields, let’s say,
“direccion_de_recogida” and “direccion_de_entrega”, is there a way to do a query and return only two fields from the DB?

Thanks again, and i have to say it’s amazing how quick you answer!
Great Job :smiley:

The difference between the two styles is that the “get” throws an error if either:

  • There is no row matching the filter
  • There is more than one row matching the filter

Using the filter clause with the first function prevents the error from being thrown. You either get the first row matching the filter or None. (It’s then up to you to determine what happens if no row is returned.)
The choice between them depends upon the application’s requirements.

There is no need to apologize. We all started somewhere at some time.

You’ve got two different options depending upon what exactly you want returned from the query (and perhaps what you might want to subsequently do with that queryset).

  • .only() - returns a queryset for the objects with only those fields populated
  • .values() (or .values_list()) - returns a dict (or tuple) of the requested values.
1 Like

Great!! Thank you Ken!! That covers all my doubts, have a nice day.
Cheers.