I am using Django 1.7 and I working with REST Framework, I have implemented a simple API to get all the objects in a Model, but i want to filter the result putting a foreign object value.
For example, actually I can have a list of Objects with this URL
http://localhost:8000/api/ocompradetalle
and if I want only one, i only can put the PK (PrimaryKey) like this
http://localhost:8000/api/ocompradetalle/1/
I want to change the primary key to filter by a Foreign field value, I mean, I have a document (OCompra) with a value on the "folio" field, this document will have many details (OCompraDetalle), so, I want to be able to put something like this:
http://localhost:8000/api/ocompradetalle/F2033
being "F2033" a "folio" value and the response should bring me all the details of the OCompra Object with this value in the "folio" field.
this is what I have at the moment.
urls.py >> I have the router that takes the ViewSets
from rest_framework import routers
from inventario_rfid.views import OCompraViewSet, OCompraDetalleViewSet
from administracion.views import ProductoViewSet
router = routers.DefaultRouter()
router.register(r'ocompra',OCompraViewSet)
router.register(r'ocompradetalle',OCompraDetalleViewSet)
router.register(r'producto',ProductoViewSet)
urlpatterns = patterns('',
...
#APIS
url(r'^api/',include(router.urls)),
)
serializers.py
from rest_framework import serializers
from administracion.serializers import ProductoSerializer
from .models import OCompra, OCompraDetalle
class OCompraSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = OCompra
fields = ('folio','codigo_proveedor','nombre_proveedor','status','fecha','subtotal','iva','envio',
'otro','total',)
class OCompraDetalleSerializer(serializers.HyperlinkedModelSerializer):
producto = ProductoSerializer(many=False)
ocompra = OCompraSerializer(many = False) << I WANT TO FILTER BY THIS (ocompra__folio)
class Meta:
model = OCompraDetalle
fields = ('ocompra','producto','cantidad_ordenada','cantidad_recibida','fecha_entrega','precio','epc')
views.py
class OCompraDetalleViewSet(viewsets.ModelViewSet):
queryset = OCompraDetalle.objects.all()
serializer_class = OCompraDetalleSerializer
class OCompraViewSet(viewsets.ModelViewSet):
queryset = OCompra.objects.all()
serializer_class = OCompraSerializer
models.py
class OCompra(models.Model):
folio = models.CharField(max_length=15)
codigo_proveedor = models.CharField(max_length=15)
nombre_proveedor = models.CharField(max_length=100)
status = models.IntegerField(default=0)
fecha = models.DateTimeField(auto_now_add=True)
usuario = models.ForeignKey(User)
subtotal = models.DecimalField(default=0,decimal_places=2, max_digits=20)
iva = models.DecimalField(default=0,decimal_places=2, max_digits=20)
envio = models.DecimalField(default=0,decimal_places=2, max_digits=20)
otro = models.DecimalField(default=0,decimal_places=2, max_digits=20)
total = models.DecimalField(default=0,decimal_places=2, max_digits=20)
def __unicode__(self):
return self.folio
class OCompraDetalle(models.Model):
ocompra = models.ForeignKey(OCompra,related_name='detalles')
producto = models.ForeignKey(Producto)
cantidad_ordenada = models.DecimalField(default=0,decimal_places=2, max_digits=10)
cantidad_recibida = models.DecimalField(default=0,decimal_places=2, max_digits=10)
fecha_entrega = models.DateField(blank=True,null=True)
precio = models.DecimalField(default=0,decimal_places=2, max_digits=10)
epc = models.CharField(max_length=25,null=True,blank=True)
The simplest way to filter the queryset of any view that subclasses GenericAPIView is to override the . get_queryset() method. Overriding this method allows you to customize the queryset returned by the view in a number of different ways.
The root QuerySet provided by the Manager describes all objects in the database table. Usually, though, you'll need to select only a subset of the complete set of objects. The default behavior of REST framework's generic list views is to return the entire queryset for a model manager.
Django REST framework allows you to combine the logic for a set of related views in a single class, called a ViewSet . In other frameworks you may also find conceptually similar implementations named something like 'Resources' or 'Controllers'.
APIView and ViewSet all have their right use cases. But most of the time, if you are only doing CRUD on resources, you can directly use ViewSets to respect the DRY principle. But if you are looking for more complex features, you can go low-level because after all, viewsets are also a subclass of APIView .
Ok, so if I'm understanding correctly you want to be able to filter on a list of OCompraDetalle objects AND be able to set the lookup field to a value in a joined table (Ocompra). This viewset should do both for you
from rest_framework import filters
OCompraDetalleViewSet(viewsets.ModelViewSet):
filter_backends = (filters.DjangoFilterBackend,)
filter_fields = ('precio','ocompra__envio')
serializer_class = OCompraDetalleSerializer
queryset = OCompraDetalle.objects.all()
lookup_field = "ocompra__folio"
So:
http://localhost:8000/api/ocompradetalle/1/
will give you the ocompradetalle object where ocompradetalle.ocompra.folio is equal to 1. This will only work if the mapping is one-to-one or the folio column has a unique index. Detail views cannot return more than one object
If you would like to filter by a column on a joined table you could do:
http://localhost:8000/api/ocompradetalle/?ocompra__envio=blah
And you will get all the ocompradetalles where ocompradetalle.ocompra.envio = blah
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With