简体   繁体   中英

Whats the most efficient way to get all related models in a tree-like structure in django?

I have this model structure:

models.py

class Region(models.Model):
    code = models.CharField(max_length=10, unique=True, verbose_name=_('code'))
    name = models.CharField(max_length=255, verbose_name=_('name'))


class Province(models.Model):
    code = models.CharField(max_length=10, unique=True, verbose_name=_('Code'))
    name = models.CharField(max_length=255, verbose_name=_('Name'))
    parent_region = models.ForeignKey('Region', on_delete=models.CASCADE, related_name='province', verbose_name=_('Regione'))


class City(models.Model):
    code = models.CharField(max_length=10, unique=True, verbose_name=_('Code'))
    name = models.CharField(max_length=255, verbose_name=_('Name'))
    parent_province = models.ForeignKey('Province', on_delete=models.CASCADE, related_name='city', verbose_name=_('Province'))


class CustomArea(models.Model):
    cities = models.ManyToManyField("City", verbose_name=_("Cities"), blank=True, related_name="in_area")
    provinces = models.ManyToManyField("Province", verbose_name=_("Provinces"), blank=True, related_name="in_area")
    regions = models.ManyToManyField("Region", verbose_name=_("Regions"), blank=True, related_name="in_area")

I want to write a method for CustomArea model that returns a queryset with all the single City element in it.

this is what I came up with:

    def list_cities(self):
        pks_provinces= self.provinces.all().values_list('id', flat=True)
        pks_regions= self.regions.all().values_list('id', flat=True)
        comuni = City.objects.filter(provincia__pk__in=pks_provinces).values_list('id', flat=True) | City.objects.filter(provincia__regione__pk__in=pks_regions).values_list('id', flat=True)  | self.cities.all().values_list('id', flat=True)
        return comuni.distinct()

Is this efficent enough? How can I improve this query to have all the single City element?

You can try something like this:

from django.apps import apps
from django.conf import settings
from django.db.models import OneToOneField, ForeignKey, ManyToManyField

from <path to your models>.models import Region, Province, City, CustomArea


class RelatedModelManager:
    def __init__(self, base_model):
        self.base_model = base_model
        self.all_models = apps.get_models()
        self.result = {}
        self.checked = []

    def get_related(self, check_model=None):
        check_model = check_model or self.base_model
        ref = []

        for m in self.all_models:
            for f in m._meta.fields:
                if isinstance(
                        f, (OneToOneField, ForeignKey, ManyToManyField)
                ) and (f.related_model == check_model) and m not in self.checked:
                    self.checked.append(m)
                    ref.append(m)
        self.result[check_model] = ref

        if ref:
            for m in ref:
                self.get_related(m)

obj = RelatedModelManager(Region)
obj.get_related()
obj.result

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM