예제 #1
0
    def _ensure_partition(self, partition_key):
        # Actually do the legwork for generating a partition
        logger.debug('Partition not found, generating')
        model_name = self._model_name_for_partition(partition_key)
        imp.acquire_lock()
        try:
            model = create_model(
                model_name,
                bases=(self.model,),
                attrs={PARTITION_KEY: partition_key},
                module_path=self.model.__module__)

            for name, manager in self.get_managers(model):
                manager.contribute_to_class(model, name)

            # Make sure that we don't overwrite an existing name in the
            # module. Raise an AttributeError if we look like we're about
            # to.
            module = sys.modules[self.model.__module__]
            if getattr(module, model_name, _marker) is _marker:
                setattr(module, model_name, model)
            else:
                raise AttributeError('{} already exists in {}'.format(
                    model_name, module))

            logger.debug(
                '{} generated, processing PartitionForeignKeys'.format(
                    model))

            # Find any PartitionForeignKeys that point to our parent model,
            # and generate partitions of those source models
            pfks_to_remove = set()
            for pfk in self.registry.foreign_keys_referencing(self.model):
                if not hasattr(pfk.cls, '_partition_manager'):
                    raise AttributeError(
                        'Source model {} does not have a partition '
                        'manager'.format(pfk.cls))
                child = pfk.cls._partition_manager.get_partition(partition_key)

                # Replace the placeholder with a real foreign key, and
                # make sure internal caches are populated correctly
                point(child, pfk.name, model, **pfk.kwargs)
                pfks_to_remove.add(pfk)
                self._fill_fields_cache(child._meta)

            # Make sure that there are no pfks hanging around
            for pkf in pfks_to_remove:
                for lst in (child._meta.fields, child._meta.local_fields):
                    for field in lst:
                        if field.name == pkf.name and isinstance(
                                field,
                                PartitionForeignKey):
                            lst.remove(field)
                            break
        finally:
            imp.release_lock()

        return model
예제 #2
0
    def test_derived_model_point_base(self):
        # If we repoint a dfk on a base non-abstract class, subclasses
        # should see the change.
        class BaseClass3(models.Model):
            c = DeferredForeignKey()

        class DerivedModel3(BaseClass3):
            pass
        point(BaseClass3, 'c', ModelA)
        self.assertEqual(ModelA, DerivedModel3.c.field.rel.to)
예제 #3
0
    def _ensure_partition(self, partition_key):
        # Actually do the legwork for generating a partition
        logger.debug('Partition not found, generating')
        model_name = self._model_name_for_partition(partition_key)
        imp.acquire_lock()
        try:
            model = create_model(model_name,
                                 bases=(self.model, ),
                                 attrs={PARTITION_KEY: partition_key},
                                 module_path=self.model.__module__)

            for name, manager in self.get_managers(model):
                manager.contribute_to_class(model, name)

            # Make sure that we don't overwrite an existing name in the
            # module. Raise an AttributeError if we look like we're about
            # to.
            module = sys.modules[self.model.__module__]
            if getattr(module, model_name, _marker) is _marker:
                setattr(module, model_name, model)
            else:
                raise AttributeError('{} already exists in {}'.format(
                    model_name, module))

            logger.debug(
                '{} generated, processing PartitionForeignKeys'.format(model))

            # Find any PartitionForeignKeys that point to our parent model,
            # and generate partitions of those source models
            pfks_to_remove = set()
            for pfk in self.registry.foreign_keys_referencing(self.model):
                if not hasattr(pfk.cls, '_partition_manager'):
                    raise AttributeError(
                        'Source model {} does not have a partition '
                        'manager'.format(pfk.cls))
                child = pfk.cls._partition_manager.get_partition(partition_key)

                # Replace the placeholder with a real foreign key, and
                # make sure internal caches are populated correctly
                point(child, pfk.name, model, **pfk.kwargs)
                pfks_to_remove.add(pfk)
                self._fill_fields_cache(child._meta)

            # Make sure that there are no pfks hanging around
            for pkf in pfks_to_remove:
                for lst in (child._meta.fields, child._meta.local_fields):
                    for field in lst:
                        if field.name == pkf.name and isinstance(
                                field, PartitionForeignKey):
                            lst.remove(field)
                            break
        finally:
            imp.release_lock()

        return model
예제 #4
0
    def test_derived_model_abstract(self):
        # If the base model is abstract, then it's actually OK as
        # the field is local to the subclass anyway.
        class BaseClass2(models.Model):
            c = DeferredForeignKey()

            class Meta:
                abstract = True

        class DerivedModel2(BaseClass2):
            pass
        point(DerivedModel2, 'c', ModelA)
        self.assertEqual(ModelA, DerivedModel2.c.field.rel.to)
예제 #5
0
    def test_options_caches_not_cleared_on_point(self):
        # Check that the relevant meta caches are not cleared after a point
        # if clear_caches=False
        class NewModelNoCache(models.Model):
            c = DeferredForeignKey()

        point(NewModelNoCache, 'c', ModelC, clean_caches=False)
        mdc_related = ModelC._meta.get_all_related_objects_with_model()
        found = False
        for rel, _ in mdc_related:
            if rel.model is NewModelNoCache:
                found = True
        self.assertEqual(False, found)
예제 #6
0
    def test_options_caches_cleared_on_point(self):
        # Check that the relevant meta caches are cleared after a point
        # to ensure related field names are up to date.
        class NewModel(models.Model):
            c = DeferredForeignKey()

        point(NewModel, 'c', ModelC)
        mdc_related = ModelC._meta.get_all_related_objects_with_model()
        found = False
        for rel, _ in mdc_related:
            if rel.model is NewModel:
                found = True
        self.assertEqual(True, found)
예제 #7
0
    def test_options_caches_cleaned(self):
        # Check that the relevant meta caches are cleared after
        # a direct call to clean_object_caches
        class NewModelNoCache2(models.Model):
            c = DeferredForeignKey()

        point(NewModelNoCache2, 'c', ModelC, clean_caches=False)
        mdc_related = ModelC._meta.get_all_related_objects_with_model()
        found = False
        for rel, _ in mdc_related:
            if rel.model is NewModelNoCache2:
                found = True
        assert not found

        clean_object_caches(NewModelNoCache2, ModelC)
        mdc_related = ModelC._meta.get_all_related_objects_with_model()
        for rel, _ in mdc_related:
            if rel.model is NewModelNoCache2:
                found = True
        self.assertEqual(True, found)
예제 #8
0
    def test_not_a_model(self):
        self.assertRaises(AssertionError, repoint, ModelB, 'fk', NotAModel)

    def test_abstract(self):
        self.assertRaises(AssertionError, repoint, ModelB, 'fk', AbstractModel)


class DeferredModelA(models.Model):
    user = DeferredForeignKey()


class DeferredModelB(models.Model):
    user = DeferredForeignKey()

# Point DeferredModelA's 'user' dfk to ModelA
point(DeferredModelA, 'user', ModelA, related_name='foo_set')

# Point ModelD's deferred fk to ModelA
point_named('dfk', 'content', ModelA)

# Point ModelCustomFiekld's deferred fk to ModelA
point_named('dfk', 'content2', ModelA)


class DeferredForeignKeyTestCase(TestCase):

    def test_specific_field(self):
        # Check that DeferredModelA's deferred field was correctly
        # processed
        m = ModelA.objects.create()
        a = DeferredModelA.objects.create(