Introduction
One of the development communities I'm involved with has a store to help people download projects, but the store has no comment or voting capability. To find the good projects, we have to download and test each project ourselves. To help the community share the tests and feedback, my friend and I built a simple review site with Django in one day.
You can see the live site below, create an account, practice "liking" entries, and see the content upload capability.
Although the site still needs polishing, I had fun getting something up quickly with Django and letting people upload their own content the day after I came up with the idea to build the site.
Background
The site interface is simple, with a listing of the project icon, a review title, review summary, and like button for the review.
The core part of the project was to create a user login to accomplish these goals:
- limit content creation and votes to only people that logged in
- list username with review
- require login to download some assets that required agreement from the user such as sample code or special technical information from the vendor
Registration is handled with a simple HTML form.
Once you're logged in, you can vote and submit content.
Using the Code
The full views.py file to create the account, login, and logout is here:
Account Creation
The section that creates the account is:
user = User.objects.create_user(request.POST['username'], password=request.POST['password1'],
email=request.POST['email'])
auth.login(request, user)
Content Creation
Content creation is handled by another views.py file that is available at:
I ran into difficulties with detecting a blank image upload field. The code for how I handled this problem is:
if not request.FILES.get('icon', False):
plugin.icon = 'theta_logo.png'
else:
plugin.icon = request.FILES['icon']
if not request.FILES.get('image', False):
plugin.image = 'invisible.png'
else:
plugin.image = request.FILES['image']
Even after searching on the Internet and Stackoverflow, I still couldn't set a default image in the model. I ended up using the following process:
- save a default logo and an invisible 1 pixel image into the
media
folder - check for an empty image with
request.FILES.get('name_from_form', False)
- if the image is blank, set it to the default image
plugin.image
and plugin.icon
refer to the fields defined in models.py.
image = models.ImageField(upload_to='images/')
icon = models.ImageField(upload_to='images/')
The full models.py is at:
Order by Newest Post First
The newest post is at the top of the list. This was surprisingly simple to implement with order_by('-pk')
. The key part is the minus sign before the primary key 'pk
'. The minus sign reverses the order.
def home(request):
plugins = ThetaPlugins.objects.order_by('-pk')
return render(request, 'theta_plugins/home.html', {'plugins': plugins})
Protecting Content
Gating content such as technical documentation that requires agreement is easy if you connect the account creation to an agreement of the terms of service or license. In views.py file, you can use the @login_required
decorator to gate the content or action. That's all you need to do.
from django.shortcuts import render
from django.contrib.auth.decorators import login_required
def home(request):
return render(request, 'theta_plugins/home.html')
@login_required
def create(request):
return render(request, 'theta_plugins/create.html')
Points of Interest
The most interesting part of the project was to allow people to create their own content and interact with the site with features like "thumbs up". Django makes this amazingly fast and easy. If web designers are primarily using tools like Bootstrap, CSS, HTML, it may be at first seem difficult to create a full site to handle user-generated content and voting. However, once you get started, everything will fall into place and you'll be able to finish your project. Django is an old web framework, but that means there are many tutorials out there for free and almost every problem you encounter has already been solved by other people.
Next Steps
The text input is the weakest part of the application. I'm considering implementing a simple Markdown Editor in Vue based on this simple example:
History
- 21st August, 2019: Initial version