문제

내가 찾고있는 것은 태그가없는 객체를 포함하는 쿼리 세트입니다.

지금까지 내가 생각 해낸 솔루션은 나에게 지나치게 복잡해 보입니다.

# Get all tags for model
tags = Location.tags.all().order_by('name')

# Get a list of tagged location id's
tag_list = tags.values_list('name', flat=True)
tag_names = ', '.join(tag_list)
tagged_locations = Location.tagged.with_any(tag_names) \
                                  .values_list('id', flat=True)

untagged_locations = []
for location in Location.objects.all():
    if location.id not in tagged_locations:
        untagged_locations.append(location)

개선을위한 아이디어가 있습니까? 감사!

도움이 되었습니까?

해결책

이 게시물에는 좋은 정보가 있으므로 삭제해야한다고 생각하지 않지만 훨씬 간단한 솔루션이 있습니다.

나는 django-tagging의 소스 코드를 빠르게 들여다 보았다. ContentType 프레임 워크와 일반적인 관계를 사용하여이를 끌어 올리는 것처럼 보입니다.

이 때문에 일반적인 역 관계 아직 수행하지 않은 경우 주어진 위치에 대한 TaggedItem 객체에 쉽게 액세스 할 수 있도록 위치 클래스에서 :

from django.contrib.contenttypes import generic
from tagging.models import TaggedItem

class Location(models.Model):
    ...

    tagged_items = generic.GenericRelation(TaggedItem,
                                          object_id_field="object_id",
                                          content_type_field="content_type")

    ...

설명

내 원래 대답은 다음을 수행하도록 제안했습니다.

untagged_locs = Location.objects.filter(tagged_items__isnull=True)

이것은 '정상 조인'에 대해 작동하지만 콘텐츠 유형 프레임 워크가 추가 확인을 시작하기 때문에 실제로 여기서는 작동하지 않습니다. content_type_id SQL로 isnull:

SELECT [snip] FROM `sotest_location` 
LEFT OUTER JOIN `tagging_taggeditem` 
 ON (`sotest_location`.`id` = `tagging_taggeditem`.`object_id`) 
WHERE (`tagging_taggeditem`.`id` IS NULL 
 AND `tagging_taggeditem`.`content_type_id` = 4 )

다음과 같이 역전시켜 해킹 할 수 있습니다.

untagged_locs = Location.objects.exclude(tagged_items__isnull=False)

그러나 그것은 옳지 않다고 느끼지 않습니다.

나는 또한 이것을 제안했지만 주석은 예상대로 작동하지 않습니다 컨텐츠 유형 프레임 워크.

from django.db.models import Count
untagged_locs = Location.objects.annotate(
    num_tags=Count('tagged_items')).filter(num_tags=0)

위의 코드는 제한된 테스트 케이스에서 저에게 효과적이지만 모델에 다른 'Taggable'객체가 있으면 버그가 될 수 있습니다. 그 이유는 그것이 확인하지 않기 때문입니다 content_type_id 요약 된대로 티켓. 다음 SQL을 생성했습니다.

SELECT [snip], COUNT(`tagging_taggeditem`.`id`) AS `num_tags` 
 FROM `sotest_location` 
LEFT OUTER JOIN `tagging_taggeditem` 
 ON (`sotest_location`.`id` = `tagging_taggeditem`.`object_id`) 
GROUP BY `sotest_location`.`id` HAVING COUNT(`tagging_taggeditem`.`id`) = 0  
ORDER BY NULL

만약에 Location 당신의 유일한 태그 가능한 객체, 위의 일이 작동합니다.

제안 된 해결 방법

주석 메커니즘이 작동하지 않으면 여기에 내가 할 일이 있습니다.

untagged_locs_e = Location.objects.extra(
        where=["""NOT EXISTS(SELECT 1 FROM tagging_taggeditem ti
 INNER JOIN django_content_type ct ON ti.content_type_id = ct.id
 WHERE ct.model = 'location'
  AND ti.object_id = myapp_location.id)"""]
)

이것은 SQL에 추가 WHER 절을 추가합니다.

SELECT [snip] FROM `myapp_location` 
WHERE NOT EXISTS(SELECT 1 FROM tagging_taggeditem ti
 INNER JOIN django_content_type ct ON ti.content_type_id = ct.id
  WHERE ct.model = 'location'
   AND ti.object_id = myapp_location.id)

그것은 합류합니다 django_content_type 테이블은 태그 가능한 모델 유형이 둘 이상인 경우 모델에 적합한 컨텐츠 유형을보고 있는지 확인하십시오.

변화 myapp_location.id 테이블 이름과 일치합니다. 아마도 테이블 이름을 하드 코딩하는 것을 피할 수있는 방법이있을 수 있지만, 그것이 중요하다면 그것을 알아낼 수 있습니다.

MySQL을 사용하지 않으면 그에 따라 조정하십시오.

다른 팁

이 시도:

[location for location in Location.objects.all() if location.tags.count() == 0]

당신의 가정 Location 클래스를 사용합니다 tagging.fields.TagField 공익사업.

from tagging.fields import TagField
class Location(models.Model):
    tags = TagField()

당신은 이것을 할 수 있습니다 :

Location.objects.filter(tags='')
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top