Подтвердить что ты не робот

Извлечение "большого" конца отношения общего внешнего ключа в Django

В Django, когда я запрашиваю ресурс, который имеет отношение "многие ко многим", я получаю все элементы в дочерней части отношения, даже те, которые напрямую не связаны с родителем. Будет легче, если я покажу вам код (классы обрезаны, чтобы показать только то, что необходимо):

Модели

class Report(models.Model):
    name = models.CharField(max_length=255)
    slug = AutoSlugField(_('slug'), populate_from='name')
    wells = models.ManyToManyField(Well, null=True)
    uuid = UUIDField(editable=False, blank=True, version=4, unique=True)


class Well(models.Model):
    slug = AutoSlugField(_('slug'), populate_from='name')
    name = models.CharField(max_length=255)

class Node(models.Model):
    @property
    def well(self):
        raise NotImplementedError("The 'well' field must be implemented")
    //irrelevant GFK omitted
    page_content_type = models.ForeignKey(ContentType, null=True, blank=True, related_name='page')
    page_object_id = models.PositiveIntegerField(blank=True, null=True)
    page_content_object = generic.GenericForeignKey('page_content_type', 
     'page_object_id')

Ресурсы

class ReportResource(ModelResource):
    wells = fields.ManyToManyField(WellResource, 'wells', full=True)
    stock = fields.ForeignKey(TickerResource, 'stock', full=True)

    class Meta:
        queryset = Report.objects.all()
        resource_name = 'ticker_reports'

class WellResource(ModelResource):
    nodes = fields.ToManyField('wells.api.NodeResource', 'nodes', full=True)
    type = fields.ForeignKey(WellTypeResource, 'type', full=True)

    class Meta:
        queryset = Well.objects.all()
        resource_name = 'wells'

class NodeResource(ModelResource):
    order = fields.IntegerField()
    content_object = GenericForeignKeyField({
                                                Content: UUIDOnlyContentResource
                                            }, 'content_object', full=True)

    class Meta:
        queryset = Node.objects.all()
        resource_name = 'nodes'
        filtering = {
            'ticker_report': ALL_WITH_RELATIONS
        }

В отчете Тикера есть много Уэллса, и эти Уэллсы распределены между всеми отчетами Тикера. Другое дело, что вы можете связать узлы с Уэллсом; для данного отчета о тикере единственными узлами, которые должны отображаться, являются те, которые связаны с этим тикером.

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

Отношения:

page_object_id, page_content_object, page_content_type - это отношение GenericForeignKey к Report

В настоящее время отображаются все узлы (это ошибка).

В TastyPie, как мне сказать, показывать только связанные объекты, а не все объекты?

Здесь короткая консоль python, которая показывает проблему более сурово:

>>> r = Report.objects.get(id=1)                                                                                                        
>>> for well in r.wells.all():                                                                                                          
...     for node in well.nodes.all():                                                                                                   
...         print 'Node in Well {0} is {1}'.format(well, node)                                                                          
...                                                                                                                                     
Node in Well The Areas You Must Watch (the-areas-you-must-watch - Fancy List) is Apple Content #1:Apple (0)                             
Node in Well The Areas You Must Watch (the-areas-you-must-watch - Fancy List) is First Solar Content #1:first solar (0)                 
Node in Well Risks (risks - Headline and Lead) is Apple Content #2:Apple (0)                                                            
Node in Well Risks (risks - Headline and Lead) is First Solar Content #2:first solar (0)                                                
>>> 

Фактический результат SQL

SELECT node.id, node.uuid, node.order,node.content_type_id, node.object_id,
       node.page_content_type_id, node.page_object_id, node.well_id FROM node 
WHERE node.well_id = 1  
ORDER BY node.order ASC 

(Изменено, чтобы было легче читать)

Ожидаемый вывод SQL:

SELECT node.id, node.uuid, node.order,node.content_type_id, node.object_id,
       node.page_content_type_id, node.page_object_id, node.well_id FROM node 
WHERE node.well_id = 1  AND node.page_content_type_id = 99 /*Report Content TypeID */ AND node.page_content_object_id = 1 /*ReportID*/
ORDER BY node.order ASC 

Ожидаемый результат:

Node in Well The Areas You Must Watch is Apple Content #1
Node in Well Risks is Apple Content #2:Apple (0)

Как я могу отфильтровать дочерний конец отношений "многие ко многим" с Django и TastyPie (хотя эта проблема очевидна и без TastyPie, что позволяет мне считать это структурной проблемой)

4b9b3361

Ответ 1

При выполнении запроса

well.nodes.all()

это извлекает все узлы, связанные с well, через отношения, описанные в вашей модели.

Звучит так, как будто вы хотите ограничить вернувшиеся узлы теми, которые ссылаются на объект Report r с помощью отношения внешнего ключа page_content_object. Это правильно? Если это так, вам нужно явно фильтровать узлы, например:

r = Report.objects.get(id=1)
for well in r.wells.all():                                                                                                          
    for node in well.nodes.filter(page_object_id = r.id,
                                  page_content_type = ContentType.objects.get_for_model(r)):
        # ...

Обновление: я ничего не знаю о TastyPie, и я должен сказать, что я действительно не понимаю, что вы пытаетесь сделать, но в Django, если есть связь между ячейками и узлами, тогда вам нужно добавьте его в свои модели. Например, если каждый Node принадлежит ровно одному well, естественным было бы добавить поле в модель Node:

class Node(models.Model):
    # ...
    well = models.ForeignKey('Well')

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

 Node.objects.filter(well__report = r,
                     page_object_id = r.id,
                     page_content_type = ContentType.objects.get_for_model(r))

Если вам нужно сделать это много, то естественным было бы добавить метод в модель Report.

Ответ 2

В отчете Тикера есть много Уэллса, и эти Уэллсы распределены между всеми Тикерные отчеты. Другое дело, что вы можете связать узлы с Уэллсом; для данного отчета о тикере, единственными узлами, которые должны отображаться, являются которые относятся к этому отчету Тикера.

В Django, когда я запрашиваю ресурс, который имеет много-ко-многим отношения, я получаю все предметы в дочерней части отношения, даже те, которые напрямую не связаны с родителем. Это будет проще, если я покажу вам код (классы обрезаны, чтобы показывать только что необходимо):

Если я правильно понимаю, node может быть связан с сообщением или колодцами (потому что вы упомянули , относящихся к этому отчету о тике). И вы ищете node, относящиеся к отчету, а не узлы , связанные с ямами отчета. (потому что вы ищете node, напрямую связанного с родителем (отчет?))

Если я прав, это довольно просто:

https://docs.djangoproject.com/en/dev/ref/contrib/contenttypes/#reverse-generic-relations

class Report(models.Model):
    name = models.CharField(max_length=255)
    slug = AutoSlugField(_('slug'), populate_from='name')
    wells = models.ManyToManyField(Well, null=True)
    uuid = UUIDField(editable=False, blank=True, version=4, unique=True)

    nodes = generic.GenericRelation(Node)


# usage
r = Report.objects.get(id=1)
nodes = r.nodes.all()