I'm trying to avoid making another end-point to handle this query, but thinking there isn't a way around it. Wanted to run it by ya'll before doing so.
Basically, I have Documents related to Customers and Products. I want to retrieve only the Documents for a specific Customer and Product.
Here are the views.py
:
class DocumentsViewSet(viewsets.ModelViewSet):
filter_backends = [StrictDjangoFilterBackend]
filterset_fields = [
'id',
'filename',
]
queryset = Documents.objects.all()
serializer_class = DocumentsSerializer
class DocumentToCustomerViewSet(viewsets.ModelViewSet):
filter_backends = [StrictDjangoFilterBackend]
filterset_fields = [
'id',
'customer_id',
'document_id'
]
queryset = DocumentToCustomer.objects.all()
serializer_class = DocumentToCustomerSerializer
class DocumentToProductViewSet(viewsets.ModelViewSet):
filter_backends = [StrictDjangoFilterBackend]
filter_fields = [
'id',
'product_id',
'document_id'
]
queryset = DocumentToProduct.objects.all()
serializer_class = DocumentToProductSerializer
I'm thinking I can do something like this shorthand:
class DocumentsViewSet(viewsets.ModelViewSet):
filter_backends = [StrictDjangoFilterBackend]
filterset_fields = [
'id',
'filename'
]
queryset = Documents.objects.filter(document_to_product__product_id=id, document_to_customer__customer_id=id)
serializer_class = DocumentsSerializer
Which does seem to work when I tested it.
But then it I think I'd need to make another end-point to accommodate both the .all()
and .filter()
... I think.
Additionally, haven't been able to get the filter_fields = []
to work with the relationship either. Trying to do something like /api/documents/?customer_id=123&product_id=123
.
I get a: TypeError: 'Meta.fields' must not contain non-model field names:
Here are the models for additional information:
class Documents(models.Model):
id = models.UUIDField(primary_key=True, null=False)
filename = models.CharField(max_length=255, null=False)
class Meta:
db_table = 'documents'
class DocumentToProduct(models.Model):
product_id = models.ForeignKey(
Product,
on_delete=models.CASCADE,
db_column='product_id'
)
document_id = models.ForeignKey(
Documents,
on_delete=models.CASCADE,
db_column='document_id'
)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
class Meta:
db_table = 'document_to_product'
unique_together = [['product_id', 'document_id']]
class DocumentToCustomer(models.Model):
customer_id = models.ForeignKey(
Customer,
on_delete=models.CASCADE,
db_column='customer_id'
)
document_id = models.ForeignKey(
Documents,
on_delete=models.CASCADE,
db_column='document_id'
)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
class Meta:
db_table = 'document_to_customer'
unique_together = [['document_id', 'customer_id']]
Any suggestions for how to keeps this clean or will just have to add another end-point to handle this request?
Ok, think I have it sorted out after getting some sleep, RTFM, and stumbling across this response. Really was quite easy...
In order to get the relationships working with django-filter
I had to add related_name
attribute to the models like:
class Documents(models.Model):
id = models.UUIDField(primary_key=True, null=False)
filename = models.CharField(max_length=255, null=False)
class Meta:
db_table = 'documents'
class DocumentToProduct(models.Model):
product_id = models.ForeignKey(
Product,
on_delete=models.CASCADE,
db_column='product_id',
related_name='document_to_product'
)
document_id = models.ForeignKey(
Documents,
on_delete=models.CASCADE,
db_column='document_id',
related_name='document_to_product'
)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
class Meta:
db_table = 'document_to_product'
unique_together = [['product_id', 'document_id']]
class DocumentToCustomer(models.Model):
customer_id = models.ForeignKey(
Customer,
on_delete=models.CASCADE,
db_column='customer_id',
related_name='document_to_customer'
)
document_id = models.ForeignKey(
Documents,
on_delete=models.CASCADE,
db_column='document_id',
related_name='document_to_customer'
)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
class Meta:
db_table = 'document_to_customer'
unique_together = [['document_id', 'customer_id']]
Then I could update my filter_fields
like so:
class DocumentsViewSet(viewsets.ModelViewSet):
filter_backends = [StrictDjangoFilterBackend]
filterset_fields = [
'id',
'filename',
'document_to_customer__customer_id',
'document_to_product__product_id'
]
queryset = Documents.objects.all()
serializer_class = DocumentsSerializer
class DocumentToCustomerViewSet(viewsets.ModelViewSet):
filter_backends = [StrictDjangoFilterBackend]
filterset_fields = [
'id',
'customer_id',
'document_id'
]
queryset = DocumentToCustomer.objects.all()
serializer_class = DocumentToCustomerSerializer
class DocumentToProductViewSet(viewsets.ModelViewSet):
filter_backends = [StrictDjangoFilterBackend]
filter_fields = [
'id',
'product_id',
'document_id'
]
queryset = DocumentToProduct.objects.all()
serializer_class = DocumentToProductSerializer
Which allowed me allowed me to pass query parameters instead of adding additional ViewSets
, end-points, etc.
/api/documents/?document_to_customer__customer_id=2&document_to_product__product_id=10
This does what I was after and only returns the Documents for a specific customer and product.