Giter VIP home page Giter VIP logo

django-publish's Introduction

Django Publish

Handy mixin/abstract class for providing a "publisher workflow" to arbitrary Django models.

Overview

  • You make your model extend publish.models.Publishable
  • Each model instance then has some extra state information and a reference to it's "public" version, as well as extra methods to control "publishing" drafts
  • You register your model with the admin and a ModelAdmin class that extends publish.admin.PublishableAdmin
  • The admin then only shows you "draft" (and "deleted") instances
  • You work on the draft instances, then when you are happy "publish" the draft values to the public instances

How to

Let's say you have an app with a simple models.py that looks this this:

from django.db import models

class MyModel(models.Model):
    title = models.CharField(max_length=100)

    class Meta:
        ordering = ["title"]

and an admin.py:

from django.contrib import admin

from models import MyModel

class MyModelAdmin(admin.ModelAdmin):
    pass

admin.site.register(MyModel, MyModelAdmin)

Then to make this model support publishing you would change the models.py thus:

from django.db import models
from publish.models import Publishable

class MyModel(Publishable): # extends from Publishable instead of models.Model
    title = models.CharField(max_length=100)

    class Meta(Publish.Meta): # note you should extend from Publish.Meta
        ordering = ["title"]

That will add some extra fields to your model (so you may need to update your db). At this point though the admin will show both the draft and published objects. We obviously do not want that, as we want the user to edit the draft objects and then "publish" them once they are happy. So we have to alter the admin.py file too:

from django.contrib import admin
from publish.admin import PublishableAdmin

from models import MyModel

class MyModelAdmin(PublishableAdmin): # just extend from PublishableAdmin instead
    pass

admin.site.register(MyModel, MyModelAdmin)

At this point the admin will start showing an action to "Publish selected MyModels" as well as details of an objects "Publication status". Publishing will show a confirmation page - much like when deleting - confirming what is about to be published (possibly including related objects).

You will then need to modify your views to handle showing only the published or draft objects. You'll probably want some way to view both versions on your site somehow. The Publishable model has a custom manager with some extra methods for this purpose, but you can also use a Q object on the Publishable class too:

# these two will return only the "draft" objects
MyModel.objects.draft()
MyModel.objects.filter(Publishable.Q_DRAFT)

# these will give you the "published" objects
MyModel.objects.published()
MyModel.objects.filter(Publishable.Q_PUBLISHED)

The latter form is handy, as the Q object can be passed in as a paramter to a view function - allowing for easy re-use of the same view function for both previewing draft objects and viewing live objects.

In addition to modifying your views, you may want to consider changing any get_absolute_url functions to correctly return the relevant URL for viewing the object - taking into account whether it is a published or draft object (using the is_public field). The PublishableAdmin class automatically provides a link to the published (View on site) and draft (Preview on site) versions if a model has implemented get_absolute_url.

The classes PublishableStackedInline and PublishableTabularInline are also available for handling inline editing of Publishable child models.

from django.contrib import admin
from publish.admin import PublishableAdmin, PublishableTabularInline

from models import MyModel, MyChildModel

class MyChildModelInline(PublishableTabularInline):
    model = MyChildModel

class MyModelAdmin(PublishableAdmin):
    inlines = [ MyChildModelInline ]

admin.site.register(MyModel, MyModelAdmin)

You'll also need to add a PublishMeta field to the parent model, so that it will also publish the child models whenever it is published:

from django.db import models
from publish.models import Publishable

class MyModel(Publishable): # extends from Publishable instead of models.Model
    title = models.CharField(max_length=100)

    class Meta(Publish.Meta): # note you should extend from Publish.Meta
        ordering = ["title"]

    class PublishMeta(Publishable.PublishMeta):
        publish_reverse_fields = ['mychildmodel_set'] # name of reverse relation


class MyChild(Publishable):
    mymodel = models.ForeignKey(MyModel)

Signals

There are two signals that can be listened to during the publish process:

  • publish.signals.pre_publish
  • publish.signals.post_publish

The handlers for these signals should have the form

def post_publish_handler(sender, instance, deleted, **kw):

Where instance will be the object being published - much as with the built-in Django signals pre_save and post_save. Note though that publishing an object may trigger multiple pre and post publish signals, depending on what other objects also need publishing. However that you should not receive the same signal for the same object - only for different objects.

The signals are triggered both for publishing changes and publishing deletions. When a change is published you will receive the draft object as the instance and deleted will be False. When a deletion is published you will receive the public instance (as that is what is being deleted) and deleted will be set to True.

As with the post_delete signal in Django you will need to take care when using the instance if deleted is True, as the object will no longer exist in the database.

Finer control

You can further control the publication process by providing a PublishMeta class on your model

from publish.models import Publishable
from django.db import models

class Page(Publishable):
    title = models.CharField(max_length=100)
    slug  = models.SlugField(max_length=100)
    body  = models.TextField()
    notes = models.TextField(blank=True)

    class PublishMeta(Publishable.PublishMeta):
        publish_exclude_fields = ['notes']

In the above class the "notes" field will be excluded from publication - it will not be copied to the public copy.

There are two other fields that can be specified:

  • publish_reverse_fields - list of reverse/child relationships to publish
  • publish_functions - dictionary of 'fieldname' : publish_function (same format as setattr)

Publish functions are useful if you need to run some additional action when publishing an object. For example you may want copy a file to a public location or subtly modify a value as it gets copied. A publish function is expected to work the same as the built-in setattr, but may (and probably will) have other side-effects.

Notes

  • A ManyToManyField specified using a "through" model will be treated as a regular reverse relationship, but will automatically be published (no need to specify it via PublishableMeta.publish_reverse_fields)

Tests

To run the tests for this app use the script:

tests/run_tests.sh

django-publish's People

Contributors

johnsensible avatar lilspikey avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

django-publish's Issues

Updates

Hello.

Are you planning to update this repository? Thanks

Permissions

I'm using django-publish on a site, where I use permissions.
However, I can't seem to find the permission for Can Publish and assign it.
I'm not sure if this is an error or incorrect installation.

does not work for Django 1.2

trying to use the project in django 1.2. gives me the following error:
cannot import name get_change_view_url

publish/actions.py in
4. from django.contrib.admin.util import get_change_view_url, model_ngettext ...

after a little bit of digging I found that
get_change_view_url was removed in svn revision 12598
http://code.djangoproject.com/changeset?old_path=django/trunk/django/contrib/admin/util.py&old=12598&new_path=django/trunk/django/contrib/admin/util.py&new=12598

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.