1

I have a model for uploaded files and I now need to have two tag fields in that model. One for user tags and one for admin tags. I've tried several solutions but neither worked.

Here is my code now and it doesn't work. Not sure if this is to create two separate tables, one for user tags and for admin tags so any help would be appreciated. Also, if you could maybe explain to me what I'm doing because I'm lost.

class UserTags(CommonGenericTaggedItemBase, TaggedItemBase):
    object_id = models.CharField(max_length=50, db_index=True)
    objects = models.Manager()

class BaseTag(TagBase):
    pass


class AdminTags(CommonGenericTaggedItemBase, TaggableManager):
    object_id = models.CharField(max_length=50, db_index=True)
    tag = models.ForeignKey(BaseTag, on_delete=models.CASCADE)
    objects = models.Manager()


# Model for all uploaded files
class Uploaded(models.Model):
    objects: models.Manager()
    user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="users")
    time_uploaded = models.DateTimeField(auto_now_add=True)
    name = models.CharField(max_length=50)
    file = models.FileField(upload_to=MEDIA_ROOT)
    tag = TaggableManager(blank=True, through=UserTags, related_name='user_tags')
    tags = TaggableManager(blank=True, through=AdminTags, related_name='admin_tags')
    additional_description = models.CharField(max_length=50, blank=True)

    def __str__(self):
        return f"{self.name} {self.file}"

2 Answers2

2

I would try to implement it like this.

from django.db import models
from taggit.managers import TaggableManager
from taggit.models import TaggedItemBase, ItemBase


class AdminTag(ItemBase):
    pass


class UserTag(ItemBase):
    pass


class ThroughAdminTag(TaggableManager):
    content_object = models.ForeignKey('AdminTag', on_delete=models.CASCADE)


class ThroughUserTag(TaggableManager):
    content_object = models.ForeignKey('UserTag', on_delete=models.CASCADE)


# Model for all uploaded files
class Uploaded(models.Model):
    objects = models.Manager()
    user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="users")
    time_uploaded = models.DateTimeField(auto_now_add=True)
    name = models.CharField(max_length=50)
    file = models.FileField(upload_to=MEDIA_ROOT)
    tag = TaggableManager(blank=True, through=ThroughUserTag, related_name='user_tags')
    tags = TaggableManager(blank=True, through=ThroughAdminTag, related_name='admin_tags')
    additional_description = models.CharField(max_length=50, blank=True)

    def __str__(self):
        return f"{self.name} {self.file}"

Not sure whether AdminTag and UserTag need any fields. Inheriting them from ItemBase should, in theory, cover that.

Yaro
  • 58
  • 1
  • 5
  • 1
    Hey, I have used your method to create a multiple tag fields in my model `create_collection` which is inherited with `models.Model` and I have created separate pair of classes for each taggable field like `subject_tag` (inherited by `ItemBase`) and `throughsubject_tag` (inherited by `Taggable Manager`). But it throws me an error `AttributeError: type object 'throughsubject_tag' has no attribute '_meta'` – Surya Nov 19 '22 at 11:39
0
from taggit.managers import TaggableManager
from taggit.models import TaggedItemBase

class ThroughTagA(TaggedItemBase):
    content_object = models.ForeignKey('Post', on_delete=models.CASCADE)

class ThroughTagB(TaggedItemBase):
    content_object = models.ForeignKey('Post', on_delete=models.CASCADE)

class Post(models.Model):    
    # ...
    tags_a = TaggableManager(blank=True, through=ThroughTagA, related_name='tags_a')
    tags_b = TaggableManager(blank=True, through=ThroughTagB, related_name='tags_b')  

Adapted from https://github.com/jazzband/django-taggit/issues/50#issuecomment-4627355

Ryan
  • 23,871
  • 24
  • 86
  • 132