Ejemplo n.º 1
0
    def __init__(self, model, admin_site, *args, **kwargs):
        super(PolymorphicParentModelAdmin,
              self).__init__(model, admin_site, *args, **kwargs)
        self._is_setup = False

        if self.base_model is None:
            self.base_model = get_base_polymorphic_model(model)
Ejemplo n.º 2
0
    def add_inline(self, indexes=None, model=None, **kwargs):
        model_name = "%s-%s" % (model._meta.app_label, model._meta.model_name)
        if issubclass(model, PolymorphicModel):
            base_model = get_base_polymorphic_model(model)
        else:
            base_model = model
        base_model_identifier = "%s-%s" % (base_model._meta.app_label,
                                           base_model._meta.model_name)

        if indexes:
            item = self.get_item(indexes)
            ctx_id = item.get_attribute("id")
            group_el = self.selenium.execute_script(
                'return $(arguments[0]).closest(".djn-group")[0]', item)
        else:
            group_el = self.get_group([base_model_identifier])
            ctx_id = group_el.get_attribute('id')

        error_desc = "%s in inline %s" % (model, indexes)

        add_selector = "#%s .djn-add-item a.djn-add-handler.djn-model-%s" % (
            ctx_id, base_model_identifier)
        add_els = self.selenium.find_elements_by_css_selector(add_selector)
        self.assertNotEqual(
            len(add_els), 0,
            "No inline add handlers found for %s" % (error_desc))
        self.click(add_els[0])

        add_link_selector = "return $('.polymorphic-type-menu:visible [data-type=\"%s\"]')[0]" % (
            model_name)
        poly_add_link = self.selenium.execute_script(add_link_selector)

        if poly_add_link:
            poly_add_link.click()

        indexes = self._normalize_indexes(indexes)

        group_el = self.selenium.execute_script(
            'return $(arguments[0]).closest(".djn-group")[0]', add_els[0])
        group_id = group_el.get_attribute('id')

        items_el = self.selenium.find_element_by_css_selector(
            '#%(id)s > .djn-fieldset > .djn-items, '
            "#%(id)s > .tabular.inline-related > .djn-fieldset > .djn-items, "
            '#%(id)s > .djn-items' % {'id': group_id})

        num_inlines = len(
            items_el.find_elements_by_xpath(
                './*[%s and not(%s)]' %
                (xpath_item(), xpath_cls('djn-empty-form'))))

        new_index = num_inlines - 1

        indexes.append([model_name, new_index])
        for field_name, val in six.iteritems(kwargs):
            self.set_field(field_name, val, indexes=indexes)
        return indexes
Ejemplo n.º 3
0
    def test_get_base_polymorphic_model_skip_abstract(self):
        """
        Skipping abstract models that can't be used for querying.
        """
        class A(PolymorphicModel):
            class Meta:
                abstract = True

        class B(A):
            pass

        class C(B):
            pass

        self.assertIs(get_base_polymorphic_model(A), None)
        self.assertIs(get_base_polymorphic_model(B), B)
        self.assertIs(get_base_polymorphic_model(C), B)

        self.assertIs(get_base_polymorphic_model(C, allow_abstract=True), A)
Ejemplo n.º 4
0
    def add_inline(self, indexes=None, model=None, **kwargs):
        model_name = "%s-%s" % (model._meta.app_label, model._meta.model_name)
        if issubclass(model, PolymorphicModel):
            base_model = get_base_polymorphic_model(model)
        else:
            base_model = model
        base_model_identifier = "%s-%s" % (
            base_model._meta.app_label, base_model._meta.model_name)

        if indexes:
            item = self.get_item(indexes)
            group_el = self.selenium.execute_script(
                'return $(arguments[0]).closest(".djn-group")[0]', item)
        else:
            group_el = self.get_group([base_model_identifier])

        group_id = group_el.get_attribute('id')

        error_desc = "%s in inline %s" % (model, indexes)

        add_selector = "#%s .djn-add-item a.djn-add-handler.djn-model-%s" % (
            group_id, base_model_identifier)
        add_els = self.selenium.find_elements_by_css_selector(add_selector)
        self.assertNotEqual(len(add_els), 0,
            "No inline add handlers found for %s" % (error_desc))
        self.click(add_els[0])

        add_link_selector = "return $('.polymorphic-type-menu:visible [data-type=\"%s\"]')[0]" % (
            model_name)
        poly_add_link = self.selenium.execute_script(add_link_selector)

        if poly_add_link:
            poly_add_link.click()

        indexes = self._normalize_indexes(indexes)

        group_el = self.selenium.execute_script(
            'return $(arguments[0]).closest(".djn-group")[0]', add_els[0])
        group_id = group_el.get_attribute('id')

        items_el = self.selenium.find_element_by_css_selector(
            '#%(id)s > .djn-fieldset > .djn-items, '
            "#%(id)s > .tabular.inline-related > .djn-fieldset > .djn-items, "
            '#%(id)s > .djn-items' % {'id': group_id})

        num_inlines = len(items_el.find_elements_by_xpath(
            './*[%s and not(%s)]' % (xpath_item(), xpath_cls('djn-empty-form'))))

        new_index = num_inlines - 1

        indexes.append([model_name, new_index])
        for field_name, val in six.iteritems(kwargs):
            self.set_field(field_name, val, indexes=indexes)
        return indexes
