let's see if I can ask the questions correctly?
model.py
class Point(models.Model):
name = models.CharField(
"nome del sistema",
max_length=128,
)
x = models.FloatField(
"cordinata spaziale x",
)
y = models.FloatField(
"cordinata spaziale y",
)
z = models.FloatField(
"cordinata spaziale z",
)
distance = float(0)
def __str__(self) -> str:
return f"{self.name}"
@property
def get_distance(self):
return self.distance
@get_distance.setter
def get_distance(self, point):
"""
ritorna la distanza che ce tra due sistemi
"""
ad = float((point.x-self.x) if point.x > self.x else (self.x-point.x))
bc = float((point.y-self.y) if point.y > self.y else (self.y- point.y))
af = float((point.z-self.z) if point.z > self.z else (self.z-point.z))
return (pow(ad,2)+pow(bc,2)+pow(af,2))**(1/2)
class Meta:
verbose_name = "point"
verbose_name_plural = "points"
in the particular model there are two defs which calculate, save and return the distance with respect to the point we pass them
wenws.py
class PointViewset(viewsets.ModelViewSet):
"""
modelo generico per un systema
"""
queryset = Point.objects.all()
serializer_class = PointSerializers
filterset_class = PointFilter
in the wenws not that much particular to explain and base base the only thing we have to say and that as filters I use 'django_filters'
filters.py
import django_filters as filters
import Point
class CustomOrderFilter(filters.CharFilter):
def filter(self, qs:QuerySet, value):
if value in ([], (), {}, '', None):
return qs
try:
base = qs.get(name=value)
for point in qs:
point.get_distance = base
qs = sorted(qs, key= lambda x: x.get_distance)
except Point.DoesNotExist:
qs = qs.none()
return qs
class PointFilter(filters.rest_framework.FilterSet):
security = filters.ChoiceFilter(choices=security_choices
point= CustomCharFilter(
label = "point"
)
class Meta:
model = Point
fields = {
'name':['exact'],
}
now the complicated thing with 'CustomCharFilter' I pass in the http request the name of the system which then returns to me in the filter as value after I check that it is not empty and I start with returning the point that I have passed with base = qs.get ( name = value)
to then calculate and save the distance for each point with point.get_distance = base '' on the inside of the for, at the end I reorder the QuerySet with
qs = sorted (qs, key = lambda x: x.get_distance) '' the problem that both with this way and with another that I have tried the QuerySet it 'transforms' into a list and this does not suit me since I have to return a QuerySet in the order of here I want. I don't know how to do otherwise, since order_by I can't use it since the distance is not inside the database
can someone help me?
So the problem is that you want to filter from a python function which cant be done in a query, as they only speak SQL.
The easy slow solution is to do the filtering in python, this might work if there are just a few Points.
points = list(Point.objects.all())
points.sort(cmp=comparison_function)
The actual real solution is to port that math to Djangos ORM and annotate your queryset with the distance to a given point, this is quite an advanced query, If you tell us your database server you use we can probably help you with that too.
ps. There is an abs()
function in python to get absolute value instead of the if/else in get_distance