def test_deconstruct_kwargs_kept(self): instance = TaggableManager(through=OfficialThroughModel, to='dummy.To') name, path, args, kwargs = instance.deconstruct() new_instance = TaggableManager(*args, **kwargs) self.assertEqual('tests.OfficialThroughModel', _remote_field(new_instance).through) self.assertEqual('dummy.To', _related_model(_remote_field(new_instance)))
def _get_subclasses(model): subclasses = [model] for field in model._meta.get_fields(): if isinstance(field, OneToOneRel) and getattr( _remote_field(field.field), "parent_link", None): subclasses.extend(_get_subclasses(field.related_model)) return subclasses
def deconstruct(self): """ Deconstruct the object, used with migrations. """ name, path, args, kwargs = super(TaggableManager, self).deconstruct() # Remove forced kwargs. for kwarg in ('serialize', 'null'): del kwargs[kwarg] # Add arguments related to relations. # Ref: https://github.com/alex/django-taggit/issues/206#issuecomment-37578676 rel = _remote_field(self) if isinstance(rel.through, six.string_types): kwargs['through'] = rel.through elif not rel.through._meta.auto_created: kwargs['through'] = "%s.%s" % (rel.through._meta.app_label, rel.through._meta.object_name) related_model = _related_model(rel) if isinstance(related_model, six.string_types): kwargs['to'] = related_model else: kwargs['to'] = '%s.%s' % (related_model._meta.app_label, related_model._meta.object_name) return name, path, args, kwargs
def similar_objects(self): lookup_kwargs = self._lookup_kwargs() lookup_keys = sorted(lookup_kwargs) qs = self.through.objects.values(*six.iterkeys(lookup_kwargs)) qs = qs.annotate(n=models.Count('pk')) qs = qs.exclude(**lookup_kwargs) qs = qs.filter(tag__in=self.all()) qs = qs.order_by('-n') # TODO: This all feels like a bit of a hack. items = {} if len(lookup_keys) == 1: # Can we do this without a second query by using a select_related() # somehow? f = _get_field(self.through, lookup_keys[0]) remote_field = _remote_field(f) rel_model = _related_model(_remote_field(f)) objs = rel_model._default_manager.filter(**{ "%s__in" % remote_field.field_name: [r["content_object"] for r in qs] }) actual_remote_field_name = remote_field.field_name if VERSION > (1, 9): actual_remote_field_name = f.target_field.get_attname() else: actual_remote_field_name = f.related_field.get_attname() for obj in objs: items[(getattr(obj, actual_remote_field_name),)] = obj else: preload = {} for result in qs: preload.setdefault(result['content_type'], set()) preload[result["content_type"]].add(result["object_id"]) for ct, obj_ids in preload.items(): ct = ContentType.objects.get_for_id(ct) for obj in ct.model_class()._default_manager.filter(pk__in=obj_ids): items[(ct.pk, obj.pk)] = obj results = [] for result in qs: obj = items[ tuple(result[k] for k in lookup_keys) ] obj.similar_tags = result["n"] results.append(obj) return results
def similar_objects(self): lookup_kwargs = self._lookup_kwargs() lookup_keys = sorted(lookup_kwargs) qs = self.through.objects.values(*six.iterkeys(lookup_kwargs)) qs = qs.annotate(n=models.Count('pk')) qs = qs.exclude(**lookup_kwargs) qs = qs.filter(tag__in=self.all()) qs = qs.order_by('-n') # TODO: This all feels like a bit of a hack. items = {} if len(lookup_keys) == 1: # Can we do this without a second query by using a select_related() # somehow? f = self.through._meta.get_field(lookup_keys[0]) remote_field = _remote_field(f) rel_model = _related_model(_remote_field(f)) objs = rel_model._default_manager.filter( **{ "%s__in" % remote_field.field_name: [r["content_object"] for r in qs] }) for obj in objs: items[(getattr(obj, remote_field.field_name), )] = obj else: preload = {} for result in qs: preload.setdefault(result['content_type'], set()) preload[result["content_type"]].add(result["object_id"]) for ct, obj_ids in preload.items(): ct = ContentType.objects.get_for_id(ct) for obj in ct.model_class()._default_manager.filter( pk__in=obj_ids): items[(ct.pk, obj.pk)] = obj results = [] for result in qs: obj = items[tuple(result[k] for k in lookup_keys)] obj.similar_tags = result["n"] results.append(obj) return results
def test_field_api(self): # Check if tag field, which simulates m2m, has django-like api. field = self.food_model._meta.get_field('tags') if django.VERSION >= (1, 9): self.assertTrue(hasattr(field, 'remote_field')) self.assertTrue(hasattr(field.remote_field, 'model')) else: self.assertTrue(hasattr(field, 'rel')) self.assertTrue(hasattr(field.rel, 'to')) self.assertEqual(self.food_model, field.model) self.assertEqual(self.tag_model, _remote_field(field).model)
def _get_gfk_case_path_info(self, direct=False, filtered_relation=None): pathinfos = [] from_field = self.model._meta.pk opts = self.through._meta linkfield = self.through._meta.get_field(self.m2m_reverse_field_name()) if direct: if VERSION < (2, 0): join1infos = [PathInfo(self.model._meta, opts, [from_field], _remote_field(self), True, False)] join2infos = linkfield.get_path_info() else: join1infos = [PathInfo(self.model._meta, opts, [from_field], _remote_field(self), True, False, filtered_relation)] join2infos = linkfield.get_path_info(filtered_relation=filtered_relation) else: if VERSION < (2, 0): join1infos = linkfield.get_reverse_path_info() join2infos = [PathInfo(opts, self.model._meta, [from_field], self, True, False)] else: join1infos = linkfield.get_reverse_path_info(filtered_relation=filtered_relation) join2infos = [PathInfo(opts, self.model._meta, [from_field], self, True, False, filtered_relation)] pathinfos.extend(join1infos) pathinfos.extend(join2infos) return pathinfos
def test_field_api(self): # Check if tag field, which simulates m2m, has django-like api. field = self.food_model._meta.get_field('tags') if django.VERSION >= (1, 9): self.assertTrue(hasattr(field, 'remote_field')) self.assertTrue(hasattr(field.remote_field, 'model')) elif django.VERSION >= (1, 8): self.assertTrue(hasattr(field, 'rel')) self.assertTrue(hasattr(field.rel, 'to')) else: self.assertTrue(hasattr(field, 'rel')) self.assertTrue(hasattr(field.rel, 'to')) # This API has changed in Django 1.8 # https://code.djangoproject.com/ticket/21414 if django.VERSION >= (1, 9): self.assertEqual(self.food_model, field.model) self.assertEqual(self.tag_model, _remote_field(field).model) if django.VERSION >= (1, 8): self.assertEqual(self.food_model, field.model) self.assertEqual(self.tag_model, _remote_field(field).model) else: self.assertEqual(self.food_model, field.related.model)
def _get_gfk_case_path_info(self, direct=False): pathinfos = [] from_field = self.model._meta.pk opts = self.through._meta linkfield = _get_field(self.through, self.m2m_reverse_field_name()) if direct: join1infos = [PathInfo(self.model._meta, opts, [from_field], _remote_field(self), True, False)] join2infos = linkfield.get_path_info() else: join1infos = linkfield.get_reverse_path_info() join2infos = [PathInfo(opts, self.model._meta, [from_field], self, True, False)] pathinfos.extend(join1infos) pathinfos.extend(join2infos) return pathinfos
def _get_subclasses(model): subclasses = [model] if VERSION < (1, 8): all_fields = (_get_field(model, f) for f in model._meta.get_all_field_names()) else: all_fields = model._meta.get_fields() for field in all_fields: # Django 1.8 + if (not RelatedObject and isinstance(field, OneToOneRel) and getattr(_remote_field(field.field), "parent_link", None)): subclasses.extend(_get_subclasses(field.related_model)) # < Django 1.8 if (RelatedObject and isinstance(field, RelatedObject) and getattr(field.field.rel, "parent_link", None)): subclasses.extend(_get_subclasses(field.model)) return subclasses
def _get_subclasses(model): subclasses = [model] for field in model._meta.get_fields(): if isinstance(field, OneToOneRel) and getattr(_remote_field(field.field), "parent_link", None): subclasses.extend(_get_subclasses(field.related_model)) return subclasses
def resolve_related_class(field, model, cls): self.through = model _remote_field(self).through = model self.post_through_setup(cls)