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))
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)
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
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)
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