Ejemplo n.º 5
0
 def delete_inline(self, indexes):
     indexes = self._normalize_indexes(indexes)
     model_id = indexes[-1][0]
     app_label, model_name = model_id.split('-')
     model_cls = apps.get_model(app_label, model_name)
     if issubclass(model_cls, PolymorphicModel):
         base_model_cls = get_base_polymorphic_model(model_cls)
     else:
         base_model_cls = model_cls
     base_model_id = "%s-%s" % (base_model_cls._meta.app_label,
                                base_model_cls._meta.model_name)
     item_id = self.get_item(indexes).get_attribute('id')
     delete_selector = "#%s .djn-delete-handler.djn-model-%s" % (
         item_id, base_model_id)
     with self.clickable_selector(delete_selector) as el:
         self.click(el)
     if self.has_grappelli:
         undelete_selector = "#%s.grp-predelete .grp-delete-handler.djn-model-%s" % (
             item_id, base_model_id)
         self.wait_until_clickable_selector(undelete_selector)
Ejemplo n.º 6
0
 def delete_inline(self, indexes):
     indexes = self._normalize_indexes(indexes)
     model_id = indexes[-1][0]
     app_label, model_name = model_id.split('-')
     model_cls = apps.get_model(app_label, model_name)
     if issubclass(model_cls, PolymorphicModel):
         base_model_cls = get_base_polymorphic_model(model_cls)
     else:
         base_model_cls = model_cls
     base_model_id = "%s-%s" % (
         base_model_cls._meta.app_label, base_model_cls._meta.model_name)
     item_id = self.get_item(indexes).get_attribute('id')
     delete_selector = "#%s .djn-delete-handler.djn-model-%s" % (
         item_id, base_model_id)
     with self.clickable_selector(delete_selector) as el:
         self.click(el)
     if self.has_grappelli:
         undelete_selector = "#%s.grp-predelete .grp-delete-handler.djn-model-%s" % (
             item_id, base_model_id)
         self.wait_until_clickable_selector(undelete_selector)
    def test_get_base_polymorphic_model(self):
        """
        Test that finding the base polymorphic model works.
        """
        # Finds the base from every level (including lowest)
        self.assertIs(get_base_polymorphic_model(Model2D), Model2A)
        self.assertIs(get_base_polymorphic_model(Model2C), Model2A)
        self.assertIs(get_base_polymorphic_model(Model2B), Model2A)
        self.assertIs(get_base_polymorphic_model(Model2A), Model2A)

        # Properly handles multiple inheritance
        self.assertIs(get_base_polymorphic_model(Enhance_Inherit), Enhance_Base)

        # Ignores PolymorphicModel itself.
        self.assertIs(get_base_polymorphic_model(PolymorphicModel), None)
Ejemplo n.º 8
0
 def get_item(self, indexes):
     indexes = self._normalize_indexes(indexes)
     group_indexes = indexes[:-1]
     model_id, item_index = indexes[-1]
     app_label, model_name = model_id.split('-')
     model_cls = apps.get_model(app_label, model_name)
     if issubclass(model_cls, PolymorphicModel):
         base_model_cls = get_base_polymorphic_model(model_cls)
     else:
         base_model_cls = model_cls
     base_model_id = "%s-%s" % (base_model_cls._meta.app_label,
                                base_model_cls._meta.model_name)
     try:
         group = self.get_group(indexes=group_indexes + [base_model_id])
     except TypeError:
         group = self.get_group(indexes=group_indexes + [model_id])
     group_id = group.get_attribute('id')
     djn_items = self.selenium.find_element_by_css_selector(
         "#%(id)s > .djn-fieldset > .djn-items, "
         "#%(id)s > .tabular.inline-related > .djn-fieldset > .djn-items, "
         "#%(id)s > .djn-items" % {'id': group_id})
     model_name, item_index = indexes[-1]
     return djn_items.find_element_by_xpath("./*[%s][%d]" %
                                            (xpath_item(), item_index + 1))
