Allowing HTML in Text Fields on a Django Site

One of the things I really wanted to be able to do with my Django blog project was display HTML in my blog posts. I just wanted to be able to use links and some basic formatting. While undertaking this task, I learned a little more about how Django itself works. Like, some stuff updates while your server is running. But some stuff will not take effect until you restart. Read on and you’ll see what I mean.

When I began my research, I first came across the ‘safe’ filter. This is included with Django and can be used in templates like this (surrounded by double curly braces):

post.text | safe | linebreaksbr


By default, Django escapes HTML tags. This stops it from doing that. It definitely isn’t a recommended option if you have users entering data since you can’t trust them (sorry users). Since I’m the only one posting though, I figured it would be okay, at least for the moment. However, it wasn’t working – or didn’t appear to be.

So, I went looking further. I came across a module called django-bleach which appeared to be exactly what I was looking for. I installed it, added the necessary import and changed the TextField in my post model to a BleachField. Unless I just wasn’t reading the documentation correctly, that was all that should have been required for it to work. But, it didn’t. So I then added my own list of allowed tags and attributes, but it still wasn’t working. And then, out of sheer frustration, I added the safe filters back to my templates. And it worked. I don’t know if this happens to other people or not, but I honestly don’t remember at what points I’d restarted my server during all this. I was operating under the assumption that changes would take effect while it was running, and that if they weren’t all I had to do was Ctrl+Shift+R for a hard refresh. That worked for CSS at least. But it apparently doesn’t work for some stuff. Like safe filters.

I decided to get rid of the Django safe filters because I figured it was more safe to just have bleach filtering the tags I chose. And for whatever reason, at that point I did restart my server, and all my awesome HTML was gone. Around this time was when I began to understand that my testing wasn’t really being done properly as I needed to be restarting between these changes, so I had to test everything again. That was how I came to realize that the safe filters worked all along, but django-bleach did not. I’m pretty sad about that, as it seemed like an awesome module. And, I mean, maybe it does work and I was missing something. I’ll probably revisit it later.

In my research I did also come across two modules that allow rich text editing: Django CKeditor and django-tinymce. I didn’t want to add more to my site than I had to, especially since it’s only on free hosting, and I didn’t feel I needed these modules since I’m fine with writing HTML the few times I want it. But I realize they would be a better option in many cases and wanted to include them for anyone reading.

I hope that this was useful information for someone somewhere. I struggled with this issue for longer than I should have when really, all along I just needed to restart my server! But I did learn some interesting things along the way, so it wasn’t a complete waste of time I guess.

Deploying a Django Site to Heroku

I recently deployed a Django website to Heroku for the very first time. It’s a blog, but it’s more of a project for my portfolio than a real blog I intend to maintain. If I ever decide to go to that much effort for one site for myself it will be for a browser-based game like Kingdom of Loathing.

Anyway, I was finishing up the Django Girls tutorial where we deploy our finished website to Heroku, and I ran into some problems. I found it frustrating trying to find how to fix everything that was wrong, and when I finally did I decided to document my experience in case anyone else can benefit.

My blog has PostgreSQL as the database which I understand is the default on Heroku. Your experience may differ if you’re using a different database. Also, disclaimer: I’m not an expert, but this worked for me and I’ll explain as well as I can.

I’m not going to tell you everything from the beginning because it’s already been done so well on the Django Girls tutorial. You should go there first and follow the instructions, but come back here before deploying, because it will not work.

One important thing I’d like to mention is that you shouldn’t put your database password or your SECRET_KEY straight into your settings.py file. This won’t necessarily hurt the functionality of your site but it’s bad practice as they aren’t protected. Instead you should use environmental variables. I’ll probably post about them in more detail at a later date. For now, just know that you can install python-dotenv and adjust your settings.py like this:

from dotenv import load_dotenv

load dotenv()

...

SECRET_KEY = os.getenv('SECRET_KEY')

Write your database password in the same way as the SECRET_KEY. Then, make a file called .env in the same folder as your settings.py file. In this file enter your secrets:

SECRET_KEY=yoursecretkeyhere
DATABASE_PASSWORD=yourdatabasepassword

Keep in mind that your variable names have to match. You could technically call these whatever you want but remember that they are variables and have to be referenced by what you write in this file.

Your site should now run locally, but you still have to share your secrets with Heroku. Luckily this is really easy. Just go to your Heroku dashboard, select your app, go to settings and hit the ‘Reveal config vars’ button. Here is where you put in your secrets.

Now you have to solve a problem. Try and deploy your Heroku app now if you want, but it probably won’t work because it won’t be able to collect your static files. Remember when Django Girls had you enter this in your wsgi.py file?:

from whitenoise.django import DjangoWhiteNoise
application = DjangoWhiteNoise(application)

Go ahead and delete those lines. That information is outdated. Instead, you do this in your settings.py file:

MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'whitenoise.middleware.WhiteNoiseMiddleware',
...

The new line is the ‘whitenoise’ one, but I included the others so you can see where it has to be positioned. Right after the security line and before the others. That’s it. This made my static files stop working, but I fixed it by moving the folder from my blog app folder to my base project folder – whether that is ‘best practice’ or not, I do not know, but it’s what worked for me. At this point I thought I’d fixed my problem and went to try deploying again, and again, it did not work. My research took me to Heroku’s deployment guide for Django apps. After doing what we’ve just done with whitenoise, they want you to put this in your settings.py file:

BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.9/howto/static-files/
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
STATIC_URL = '/static/'

# Extra places for collectstatic to find static files.
STATICFILES_DIRS = (
os.path.join(BASE_DIR, 'static'),
)

This broke my static files again locally. My static folder is called ‘static’, by the way. To fix my static files I had to make STATIC_ROOT point to ‘static’ and STATICFILES_DIRS point to ‘staticfiles’ (I got errors when I tried making them both point to ‘static’. I tried deploying to Heroku again, and again, it did not work. In a whirl of frustration I started trying random things and my deploy finally worked when I simply commented out the STATICFILES_DIRS line.

At that point I was super excited, but my live site didn’t work – I was getting a 500 Server Error page. I realised it was database related, since I had a static page which worked just fine and could also get into the admin panel. I made my superuser and entered the admin console, but couldn’t load anything in the database. So, back to Google. Someone said that running manage.py makemigrations and migrate on the server was the solution. It was not. Then, someone said Heroku needed the migrations folder. Now, I had added that to .gitignore, since I had read that you could get conflicts if there were different migrations folders being merged into a repository. I also had the impression you just made the migrations again on the server after deploying. I always try to do what is considered best practice, but apparently that information was wrong. I unignored my migrations folder, pushed to Heroku again, and did ‘heroku run python manage.py migrate’ to…. migrate the migrations! Well, that worked.

I’m going to mention here that I realise the Django Girls site has you run migrate once your site is up. But at this point it had been like three hours since I’d left the tutorial, and I’d forgotten all about it.

Now you’ve hopefully got your site up and running! It doesn’t matter how simple it is; I feel getting it deployed is a huge step after the ordeal it was for me and it’s something you can be proud of.