Example #1
0
def publish_selected(modeladmin, request, queryset):
    queryset = queryset.select_for_update()
    opts = modeladmin.model._meta
    app_label = opts.app_label

    all_published = NestedSet()
    for obj in queryset:
        obj.publish(dry_run=True, all_published=all_published)

    perms_needed = []
    _check_permissions(modeladmin, all_published, request, perms_needed)

    if request.POST.get('post'):
        if perms_needed:
            raise PermissionDenied

        n = queryset.count()
        if n:
            for object in all_published:
                modeladmin.log_publication(request, object)

            queryset.publish()

            modeladmin.message_user(
                request,
                _("Successfully published %(count)d %(items)s.") % {
                    "count": n,
                    "items": model_ngettext(modeladmin.opts, n)
                })
            # Return None to display the change list page again.
            return None

    admin_site = modeladmin.admin_site

    context = {
        "title": _("Publish?"),
        "object_name": force_unicode(opts.verbose_name),
        "all_published":
        _convert_all_published_to_html(admin_site, all_published),
        "perms_lacking": _to_html(admin_site, perms_needed),
        'queryset': queryset,
        "opts": opts,
        "root_path": _root_path(admin_site),
        "app_label": app_label,
        'action_checkbox_name': helpers.ACTION_CHECKBOX_NAME,
    }

    # Display the confirmation page
    return render_to_response(
        modeladmin.publish_confirmation_template or [
            "admin/%s/%s/publish_selected_confirmation.html" %
            (app_label, opts.object_name.lower()),
            "admin/%s/publish_selected_confirmation.html" % app_label,
            "admin/publish_selected_confirmation.html"
        ],
        context,
        context_instance=template.RequestContext(request))
Example #2
0
    def publish_deletions(self,
                          all_published=None,
                          parent=None,
                          dry_run=False):
        '''
        actually delete models that have been marked for deletion
        '''
        if self.publish_state != Publishable.PUBLISH_DELETE:
            return

        if all_published is None:
            all_published = NestedSet()

        if self in all_published:
            return

        all_published.add(self, parent=parent)

        self._pre_publish(dry_run, all_published, deleted=True)

        for related in self._meta.get_all_related_objects():
            if not issubclass(related.model, Publishable):
                continue
            name = related.get_accessor_name()
            if name in self.PublishMeta.excluded_fields():
                continue
            try:
                instances = getattr(self, name).all()
            except AttributeError:
                instances = [getattr(self, name)]
            for instance in instances:
                instance.publish_deletions(all_published=all_published,
                                           parent=self,
                                           dry_run=dry_run)

        if not dry_run:
            public = self.public
            self.delete(mark_for_deletion=False)
            if public:
                public.delete(mark_for_deletion=False)

        self._post_publish(dry_run, all_published, deleted=True)
Example #3
0
    def publish_deletions(self, all_published=None, parent=None,
                          dry_run=False):
        '''
        actually delete models that have been marked for deletion
        '''
        if self.publish_state != Publishable.PUBLISH_DELETE:
            return

        if all_published is None:
            all_published = NestedSet()

        if self in all_published:
            return

        all_published.add(self, parent=parent)

        self._pre_publish(dry_run, all_published, deleted=True)

        for related in self._meta.get_all_related_objects():
            if not issubclass(related.model, Publishable):
                continue
            name = related.get_accessor_name()
            if name in self.PublishMeta.excluded_fields():
                continue
            try:

                instances = getattr(self, name).all()
            except AttributeError:
                instances = [getattr(self, name)]
            for instance in instances:
                instance.publish_deletions(all_published=all_published,
                                           parent=self, dry_run=dry_run)

        if not dry_run:
            public = self.public
            self.delete(mark_for_deletion=False)
            if public:
                public.delete(mark_for_deletion=False)

        self._post_publish(dry_run, all_published, deleted=True)
