The audio is in Bangla, you can switch to HD video by toggling the youtube settings.
(I do not prepare the scripts beforehand, so please apologize my clumsiness) .
The audio is in Bangla, you can switch to HD video by toggling the youtube settings.
(I do not prepare the scripts beforehand, so please apologize my clumsiness) .
In this post, we would like to see how we can limit user accesses to our Django views.
If you have worked with Django, you probably have used the login_required
decorator already. Adding the decorator to a view limits access only to the logged in users. If the user is not logged in, s/he is redirected to the default login page. Or we can pass a custom login url to the decorator for that purpose.
Let’s see an example:
1 2 3 4 5 |
from django.contrib.auth.decorators import login_required @login_required def secret_page(request): return render_to_response("secret_page.html") |
There’s another nice decorator – permission_required
which works in a similar fashion:
1 2 3 4 5 |
from django.contrib.auth.decorators import permission_required @permission_required('entity.can_delete', login_url='/loginpage/') def my_view(request): return render_to_response("entity/delete.html") |
Awesome but let’s learn how do they work internally.
We saw the magic of the login_required
and permission_required
decorators. But we’re the men of science and we don’t like to believe in magic. So let’s unravel the mystery of these useful decorators.
Here’s the code for the login_required
decorator:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
def login_required(function=None, redirect_field_name=REDIRECT_FIELD_NAME, login_url=None): """ Decorator for views that checks that the user is logged in, redirecting to the log-in page if necessary. """ actual_decorator = user_passes_test( lambda u: u.is_authenticated(), login_url=login_url, redirect_field_name=redirect_field_name ) if function: return actual_decorator(function) return actual_decorator |
By reading the code, we can see that the login_required
decorator uses another decorator – user_passes_test
which takes/uses a callable to determine whether the user should have access to this view. The callable must accept an user instance and return a boolean value. user_passes_test
returns a decorator which is applied to our view.
If we see the source of permission_required
, we would see something quite similar. It also uses the same user_passes_test
decorator.
Now that we know how to limit access to a view based on whether the logged in user passes a test, it’s quite simple for us to build our own decorators for various purposes. Let’s say we want to allow access only to those users who have verified their emails.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
from django.contrib.auth.decorators import user_passes_test from django.contrib.auth import REDIRECT_FIELD_NAME def check_email_verification(user): return EmailVerification.objects.all().filter(user=user, verified=True) def check_email(function=None, redirect_field_name=REDIRECT_FIELD_NAME, login_url=None): """ Decorator for views that checks that the user is logged in, redirecting to the log-in page if necessary. """ actual_decorator = user_passes_test( check_email_verification, login_url=login_url, redirect_field_name=redirect_field_name ) if function: return actual_decorator(function) return actual_decorator |
Now we can use the decorator to a view like:
1 2 3 4 |
@login_required @check_email(login_url="/redirect/login/?reason=verify_email") def verified_users_only(request): return render_to_response("awesome/offers.html") |
Users who have verified their email addresses will be able to access this view. And if they didn’t, they will be redirected to the login view. Using the reason
query string, we can display a nice message explaining what’s happening.
Please note, we have used two decorators on the same view. We can use multiple decorators like this to make sure the user passes all the tests we require them to.
I assume you are already familiar with Docker and it’s use cases. If you haven’t yet started using Docker, I strongly recommend you do soon.
I have a Django application that I want to dockerize it for local development. I am also new to Docker, so everything I do in this post might not be suitable for your production environment. So please do check Docker best practices for production apps. This tutorial is meant to be a basic introduction to Docker. In this post, I am going to use Docker Machine and Docker Compose. You can get them by installing the awesome Docker Toolbox.
Before we start, we need to break down our requirements so we can individually build the required components. For my particular application, we need these:
We will build images for these separately so we can create individual containers and link them together to compose our ultimate application. We shall build our Django App server and use pre-built images for MySQL and Redis.
Before we begin, let’s talk Dockerfile
s. Dockerfiles are scripts to customize our docker builds. It allows us control and flexibility over how we build the images for our applications. We will use our custom Dockerfile to build the Django app server.
To build an image for a Django application we need to go through these following steps:
Here’s the Dockerfile we shall use:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
FROM phusion/baseimage MAINTAINER masnun ENV DEBIAN_FRONTEND noninteractive RUN apt-get update RUN apt-get install -y python python-pip python-dev RUN apt-get install -y libxml2-dev libxslt-dev libffi-dev libssl-dev RUN apt-get install -y libmysqlclient-dev ADD requirements.txt /app/src/requirements.txt WORKDIR /app/src RUN pip install -r requirements.txt WORKDIR /app/src/lisp CMD [ "python", "manage.py", "runall"] EXPOSE 8000 |
So what are we doing here:
phusion/baseimage
as our base image. It’s a barebone image based on Ubuntu. Ubuntu by default comes with many packages which we don’t need to run inside docker. This base image gets rid of those and provides a very lean and clean image to start with. DEBIAN_FRONTEND
to be non interactive. This will not display any interactive prompts during the build process. Since the docker build process is automated, we really don’t have any way to interact during it. So we disable interaction. And as you might have guessed already ENV
sets an environment variable.requirements.txt
file to /app/src/requirements.txt
, change the work directory and install the packages using pip. ADD
is used to copy any files or directories to the container while it builds. You might wonder why we didn’t copy over our entire project – that’s because we want to use docker for our development. We will use a nice featire of Docker which would allow us to mount our local directories directly inside the container. Doing this, we would not need to copy files every time they change. More on this will come later./app/src/lisp
and run the runall
management command. This command runs the Django default server along with some other services my application needs. But usually we would want to just do runserver
EXPOSE
port 8000If you go through the Dockerfile References you will notice – we can do a lot more with Dockerfiles.
As we mentioned earlier, we shall use pre-built images for MySQL and Redis. We could build them ourselves too but why not take advantage of the well maintained images from the generous folks in the docker community?
We can link multiple docker containers to compose a final application. We can do that using the docker
command manually. But Docker Compose is a very nice tool which allows us to define the services we need in a very easy to read syntax. With docker compose, we don’t need to run them manually, we can just use simple commands to do complex docker magic! Here’s our docker-compose.yml
file:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
web: build: . restart: always volumes: - .:/app/src ports: - "8000:8000" links: - redis - mysql redis: image: redis:latest volumes: - /var/lib/redis ports: - "6379" mysql: image: mysql:latest volumes: - /var/lib/mysql ports: - "3306:3306" environment: MYSQL_ROOT_PASSWORD: su53RsEc53T! |
In our docker-compose file, we define 3 components:
build
key. We ask to restart always and define volumes to mount. .:/app/src
means – mount the current directory on my OS X as /app/src/
on the container. We also define which ports to expose and which containers should be linked with itimage
key. Please make sure the volume
paths exist and are accessible. You can consult the Compose File Reference for more details.
To run the application, we can do:
1 |
docker-compose up |
Please note, the Django server might throw errors if the MySQL / Redis server takes time to initialize. So I usually run them separately:
1 2 3 4 5 6 |
docker-compose start mysql docker-compose start redis # After some time docker-compose start web |
Our MySQL server is running on the IP of the Docker Machine. You need to use this IP address in your Django settings file. To get the IP of a docker machine, type in:
1 2 |
# Here `default` is the machine name docker-machine ip default |
We can pass a MYSQL_DATABASE
environment value to the mysql
image so the database is created when creating the service. Or we can also connect to the docker machine manually and create our databases.