Django вложенный prefetch_related - PullRequest
0 голосов
/ 11 мая 2018

Я использую вложенную предварительную выборку, чтобы связать все мои объекты друг с другом, а затем помещаю их в шаблон, чтобы показать их.

Моя общая настройка: у меня есть фреймворки, категории и элементы управления. Элемент управления связан с категорией, категория связана с каркасом. Категория также может иметь суперкатегорию, и в этом случае категория вызывает другой объект категории. Каждый элемент управления также имеет начальную оценку, текущую оценку и целевую оценку.

То, что я хочу сделать, - это для каждой структуры, для каждой суперкатегории, для каждой подкатегории показать каждый элемент управления со своими баллами.

Пример:

Framework A
  Super Category 1
    Subcategory 1
      Control 1
        Initial
        Current
        Target
      Control 2
       ...
    Subcategory 2
      Control 3
       ...
  Super Category 2
     Subcategory 3
       Control 4
        ...

Framework B
...

Мне уже удалось это сделать, используя множество вложенных предварительных выборок.

Мои модели:

# models.py
#==============[FRAMEWORKS]==============#
class Framework(models.Model):
    name = models.CharField(max_length=100)
    description = models.TextField(null=True)

    def __str__(self):
        return self.name.replace(' ', '_')

class FrameworkCat(models.Model):
    name = models.CharField(max_length=100)
    identifier = models.CharField(max_length=10,
                              null=True,
                              blank=True,
                              verbose_name="optional identifier")
    framework = models.ForeignKey(Framework,
                              on_delete=models.CASCADE,
                              verbose_name="related framework")
    superCat = models.ForeignKey('self',
                             on_delete=models.CASCADE,
                             verbose_name="super category",
                             blank=True,
                             null=True)

    hexColor = models.CharField(max_length=10,
                            null=True,
                            blank=True,
                            verbose_name="hex color")

    def __str__(self):
        return self.name

#==============[CONTROLS]==============#
class Control(models.Model):
    title = models.CharField(max_length=250)
    description = models.TextField()
    framework = models.ForeignKey(Framework,
                                on_delete=models.CASCADE,
                                verbose_name="related framework")
    category = models.ForeignKey(FrameworkCat,
                             on_delete=models.CASCADE,
                             verbose_name="related category",
                             null=True)
    def __str__(self):
        return self.title

class ProjectScore(models.Model):
    project = models.ForeignKey(Project,
                            on_delete=models.CASCADE,
                            verbose_name="related project")
    control = models.OneToOneField(Control,
                            on_delete=models.CASCADE,
                            verbose_name="related control")
    framework = models.ForeignKey(Framework,
                              on_delete=models.CASCADE,
                              verbose_name="related framework")

    score = models.IntegerField(default=-1)
    current_score = models.IntegerField(default=-1)
    target = models.IntegerField(default=-1)

    def __str__(self):
        return "Project Score"

Мой (тестовый) вид:

# views.py
def testing_models(request):
    def_data = default_data(request)


    frameworks = Framework.objects.prefetch_related(Prefetch('frameworkcat_set',
                                                         queryset=FrameworkCat.objects.prefetch_related(Prefetch('frameworkcat_set',
                                                         queryset=FrameworkCat.objects.prefetch_related(Prefetch('control_set',
                                                         queryset=Control.objects.select_related('projectscore').order_by('id'),
                                                         to_attr='controls')).exclude(superCat=None),
                                                         to_attr='categories')).filter(superCat=None),
                                                         to_attr='supercategories')).all()

    def_data['frameworks'] = frameworks

    return render(request, 'testing_models.html', def_data)

И мой шаблон, чтобы показать все:

# templates/testing_models.html
{% for framework in frameworks %}
    {% for supercategory in framework.supercategories %}
        <p><strong>{{ supercategory.name }}</strong></p>

        {% for subcategory in supercategory.categories %}
            <p>{{ subcategory.name }}</p>

            {% for control in subcategory.controls %}
                <p>{{ control.title }}</p>

                <p>{{ control.projectscore.score }}</p>
                <p>{{ control.projectscore.current_score }}</p>
                <p>{{ control.projectscore.target }}</p>
            {% endfor %}
        {% endfor %}
    {% endfor %}
{% endfor %}

Это все работает правильно, выполнив 6 запросов. Теперь мой главный вопрос: есть ли лучший способ получить эти объекты и связать их, чем использовать все эти вложенные предварительные выборки? Есть ли какой-то другой синтаксис, который я мог бы использовать, чтобы его было легче читать и модифицировать? У меня есть еще много вещей, которые я хотел бы связать, но я боюсь, что выражение python станет слишком большим, и мой обзор будет потерян.

Очень ценится!

...