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

Django: как я могу выполнить запрос на основе полей GenericForeignKey?

Я новичок в использовании GenericForeignKey, и я не мог заставить его работать в запросе. Таблицы выглядят примерно так:

class Ticket(models.Model):
    issue_ct = models.ForeignKey(ContentType, related_name='issue_content_type')
    issue_id = models.PositiveIntegerField(null=True, blank=True)
    issue = generic.GenericForeignKey('issue_ct', 'issue_id')

class Issue(models.Model):
    scan = models.ForeignKey(Scan)

Сканирование создает одну проблему, проблема генерирует некоторые билеты, и я сделал Issue в качестве внешнего ключа в таблице Ticket. Теперь у меня есть объект Scan, и я хочу запросить все билеты, связанные с этим сканированием. Я попробовал это первым:

tickets = Tickets.objects.filter(issue__scan=scan_obj)

который не работает. Затем я попробовал это:

issue = Issue.objects.get(scan=scan_obj)
content_type = ContentType.objects.get_for_model(Issue)
tickets = Tickets.objects.filter(content_type=content_type, issue=issue)

Все еще не работает. Мне нужно знать, как делать такие запросы в django? Спасибо.

4b9b3361

Ответ 1

Поле Ticket.issue, которое вы определили, поможет вам перейти от экземпляра Ticket к прикрепленному к нему Issue, но он не позволит вам вернуться назад. Вы близки вашему второму примеру, но вам нужно использовать поле issue_id - вы не можете запрашивать в GenericForeignKey (он просто помогает вам получить объект, когда у вас есть экземпляр Ticket). Попробуйте следующее:

from django.contrib.contenttypes.models import ContentType

issue = Issue.objects.get(scan=scan_obj)
tickets = Ticket.objects.filter(issue_id=issue.id, issue_ct=ContentType.objects.get_for_model(issue))

Ответ 2

Фильтрация по GenericForeignKey может путем создания второй модели, которая разделяет db_table с Ticket. Сначала разделите билет на абстрактную модель и конкретную модель.

class TicketBase(models.Model):
    issue_ct = models.ForeignKey(ContentType, related_name='issue_content_type')
    issue_id = models.PositiveIntegerField(null=True, blank=True)

    class Meta:
        abstract = True

class Ticket(models.Model):
    issue = generic.GenericForeignKey('issue_ct', 'issue_id')

Затем создайте модель, также подклассы TicketBase. Этот подкласс будет иметь все те же поля, кроме issue, который вместо этого определяется как ForeignKey. Добавление пользовательского Manager позволяет фильтровать только один ContentType.

Поскольку этот подкласс не требуется синхронизировать или переносить, он может быть создан динамически с помощью type().

def subclass_for_content_type(content_type):
    class Meta:
        db_table = Ticket._meta.db_table

    class Manager(models.Manager):
        """ constrain queries to a single content type """
        def get_query_set(self):
            return super(Manager, self).get_query_set().filter(issue_ct=content_type)

    attrs = {
        'related_to': models.ForeignKey(content_type.model_class()),
        '__module__': 'myapp.models',
        'Meta': Meta,
        'objects': Manager()
    }
   return type("Ticket_%s" % content_type.name, (TicketBase,), attrs)