Групиране на django обекти с помощта на QuerySet API чрез споделени текстови тагове с помощта на два модела с връзка ForeignKey

Здравейте, опитвам се да напиша django webapp, който седи върху наследена база данни и затова не мога да контролирам твърде много моите полета на модела и да постигна функционалност, използвайки нови модели.

Имам много документи с дадени от потребителя етикети, разделени със запетая. Искам да групирам „свързани“ документи въз основа на споделени тагове.

# Model to express legacy table
class Document(models.Model):
    id = models.BigIntegerField(primary_key= True)
    metadata_id = models.CharField(max_length=384)
    tags_as_csv = models.TextField()

# Created new Model tag_text extracted from tags_as_csv
class Tagdb(models.Model):
    tagid = models.BigIntegerField(primary_key=True)
    referencing_document = models.ForeignKey(Document)
    tag_text = models.TextField(blank=True)

Така един документ ще съдържа:

Document : 
id = 1 , 
metadata_id = "a1ee3df3600c6f77a6e851781f7e70c6" , 
tags_as_csv = "raw-data , high temperature , important"

Tagdb ще има записи като

id , referencing_document , tag_text
1  , 1 , "raw-data" 
2  , 1 , "high temperature"
3  , 1 , "important"
4  , 2 , "important"
5  , 2 , "processed-data"
6  , 3 , "important"
7  , 4 , "processed-data"

Сега искам да извлека всички обекти Document, които съответстват на тагове, съответстващи на родителски документ. Което правя, използвайки следния метод get_queryset.

   def get_queryset(self, **kwargs):
        parent_document = Document.objects.get(id=self.kwargs['slug'])
        tags_in_parent_document = [x.tag_text for x in Tagdb.objects.filter(referencing_document=parent_document.id)]
        # This will contain all the Document ids that match all the tags
        queryset_with_duplicates = []
        for tag in tags_in_parent_document:
            queryset_with_duplicates.extend([x.referencing_document.id for x in Tagdb.objects.filter(tagtext__icontains=tag)])

        # Make sure we have only unique ids
        queryset_unique = set(queryset_with_duplicates)

        # Get all the Document objects 
        queryset = Document.objects.filter(id__in=queryset_unique)

        return queryset

Въпросът ми е: има ли по-добър начин. Мога ли по някакъв начин да получа всички документи, които съдържат всички тагове в основния документ, и да филтрирам дубликатите (тъй като няколко документа съдържат един и същ маркер).


person harijay    schedule 07.03.2012    source източник


Отговори (1)


По-добре създайте два допълнителни модела: един за етикет и един за връзка между етикет и документ. Ако е донякъде неприемливо, можете да използвате нещо като:

Document.objects.filter(tagdb__tag_text__in=doc.tags_as_csv.split(' , ')).distinct()

Плюс това, добавете моделен метод за получаване/задаване на тагове, това ще улесни всеки възможен рефакторинг.

person ilvar    schedule 07.03.2012
comment
Последвах съвета ви и създадох модел ManyToManyField, който свързва двете заедно. Животът е по-лесен с новосъздадена таблица, както препоръчахте, особено като автоматично създадените търсения на полета, които са резултат от съпоставяне ManyToManyField. Въпреки това се натъкнах на нов проблем. Чудя се как мога да комбинирам търсене __in с търсене __icontains. stackoverflow.com/questions/9647142/ - person harijay; 10.03.2012