Medium-like editor for Django part two

In the last post, we talked about what a Medium-like editor looks like and some preliminary concepts about Django web framework. In this post, we are going to build a simple version of Medium-like editor. Image upload function will be covered in the next post.

The main packages we are going to use are Medium Editor JavaScript plugin and Django wrapper for it. Thanks for all the contributors for the packages that make our life so much easier.

Installing

I highly recommend using Bower to manage JavaScript and CSS packages.

$ npm install -g bower

Create a .bowerrc file under your project home directory to config Bower.

{
"directory": "path/to/bower_components"
}

All the installed packages will go into the directory specified above.

Then we can install our magic package.

bower install medium-editor

To install the Django wrapper,

https://github.com/g3rd/django-mediumeditor

The wrapper has all the JavaScript and CSS out of the box. The only thing you need to do is to hook up the form textfield with MediumEditorTextarea widget.

Assume you have a simple post model in your models.py.

class Post(models.Model):
title = models.CharField(max_length=200)
pub_date = models.DateTimeField()
text = models.TextField()
slug = models.SlugField(max_length=200, unique=True)
    def get_absolute_url(self):
return "/%s" % self.slug
    def get_edit_url(self):
return "/post/%s/edit" % self.pk

Serve the request of creating a new post in views.py

@login_required
def new_post(request):
if request.method == "POST":
form = PostForm(data=request.POST)
if form.is_valid():
post = form.save(commit=False)
return redirect(post.get_absolute_url())
else:
form = PostForm()
return render(request, 'blogengine/new_post.html', {'form': form})

Routes the url requests in urls.py

url(r'^post/create/$', 'blogengine.views.new_post'),
url(r'^(?P<slug>[a-zA-Z0-9-]+)/?$', PostDetail.as_view(), name='post-detail'),

Test Driven

Let's first create a test for our new feature. We then write our code to fix the test.

In tests.py

from django.core.urlresolvers import reverse

...

# Parent class for common methods

class BaseAcceptTest(LiveServerTestCase, TestUtils):

fixtures = ["users.json"]

def setUp(self):

self.client = Client() class PostViewTest(BaseAcceptTest):

    def test_medium_editor(self):
self.client.login(username='your-user-name', password= 'password')
response = self.client.get(reverse('blogengine.views.new_post'))
self.assertTrue("django-mediumeditor-editable" in response.content.decode('utf-8'))

If your run

python manage.py test

The test will fail and that is exactly what we want. Now we roll up our sleeves to make it pass.


Add the Django wrapper to your INSTALLED_APPS in settings.py

INSTALLED_APPS = [
...
'mediumeditor',
]

In the forms.py, add the MediumEditorTextarea widget to 'text' field.

class PostForm(forms.ModelForm):

def save(self, commit=True):
post = super(PostForm, self).save(commit=False)
post.save(commit)
return post
class Meta:
model = Post
fields = ('title','text')
widgets = {
'text': MediumEditorTextarea(),
}

To make all the JavaScripts work, you need to include them in your HTML file.

Django form has a media field where you could define all your js files there and include them in your template.

In widgets.py,

class MediumEditorTextarea(forms.Textarea):
...
class Media:
js = (
'bower_components/jquery/dist/jquery.min.js',
'bower_components/medium-editor/dist/js/medium-editor.js',
'js/mediumeditor/django-mediumeditor.js',
)

In the head tag of your html file, 

<head> ...

<link rel="stylesheet" type="text/css" href="{% static 'bower_components/medium-editor/dist/css/medium-editor.min.css' %}"> <link rel="stylesheet" type="text/css" href="{% static 'css/mediumeditor/django-mediumeditor.css' %}"> <link rel="stylesheet" type="text/css" href="{% static 'bower_components/medium-editor/dist/css/themes/beagle.css' %}"> {{ form.media }} </head>

Now you should have a working Medium-like editor on your Django website. 

Run the test again.

python manage.py test

All green! Good.

Optional

Theme

In medium-editor/dist/css/themes folder, there are lots of themes you can choose to prettify your tool bar.

Format editor area style

You can write your own CSS code in django-mediumeditor.css to change the style of the text area. For me, I like remove the border and change the font size. Makes it more medium-like :-)

Add more buttons to tool bar

MediumEditor is initialized in django-mediumeditor.js. You can add more buttons under the tool bar and you can even design your own buttons by following the guide here.