Ejemplo n.º 9
0
 def get_item(self, indexes):
     indexes = self._normalize_indexes(indexes)
     group_indexes = indexes[:-1]
     model_id, item_index = indexes[-1]
     app_label, model_name = model_id.split('-')
     model_cls = apps.get_model(app_label, model_name)
     if issubclass(model_cls, PolymorphicModel):
         base_model_cls = get_base_polymorphic_model(model_cls)
     else:
         base_model_cls = model_cls
     base_model_id = "%s-%s" % (
         base_model_cls._meta.app_label, base_model_cls._meta.model_name)
     try:
         group = self.get_group(indexes=group_indexes + [base_model_id])
     except TypeError:
         group = self.get_group(indexes=group_indexes + [model_id])
     group_id = group.get_attribute('id')
     djn_items = self.selenium.find_element_by_css_selector(
         "#%(id)s > .djn-fieldset > .djn-items, "
         "#%(id)s > .tabular.inline-related > .djn-fieldset > .djn-items, "
         "#%(id)s > .djn-items" % {'id': group_id})
     model_name, item_index = indexes[-1]
     return djn_items.find_element_by_xpath(
         "./*[%s][%d]" % (xpath_item(), item_index + 1))
Ejemplo n.º 10
0
    def __init__(self, model, admin_site, *args, **kwargs):
        super(PolymorphicChildModelAdmin,
              self).__init__(model, admin_site, *args, **kwargs)

        if self.base_model is None:
            self.base_model = get_base_polymorphic_model(model)
Ejemplo n.º 11
0
    def save_existing_objects(self, initial_forms=None, commit=True):
        """
        Identical to parent class, except ``self.initial_forms`` is replaced
        with ``initial_forms``, passed as parameter.
        """
        if not initial_forms:
            return []

        saved_instances = []

        forms_to_delete = self.deleted_forms

        for form in initial_forms:
            pk_name = self._pk_field.name

            if not hasattr(form, '_raw_value'):
                # Django 1.9+
                raw_pk_value = form.fields[pk_name].widget.value_from_datadict(
                    form.data, form.files, form.add_prefix(pk_name))
            else:
                raw_pk_value = form._raw_value(pk_name)

            # clean() for different types of PK fields can sometimes return
            # the model instance, and sometimes the PK. Handle either.
            if self._should_delete_form(form):
                pk_value = raw_pk_value
            else:
                try:
                    pk_value = form.fields[pk_name].clean(raw_pk_value)
                except ValidationError:
                    # The current form's instance was initially nested under
                    # a form that was deleted, which causes the pk clean to
                    # fail (because the instance has been deleted). To get
                    # around this we clear the pk and save it as if it were new.
                    with mutable_querydict(form.data):
                        form.data[form.add_prefix(pk_name)] = ''

                    if not form.has_changed():
                        form.__dict__['changed_data'].append(pk_name)

                    saved_instances.extend(
                        self.save_new_objects([form], commit))
                    continue
                pk_value = getattr(pk_value, 'pk', pk_value)

            obj = None
            if obj is None and form.instance and pk_value:
                model_cls = form.instance.__class__
                try:
                    obj = model_cls.objects.get(pk=pk_value)
                except model_cls.DoesNotExist:
                    if pk_value and force_str(
                            form.instance.pk) == force_str(pk_value):
                        obj = form.instance
            if obj is None:
                obj = self._existing_object(pk_value)

            if obj is None or not obj.pk:
                continue

            if form in forms_to_delete:
                self.deleted_objects.append(obj)
                model_cls = type(obj)
                base_model_cls = get_base_polymorphic_model(type(obj))
                if not base_model_cls:
                    self.delete_existing(obj, commit=commit)
                else:
                    # Special polymorphic delete handling
                    try:
                        self.delete_existing(obj, commit=commit)
                    except base_model_cls.DoesNotExist:
                        pass
                continue

            # fk_val: The value one should find in the form's foreign key field
            old_ct_val = ct_val = ContentType.objects.get_for_model(
                self.instance.__class__).pk
            old_fk_val = fk_val = self.instance.pk
            if form.instance.pk:
                original_instance = self.model.objects.get(pk=form.instance.pk)
                fk_field = getattr(self, 'fk',
                                   getattr(self, 'ct_fk_field', None))
                if fk_field:
                    old_fk_val = getattr(original_instance,
                                         fk_field.get_attname())
                ct_field = getattr(self, 'ct_field', None)
                if ct_field:
                    old_ct_val = getattr(original_instance,
                                         ct_field.get_attname())

            if form.has_changed(
            ) or fk_val != old_fk_val or ct_val != old_ct_val:
                self.changed_objects.append((obj, form.changed_data))
                saved_instances.append(
                    self.save_existing(form, obj, commit=commit))
                if not commit:
                    self.saved_forms.append(form)
        return saved_instances