Example #4
0
    def publish_changes(self, dry_run=False, all_published=None, parent=None):
        '''
        publish changes to the model - basically copy all of it's content to another copy in the 
        database.
        if you set dry_run=True nothing will be written to the database.  combined with
        the all_published value one can therefore get information about what other models
        would be affected by this function
        '''

        assert not self.is_public, "Cannot publish public model - publish should be called from draft model"
        assert self.pk is not None, "Please save model before publishing"

        # avoid mutual recursion
        if all_published is None:
            all_published = NestedSet()

        if self in all_published:
            return all_published.original(self).public

        all_published.add(self, parent=parent)        

        self._pre_publish(dry_run, all_published)

        public_version = self.public
        if not public_version:
            public_version = self.__class__(is_public=True)
        
        excluded_fields = self.PublishMeta.excluded_fields()
        reverse_fields_to_publish = self.PublishMeta.reverse_fields_to_publish()
        
        if self.publish_state == Publishable.PUBLISH_CHANGED:
            # copy over regular fields
            for field in self._meta.fields:
                if field.name in excluded_fields:
                    continue
                
                value = getattr(self, field.name)
                if isinstance(field, RelatedField):
                    related = field.rel.to
                    if issubclass(related, Publishable):
                        if value is not None:
                            value = value._get_public_or_publish(dry_run=dry_run, all_published=all_published, parent=self)
                
                if not dry_run:
                    publish_function = self.PublishMeta.find_publish_function(field.name, setattr)
                    publish_function(public_version, field.name, value)
        
            # save the public version and update
            # state so we know everything is up-to-date
            if not dry_run:
                public_version.save()
                self.public = public_version
                self.publish_state = Publishable.PUBLISH_DEFAULT
                self.save(mark_changed=False)
        
        # copy over many-to-many fields
        for field in self._meta.many_to_many:
            name = field.name
            if name in excluded_fields:
                continue
            
            m2m_manager = getattr(self, name)
            public_objs = list(m2m_manager.all())

            field_object, model, direct, m2m = self._meta.get_field_by_name(name)
            through_model = self._get_through_model(field_object)
            if through_model:
                # see if we can work out which reverse relationship this is
                # see if we are using our own "through" table or not
                if issubclass(through_model, Publishable):
                    # this will be db name (e.g. with _id on end)
                    m2m_reverse_name = field_object.m2m_reverse_name()
                    for reverse_field in through_model._meta.fields:
                        if reverse_field.column == m2m_reverse_name:
                            related_name = reverse_field.name
                            related_field = getattr(through_model, related_name).field
                            reverse_name = related_field.related.get_accessor_name()
                            reverse_fields_to_publish.append(reverse_name)
                            break
                    continue # m2m via through table won't be dealt with here

            related = field_object.rel.to
            if issubclass(related, Publishable):
                public_objs = [p._get_public_or_publish(dry_run=dry_run, all_published=all_published, parent=self) for p in public_objs]
            
            if not dry_run:
                public_m2m_manager = getattr(public_version, name)
                old_objs = public_m2m_manager.exclude(pk__in=[p.pk for p in public_objs])
                public_m2m_manager.remove(*old_objs)
                public_m2m_manager.add(*public_objs)

        # one-to-many and one-to-one reverse relations
        for obj in self._meta.get_all_related_objects():
            if issubclass(obj.model, Publishable):
                name = obj.get_accessor_name()
                if name in excluded_fields:
                    continue
                if name not in reverse_fields_to_publish:
                    continue
                if obj.field.rel.multiple:
                    related_items = getattr(self, name).all()
                else:
                    try:
                        related_items = [getattr(self, name)]
                    except obj.model.DoesNotExist:
                        related_items = []

                for related_item in related_items:
                    related_item.publish(dry_run=dry_run, all_published=all_published, parent=self)
                
                # make sure we tidy up anything that needs deleting
                if self.public and not dry_run:
                    if obj.field.rel.multiple:
                        public_ids = [r.public_id for r in related_items]
                        deleted_items = getattr(self.public, name).exclude(pk__in=public_ids)
                        deleted_items.delete(mark_for_deletion=False)
        
        self._post_publish(dry_run, all_published)

        return public_version
Example #5
0
 def publish(self, all_published=None):
     '''publish all models in this queryset'''
     if all_published is None:
         all_published = NestedSet()
     for p in self:
         p.publish(all_published=all_published)
