Как получить все объекты модели, связанные с исходным, даже если они находятся дальше, чем непосредственно связаны?
Возможно, название немного сбивает с толку, но я считаю, что объяснение будет намного понятнее.
У меня есть две модели
class AgrParameterUnits(models.Model):
Name = models.CharField(max_length=50, verbose_name=_("Name"))
ShortName = models.CharField(max_length=50, verbose_name=_("ShortName"))
class AgrParameterUnitConversions(models.Model):
ParrentParameterUnitId = models.ForeignKey(AgrParameterUnits, on_delete=models.DO_NOTHING, null=False, blank=False, db_column='ParrentParameterUnitId', related_name='ParrentParameterUnitId', primary_key=True, verbose_name=_("Parrent Parameter Unit Id"))
ChildParameterUnitId = models.ForeignKey(AgrParameterUnits, on_delete=models.DO_NOTHING, null=False, blank=False, db_column='ChildParameterUnitId', related_name='ChildParameterUnitId', verbose_name=_("Child Parameter Unit Id"))
ConversionCoefficent = models.DecimalField(max_digits=18, decimal_places=7, null=False, blank=False, db_column='ConversionCoefficent', verbose_name=_("Conversion Coefficent"))
Речь идет о преобразованиях между единицами измерения.
Сценарий следующий.
Я получаю одну единицу, и мне нужны все, которые так или иначе связаны с начальной единицей.
Пример:
в базе данных есть 3 AgrParameterUnits
записи и 2 AgrParameterUnitConversions
записи
AgrParameterUnits
записи:
Гц, килогерц, мегагерц.
AgrParameterUnitConversions
записи:
1 килогерц = 1000 Гц
1 Мегагерц = 1000 КилоГерц
Как бы выглядел запрос, если бы я хотел, задавая Герц, найти Килогерц и Мегагерц?
Это очень похоже на задачу рекурсии, с которой я пока не могу справиться. Вот что у меня есть на данный момент.
def _get_units(base_unit):
try:
"""Try to filter unit conversions where this the received unit is the parent unit"""
unit_choices = AgrParameterUnitConversions.objects.filter(ParrentParameterUnitId=base_unit).annotate(
unit_name=F('ParrentParameterUnitId__Name'),
unit_id=F('ParrentParameterUnitId'),
).values("unit_id", "unit_name")
related_units = AgrParameterUnitConversions.objects.filter(
ChildParameterUnitId=unit_choices[0]["unit_id"]).annotate(
unit_name=F('ParrentParameterUnitId__Name'),
unit_id=F('ParrentParameterUnitId'),
).values("unit_id", "unit_name")
units_this_round = (unit_choices | related_units).distinct()
except IndexError as e:
"""If the above filter fails on list index out of range, it means there is no conversion where this unit is a parent unit
In that cate try to filter for conversions, where it is as a child parameter unit.
If one of the two is found, repeat until no more conversions are to be found"""
unit_choices = AgrParameterUnitConversions.objects.filter(ChildParameterUnitId=base_unit).annotate(
unit_name=F('ParrentParameterUnitId__Name'),
unit_id=F('ParrentParameterUnitId'),
).values("unit_id", "unit_name")
related_units = AgrParameterUnitConversions.objects.filter(
ChildParameterUnitId=unit_choices[0]["unit_id"]).annotate(
unit_name=F('ParrentParameterUnitId__Name'),
unit_id=F('ParrentParameterUnitId'),
).values("unit_id", "unit_name")
units_this_round = (unit_choices | related_units).distinct()
available_units = (related_units | units_this_round).distinct()
if related_units:
return _get_units(related_units[0]["unit_id"])
return available_units
Даже подсказка по использованию инструмента/процедуры была бы очень полезна.