The fourth version of Röda Tråden, now written in Django!
Röda tråden is a website primarily used by students at Umeå University to navigate and organize their study materials. The website provides a structured and overview platform where students can find course information, schedules, learning materials, and other relevant information for their studies. It is designed to help students in their academic journey by bringing everything they need together in one place.
Django is a Python-based web framework. Tactically chosen since students at Teknisk Fysik is more familiar with Python than most other languages used in web frameworks. It is also very modular and does a lot of work for you, which is good when the development eventually moves to other people.
More information can be found on their website. If you are very new to this framework, I heavily recommend that you first go through the project "Writing your first Django app" to get an idea of how the framework is structured.
For the beginner, I will here quickly describe how to download and install this repository. The first case is for local development. The second case is for production on your site. Note: This guide will be tailored towards Linux users, as I only ever use Linux. With some quick searching, I found this article which might help with installation on Windows.
-
Clone this repository to your computer by
git clone https://github.com/it-amanuens/rodatraden/. -
Install a virtual environment in the root path directory of the repository by executing
python -m venv .venvand then activate it. On linux you can activate it by runningsource .venv/bin/activate. Windows has.\.venv\Scripts\activate -
Enter the cloned git repository
cd rodatraden. Enter the foldertf, copy the filesettings-template.pytosettings.py, and edit the file with your favorite editor. -
Since this is for local development, not much has to be changed. However, the variable
DATABASEShas to be changed to suit your setup. Django supports a myriad of databases. This project is configured for MySQL, and a guide on how to set up a local MySQL-server can be found here. -
After your database is set up, change the settings in the
settings.pyfile and save. -
In your virtual environment, install all of the required packages by running
pip install -r requirements.txtin the cloned repository. -
Make new migrations for your database by running
python manage.py makemigrationsin the cloned repository. After this, migrate to the database by runningpython manage.py migrate. -
If everything went well and it is all set up, start the server by running
python manage.py runserver. Your local version should then be accessible via 127.0.0.1:8000 in your browser. Congratulations! -
Take down the project again to create the new superuser (ctrl + c to shutdown server). This user is used for manage the instance and setup courses and can be created with:
python manage.py createsuperuserRestart the server (step 8).
I assume that you already have an http server with e.g. Apache or Nginx and a database setup. This guide will focus on linux. For windows see section lower down
-
Follow steps 1-4 in the local development section.
-
Set up a media folder e.g.
var/www/namedmediawith a folder inside calledprofiles. The userwww-datashould have read and write access to this folder. This could be done by adding a group to the folders wherewww-datais included, and runchmod 770 -R media. -
In the
tf/settings.py-file more has to be changed than for local development.- Change the
SECRET_KEYto a random 20-30 character string. - Set
DEBUG=False. - Add the server address to
ALLOWED_HOSTS. - Add database information in the variable
DATABASES. - Set the
MEDIA_ROOTvariable to the writeable media folder setup in step 2.
- Change the
-
Save the
settings.py-file. -
Run
python manage.py makemigrationsandpython manage.py migrateto fill the database. -
Run
python manage.py collectstaticto gather all the static files to the site root folder. -
Everything should be ready to be configured with your HTTP-server. This step is mostly up to you and what you prefer to do. Django supports
WSGI, and more detailed explanations can be found here. A possible deployment method is to run the server withpython manage.py runserverand use a proxy to redirect requests to127.0.0.1, but I can't give more detail than that. (one more detail, uncomment wfastcgi in requirements.txt on windows)
I assume that you already have a Windows Server with IIS enabled (including the CGI role service) and Python installed system-wide (for example C:\Python312). This guide focuses on deployment using IIS and FastCGI (wfastcgi).
If not, i recomend reading through these two:
https://www.toptal.com/developers/django/installing-django-on-iis-a-step-by-step-tutorial
https://blog.devgenius.io/deploy-django-app-to-iis-windows-server-beginners-guide-with-images-3d03b6fd5b7e
This setup has not been fully tested on Windows, so some adjustment is probably neccesary depending on your environment.
-
Follow steps 1-4 in the local development section.
-
Set up a media folder e.g.
C:\inetpub\rodatraden\namedmediawith a folder inside calledprofiles. The IIS application pool user for your site (for exampleIIS AppPool\rodatraden) must have read and write access to this folder. This can be done by running:icacls "C:\inetpub\rodatraden\media" /grant "IIS AppPool\rodatraden":(OI)(CI)M -
In the
tf/settings.py-file more has to be changed than for local development.- Change the
SECRET_KEYto a random 20-30 character string. - Set
DEBUG=False. - Add the server address or domain to
ALLOWED_HOSTS. - Add database information in the variable
DATABASES. If using SQLite, ensure the database file has write permissions. - Set the
MEDIA_ROOTvariable to the writeable media folder setup in step 2.
- Change the
-
Save the
settings.py-file. -
Run
python manage.py makemigrationsandpython manage.py migrateto fill the database. -
Run
python manage.py collectstaticto gather all the static files to the site root folder. -
Everything should be ready to be configured with IIS. Unlike Linux (WSGI), Windows typically uses FastCGI via
wfastcgi.-
Install FastCGI support:
pip install wfastcgi -
Grant the IIS application pool user read and execute access to the entire project folder (this is especially important for the virtual environment):
icacls "C:\inetpub\rodatraden" /grant "IIS AppPool\rodatraden":(OI)(CI)RX -
In IIS Manager:
- Add a Website pointing to your project root folder.
- Add a Module Mapping using the FastCgiModule, pointing the script
processor to your virtual environment
python.exeandwfastcgi.py. - Set required environment variables such as
DJANGO_SETTINGS_MODULE.
-
Since Django does not serve static files in production, create a Virtual Directory in IIS:
- Alias:
static - Physical path: your collected static files folder.
python manage.py collectstaticto create the static folder.
- Alias:
-
Also add the media folder to IIS to serve user uploaded files.
Note: if IIS routes
static/mediato Python instead of serving files, open thestaticandmediavirtual directories, remove any Python handler, then add a Module Mapping:Request path=*,Module=StaticFileModule,Executable=(blank),Name=StaticFile. Enable "Invoke handler only if request is mapped to: File or folder". Ensure "Static Content" is installed. -
-
Restart IIS and verify that the site loads correctly.
If you don't want to migrate data from an old instance, then you will have to create new the all new data from scratch.
New super users can be created in django by running this command python manage.py createsuperuser
After this navigate to the admin interface. Here we will have to add entries like "akademiska år", "institutioner" "Nivåer", "Spår" and "Tidsperioder".
- Akademiska år : The study year (You probably want a few courses here)
- Institutioner : The institution / faculty where the course can be / is taken
- Nivåer : If it's an advanced course or not (grundläggande / avancerad)
- Spår : The different tracks that can be choosen. Make a profile before on the main site
- Tidsperioder : This is when during the year a course starts. For example week 0 for "läsperiod 1", week 10 for "läsperiod 2" Week 0 is the beginning of time academic year. If a course starts 3 weeks into period 2, then specify week 13.
After after creating these, new courses can be added to the default site
This repository now includes a GitHub Actions workflow that runs when you push a version tag (v*).
It will:
- Create a GitHub Release from the tag
- Build a Docker image from
Dockerfile - Publish the image to GitHub Container Registry as
ghcr.io/<owner>/rodatraden
- Ensure you are on the branch you want to release (usually
master) and push your latest changes. - Create and push a semantic version tag:
git tag v1.0.0git push origin v1.0.0 - Wait for the workflow to finish in the GitHub Actions tab.
Example:
docker pull ghcr.io/<owner>/rodatraden:v1.0.0
-
python -Xutf8 ./manage.py dumpdata --natural-foreign --natural-primary -e contenttypes -e auth.Permission --indent 2 -o data.json(more info can be found here: https://www.coderedcorp.com/blog/how-to-dump-your-django-database-and-load-it-into-/) -
We then have to copy over the media folder (if the images uploaded to Rödatråden should be saved). Easy methode is just to zip and send over the media folder.
-
When setting up the new instance, first run
python manage.py migrateto create the new migration table. -
Restore user data using
python manage.py loaddata data.json -
Extract the media folder to same directory (project-root/media/)
This project includes a compose template focused on local development/testing, using the same file locations as local non-Docker setup.
The compose setup mounts these host paths directly into the container:
- Database file:
mydatabase - Uploaded media:
media/ - Collected static:
static/ - Source/config:
tf/,rodatraden/,templates/
This means Docker and local development use the same files.
If you want a clean test instance, back up and remove mydatabase.
- Copy compose template:
cp docker-compose-template.yml docker-compose.yml - Copy settings template:
cp tf/settings-template.py tf/settings.pyand edittf/settings.pyas needed. - Build and start:
docker compose up --build -d - Open a shell in the running container:
docker compose exec rodatraden sh - Run Django setup commands manually inside the container:
python manage.py makemigrationspython manage.py migratepython manage.py createsuperuser - Exit shell:
exit - Open:
http://127.0.0.1:8000
For production, create a docker-compose.override.yml alongside your docker-compose.yml.
Docker Compose automatically merges it, so you don't need to change the base file.
# docker-compose.override.yml
services:
rodatraden:
labels:
- "traefik.enable=true"
- "traefik.http.routers.rodatraden.rule=Host(`yourdomain.com`)"
- "traefik.http.routers.rodatraden.entrypoints=websecure"
- "traefik.http.routers.rodatraden.tls.certresolver=myresolver"
- "traefik.http.services.rodatraden.loadbalancer.server.port=8000"
networks:
- default
- traefik
reverse-proxy:
image: traefik:v3.6
command:
- --providers.docker=true
- --providers.docker.endpoint=unix:///var/run/docker.sock
- --providers.docker.exposedbydefault=false
- --entrypoints.web.address=:80
- --entrypoints.web.http.redirections.entrypoint.to=websecure
- --entrypoints.web.http.redirections.entrypoint.scheme=https
- --entrypoints.websecure.address=:443
- --certificatesresolvers.myresolver.acme.tlschallenge=true
- --certificatesresolvers.myresolver.acme.email=your@email.com
- --certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json
- --log.level=INFO
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./letsencrypt:/letsencrypt
networks:
- traefik
restart: unless-stopped
networks:
traefik:
external: falseReplace your@email.com with your real email (used by Let's Encrypt for cert notifications) and yourdomain.com with your domain. The letsencrypt/ folder will be created automatically to store certificates.
Also update tf/settings.py for production:
- Set
SECRET_KEYto a long random string - Set
DEBUG = False - Add your domain to
ALLOWED_HOSTS, e.g.['yourdomain.com'] - Add your domain to
CSRF_TRUSTED_ORIGINS, e.g.['https://yourdomain.com']
We are using depbot to get updates for dependencies automatically. Some dependencies especially node dependencies will have to be updated manually.
They are specified in package.json file.
To update these, you will have to run "npm install"
Then you copy them all
cp node_modules/chart.js/dist/chart.umd.min.js rodatraden/static/assets/js/
cp node_modules/d3/dist/d3.min.js rodatraden/static/assets/js/
cp node_modules/popper.js/dist/umd/popper.min.js rodatraden/static/assets/js/
cp node_modules/select2/dist/js/select2.min.js rodatraden/static/assets/js/
cp node_modules/select2/dist/css/select2.min.css rodatraden/static/assets/css/
And run collect static for static files to work:
python manage.py collectstatic