2009-11-30 3 views
1

내가 찾고있는 것은 태그가없는 객체가 포함 된 QuerySet입니다.장고 태그로 태그가없는 객체 검색

내가 지금까지 함께 왔어요 솔루션은 나에게 지나치게 복잡해 보이는

:

# 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) 

어떤 아이디어 개선을위한? 감사!

답변

3

이 게시물에 몇 가지 좋은 정보가있다, 그래서 그것을 삭제해야한다고 생각하지 않지만, 훨씬, 훨씬 더 간단한 해결책이있다

장고 태그에 대한 소스 코드를 빠르게 살펴 보았습니다. 그들은 ContentType 프레임 워크와 일반적인 관계를 사용하여 그것을 제거한 것처럼 보입니다.

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") 

    ... 

: 아직 수행하지 않은 경우이 때문에

, 당신은, 주어진 위치의 TaggedItem 객체에 쉽게 접근 할 수 있도록 위치 클래스에 generic reverse relation을 만들 수있을 것입니다 이 w 비록

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

: 내 원래의 대답은이 일을 제안

해명 작동 울드 상기 콘텐츠 형식 프레임 워크는 isnull에 대한 SQL에 content_type_id에 대한 추가 검사가 발생하기 때문에,이 실제로 여기에 작동하지 않습니다 '에 가입 정상'

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) 

그러나 그다지 옳지 않다고 생각합니다.

또한 제안했지만 내용 유형 프레임 워크가 annotations don't work as expected 인 것으로 지적되었습니다.

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

위의 코드

내 제한된 테스트 케이스에 나를 위해 작동하지만이 모델의 다른 'taggable'객체가있는 경우는 버그가 될 수 있습니다. 그 이유는 the ticket에 설명 된대로 content_type_id을 확인하지 않기 때문입니다. Location이 유일한 taggable 목적은

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 

경우, 위의 작동합니다 : 그것은 다음과 같은 SQL을 생성합니다.

제안 된 해결 방법, 여기에 내가 그동안 어떻게 할 것인지 작동하도록 주석 메커니즘을 얻기의 짧은이다

:

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에 절 :

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을 사용하지 않는 경우 적절하게 조정하십시오.

+0

'object \ _id \ _field'및 'content \ _type \ _field'매개 변수는 기본적으로 전달되는 항목을 기본값으로하기 때문에 무의미하지만 API를 표시하는 것이 도움이된다는 생각이 들었습니다. –

+0

멋진 답변을 제공해 주셔서 감사합니다! 그러나, 나는 틀린 일을하고 있을지도 모르지만 나는 일할 수 없습니다. tagged items의 집합을 제공하기 위해'Location.objects.filter (tagged_items__isnull = False) '를 얻을 수는 있지만'Location.objects.filter (tagged_items__isnull = True)'는 단지 빈 쿼리를 제공한다. – lemonad

+0

또한 주석은 제네릭 관계에서 올바르게 작동합니까? 다음 티켓은 그렇지 않다는 것을 나타냅니다. http://code.djangoproject.com/ticket/10461 – lemonad

0

이 시도 :

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

사용 괄호 대신 대괄호 대신 목록의 발전기를 얻을 수 있습니다. (대부분) 동일한 사용법으로 메모리 요구량이 훨씬 적습니다. – Javier

+0

글쎄, 이것은 태그가 지정되지 않은 개체 목록이지만 ** 태그가없는 개체의 ** 쿼리 집합 **이 아닙니다. 주요 차이점은 관리자 기능이없고 느슨하게 평가되지 않는다는 것입니다. –

0

Location 클래스는 tagging.fields.TagField 유틸리티를 사용한다고 가정합니다.

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

당신은이 작업을 수행 할 수 있습니다

Location.objects.filter(tags='') 
+0

불행히도 django-tagging은 'tags'컬럼을 도입하지 않으므로 필터에서 사용할 수 있습니다. 어쨌든 ... 나는 "매뉴얼"에 따라 모든 것을 설정했다고 생각합니다. – lemonad

+0

간단한 장고 태그 지정 예제를 통해이 작업을 발견했지만,'TagField' 유틸리티를 사용하여 모델에 포함시켜야한다고 생각합니다. –

+0

아하, 내가 어떻게 작동하는지 알 수있어. 나는'TagField'를 가지고 있지만 불행하게도 당신이 태그를 붙여서 모델을 등록하면'tags'라고 이름을 붙일 수 없습니다. 내가했을 때 정말 못생긴 버그가 발생했습니다 (TaggedItem 등으로 태그를 검색 할 때 태그가 제거됨). 이름을 변경 한 후에 모든 것이 잘 동작했습니다. 여기에 이름 바꾸기 조언이 있습니다. http://tylerlesmann.com/2009/mar/06/adding-tagging-django-10-applications-existing-dat/ – lemonad

관련 문제