我有一个普通模型和一个抽象模型,如下所示:
class TaggedSubject(models.Model):
user = models.ForeignKey(User, null=True, blank=True)
category = models.CharField(max_length=200)
foo = models.CharField(max_length=50)
bar = models.CharField(max_length=50)
# etc
content_type = models.ForeignKey(ContentType)
content_object_pk = models.CharField(max_length=255)
content_object = generic.GenericForeignKey("content_type", "content_object_pk")
def __unicode__(self):
if self.user:
return "%s" % (self.user.get_full_name() or self.user.username)
else:
return self.label
class Taggable(models.Model):
tagged_subjects = generic.GenericRelation(TaggedSubject, content_type_field='content_type', object_id_field='content_object_pk')
@property
def tagged_users(self):
return User.objects.filter(pk__in=self.tagged_subjects.filter(user__isnull=False).values("user"))
class Meta:
abstract = True
然后,Taggable
抽象模型类按如下方式使用:
class Photo(Taggable):
image = models.ImageField(upload_to="foo")
# ... etc
因此,如果我们有一个照片对象:
photo = Photo.objects.all()[0]
我可以用 photo.tagged_users.all() 标记照片中的所有用户
我想添加与用户对象的反比关系,这样如果我有一个用户:
user = User.objects.filter(pk__in=TaggedSubject.objects.exclude(user__isnull=True).values("user"))[0]
我可以调用类似 user.tagged_photo_set.all()
的东西并让它返回所有照片对象。
我怀疑由于 TaggedSubject 连接到通用关系上的可标记模型,因此无法将其用作具有ManyToMany
字段的through
模型。
假设这是真的,这是我认为我需要(以某种方式)添加到用户模型中的函数:
def tagged_photo_set(self):
Photo.objects.filter(pk__in=TaggedSubject.objects.filter(user=self, content_type=ContentType.objects.get_for_model(Photo))
我想知道是否可以对其进行设置,以便每次基于 Taggable 创建新的模型类时,它都会创建上述函数的一个版本并将其添加(理想情况下作为行为类似于属性的函数!
或者,如果以某种方式可以在通用关系上进行 ManyToMany 字段连接(我非常怀疑),那也会起作用。
最后,如果有第三个更酷的选择我没有看到,我当然愿意接受它。
设置基类子类的模型时,您可以使用add_to_class
和class_prepared
信号进行一些后处理:
def add_to_user(sender, **kwargs):
def tagged_FOO_set(self):
return sender.objects.filter(pk__in=TaggedSubject.objects.filter(
user=self,
content_type=ContentType.objects.get_for_model(sender)))
if issubclass(sender, MyAbstractClass):
method_name = 'tagged_{model}_set'.format(model=sender.__name__.lower())
User.add_to_class(method_name, property(tagged_FOO_set))
class_prepared.connect(add_to_user)