1👍
You can make a QuerySet
that renders with:
from django.db.models import Q
class ComparisonView(viewsets.ModelViewSet):
serializer_class = ComparisonSerializer
queryset = Comparison.objects.all()
def get_queryset(self):
h1 = self.request.query_params.get('hash1')
h2 = self.request.query_params.get('hash2')
return self.queryset.filter(
Q(hash1=h1, hash2=h2) |
Q(hash1=h2, hash2=h1)
)
Finally, one other small annoyance is that ideally I want to return a single object, while currently filter returns a list containing a single object for a unique hash pair.
This is because you use the list
function of the ModelViewSet
. The viewset will retrieve an object if you specify a primary key (of the Comparison
).
What you can do is working with a RetrieveAPIView
[drf-doc], and override the .get_object()
method [drf-doc]:
from django.db.models import Q
from django.shortcuts import get_object_or_404
from rest_framework.generics import RetrieveAPIView
class ComparisonView(RetrieveAPIView):
serializer_class = ComparisonSerializer
queryset = Comparison.objects.all()
def get_object(self):
h1 = self.request.query_params.get("hash1")
h2 = self.request.query_params.get("hash2")
return get_object_or_404(
self.queryset,
Q(hash1=h1, hash2=h2) |
Q(hash1=h2, hash2=h1)
)
You might want to add an extra constraint that hash1
is always less than or equal to hash2
, this thus prevent retrieving two items, since it might be possible that there exists a Comparison
for hash1=h1
and hash2=h2
; and one for hash1=h2
and hash2=h1
. You can add a CheckConstraint
with:
from django.db.models import Q, F
class Comparison(models.Model):
result = models.FloatField()
hash1 = models.CharField(max_lModelViewSetength=100)
hash2 = models.CharField(max_length=100)
class Meta:
constraints=[
models.UniqueConstraint(fields=['hash1','hash2'], name='compared'),
models.CheckConstraint(check=Q(hash1__lte=F('hash2')), name='symmetry')
]
In that case the create logic should determine which of the two hashes is the smallest. It also means that you can query simply by first ordering h1
and h2
with:
from rest_framework.generics import RetrieveAPIView
class ComparisonView(RetrieveAPIView):
serializer_class = ComparisonSerializer
queryset = Comparison.objects.all()
def get_object(self):
h1 = self.request.query_params.get('hash1')
h2 = self.request.query_params.get('hash2')
if h1 is not None and h2 is not None:
h1, h2 = sorted((h1, h2))
return get_object_or_404(
self.queryset, hash1=h1, hash2=h2
)