Example #6
0
    def publish_changes(self, dry_run=False, all_published=None, parent=None):
        '''
        publish changes to the model - basically copy all of it's content to another copy in the
        database.
        if you set dry_run=True nothing will be written to the database.  combined with
        the all_published value one can therefore get information about what other models
        would be affected by this function
        '''

        assert not self.is_public, "Cannot publish public model - publish should be called from draft model"
        assert self.pk is not None, "Please save model before publishing"

        # avoid mutual recursion
        if all_published is None:
            all_published = NestedSet()

        if self in all_published:
            return all_published.original(self).public

        all_published.add(self, parent=parent)

        self._pre_publish(dry_run, all_published)

        public_version = self.public
        if not public_version:
            public_version = self.__class__(is_public=True)

        excluded_fields = self.PublishMeta.excluded_fields()
        reverse_fields_to_publish = self.PublishMeta.reverse_fields_to_publish(
        )

        if self._changes_need_publishing():
            # copy over regular fields
            for field in self._meta.fields:
                if field.name in excluded_fields:
                    continue

                value = getattr(self, field.name)
                if isinstance(field, RelatedField):
                    related = field.rel.to
                    if issubclass(related, Publishable):
                        if value is not None:
                            value = value._get_public_or_publish(
                                dry_run=dry_run,
                                all_published=all_published,
                                parent=self)

                if not dry_run:
                    publish_function = self.PublishMeta.find_publish_function(
                        field.name, setattr)
                    publish_function(public_version, field.name, value)

            # save the public version and update
            # state so we know everything is up-to-date
            if not dry_run:
                public_version.save()
                self.public = public_version
                self.publish_state = Publishable.PUBLISH_DEFAULT
                self.save(mark_changed=False)

        # copy over many-to-many fields
        for field in self._meta.many_to_many:
            name = field.name
            if name in excluded_fields:
                continue

            m2m_manager = getattr(self, name)
            public_objs = list(m2m_manager.all())

            field_object, model, direct, m2m = self._meta.get_field_by_name(
                name)
            through_model = self._get_through_model(field_object)
            if through_model:
                # see if we can work out which reverse relationship this is
                # see if we are using our own "through" table or not
                if issubclass(through_model, Publishable):
                    # this will be db name (e.g. with _id on end)
                    m2m_reverse_name = field_object.m2m_reverse_name()
                    for reverse_field in through_model._meta.fields:
                        if reverse_field.column == m2m_reverse_name:
                            related_name = reverse_field.name
                            related_field = getattr(through_model,
                                                    related_name).field
                            reverse_name = related_field.related.get_accessor_name(
                            )
                            reverse_fields_to_publish.append(reverse_name)
                            break
                    continue  # m2m via through table won't be dealt with here

            related = field_object.rel.to
            if issubclass(related, Publishable):
                public_objs = [
                    p._get_public_or_publish(dry_run=dry_run,
                                             all_published=all_published,
                                             parent=self) for p in public_objs
                ]

            if not dry_run:
                public_m2m_manager = getattr(public_version, name)

                old_objs = public_m2m_manager.exclude(
                    pk__in=[p.pk for p in public_objs])
                public_m2m_manager.remove(*old_objs)
                public_m2m_manager.add(*public_objs)

        # one-to-many and one-to-one reverse relations
        for obj in self._meta.get_all_related_objects():
            if issubclass(obj.model, Publishable):
                name = obj.get_accessor_name()
                if name in excluded_fields:
                    continue
                if name not in reverse_fields_to_publish:
                    continue
                if obj.field.rel.multiple:
                    related_items = getattr(self, name).all()
                else:
                    try:
                        related_items = [getattr(self, name)]
                    except (obj.model.DoesNotExist, ObjectDoesNotExist):
                        related_items = []

                for related_item in related_items:
                    related_item.publish(dry_run=dry_run,
                                         all_published=all_published,
                                         parent=self)

                # make sure we tidy up anything that needs deleting
                if self.public and not dry_run:
                    if obj.field.rel.multiple:
                        public_ids = [r.public_id for r in related_items]
                        deleted_items = getattr(
                            self.public, name).exclude(pk__in=public_ids)
                        deleted_items.delete(mark_for_deletion=False)

        self._post_publish(dry_run, all_published)

        return public_version