= Django-ForRunners

{{https://raw.githubusercontent.com/jedie/django-for-runners/master/src/for_runners/static/Django-ForRunners128.png|Logo}} Store your GPX tracks of your running (or other sports activity) in django.

| {{https://github.com/jedie/django-for-runners/workflows/test/badge.svg?branch=master|Build Status on github}} | [[https://github.com/jedie/django-for-runners/actions|github.com/jedie/django-for-runners/actions]] |
| {{https://codecov.io/gh/jedie/django-for-runners/branch/master/graph/badge.svg|Coverage Status on codecov.io}} | [[https://codecov.io/gh/jedie/django-for-runners|codecov.io/gh/jedie/django-for-runners]] |
| {{https://coveralls.io/repos/jedie/django-for-runners/badge.svg|Coverage Status on coveralls.io}} | [[https://coveralls.io/r/jedie/django-for-runners|coveralls.io/r/jedie/django-for-runners]] |

(The name **Django-ForRunners** has the origin from the great Android tracking app **ForRunners** by Benoît Hervier: http://rvier.fr/#forrunners )

== Features:

* GPX track management:
** Upload GPX tracks
** Import GPX tracks from commandline
** Track analysis:
*** basics: Track length / Duration / Pace / Hart rate Up-/Downhill
*** Display route on OpenStreetMap map
*** Graphs with elevation / heart rate / cadence (if available in GPX data)
** Data that is automatically extracted from the web:
*** Start/finish Address from OpenStreetMap
*** Start/finish weather information from metaweather.com
** Store additional data:
*** Ideal track distance (for easier grouping/filtering tracks)
* sports competitions Management:
** Create a List of Sport Events
*** Add participation to a event
*** link GPX track with a event participation
*** Store you event participation:
**** official track length
**** measured finisher time
**** Number of participants who have finished in your discipline
*** Add links to webpages relatet to this event
*** Record costs (entry fee, T-shirt etc.)
* common
** Multiple user support (However: no rights management and currently only suitable for a handful of users)


== Project structure

There are two main directories:

|= directory |= description
| **[[https://github.com/jedie/django-for-runners/tree/master/src|/src/]]**               | The main  Django-ForRunners source code
| **[[https://github.com/jedie/django-for-runners/tree/master/deployment|/deployment/]]** | deploy  Django-ForRunners for production use case

== install

There exists two kind of installation/usage:

* local development installation using poetry
* production use with docker-compose
* Install as [[https://yunohost.org|YunoHost]] App via [[https://github.com/YunoHost-Apps/django-for-runners_ynh|django-for-runners_ynh]]

This README contains only the information about local development installation.

Read [[https://github.com/jedie/django-for-runners/tree/master/deployment#readme|/deployment/README]] for instruction to install  Django-ForRunners on a root server.


=== prepare

{{{
~$ git clone https://github.com/jedie/django-for-runners.git
~$ cd django-for-runners/
~/django-for-runners$ make
_________________________________________________________________
DjangoForRunners - *dev* Makefile

install-poetry         install or update poetry
install                install DjangoForRunners via poetry
manage-update          Collectstatic + makemigration + migrate
update                 update the sources and installation
lint                   Run code formatters and linter
fix-code-style         Fix code formatting
tox-listenvs           List all tox test environments
tox                    Run pytest via tox with all environments
tox-py36               Run pytest via tox with *python v3.6*
tox-py37               Run pytest via tox with *python v3.7*
tox-py38               Run pytest via tox with *python v3.8*
pytest                 Run pytest
update-rst-readme      update README.rst from README.creole
publish                Release new version to PyPi
run-dev-server         Run the django dev server in endless loop.
createsuperuser        Create super user
messages               Make and compile locales message files
dbbackup               Backup database
dbrestore              Restore a database backup
run-docker-dev-server  Start docker containers with current dev source code
}}}


=== local development installation

{{{
# install or update Poetry:
~/django-for-runners$ make install-poetry

# install  Django-ForRunners via poetry:
~/django-for-runners$ make install
...

# Collectstatic + makemigration + migrate:
~/django-for-runners$ make manage-update

# Create a django super user:
~/django-for-runners$ ./manage.sh createsuperuser

# start local dev. web server:
~/django-for-runners$ make run-dev-server
}}}

The web page is available in Port 8000, e.g.: {{{http://127.0.0.1:8000/}}}


=== local docker dev run

You can run the deployment docker containers with current source code with:
{{{
~/django-for-runners$ make run-docker-dev-server
}}}
Just hit Cntl-C to stop the containers

The web page is available on Port 80, e.g.: {{{http://localhost/}}}


=== import GPX files

e.g.:

{{{
~/django-for-runners$ poetry run manage import_gpx --username <django_username> ~/backups/gpx_files
}}}

**Note:** It is no problem to start **import_gpx** with the same GPX files: Duplicate entries are avoided. The start/finish (time/latitude/longitude) are compared.


=== backup

Create a backup into {{{.../backups/<timestamp>/}}} e.g.:
{{{
~/django-for-runners$ poetry run for_runners backup
}}}

The backup does:

 * backup the database
 * export all GPX tracks
 * generate .csv files:
    * a complete file with all running tracks
    * one file for every user


=== regenerate all SVG files

{{{
~/django-for-runners$ poetry run for_runners recreate-svg
}}}


== Screenshots


(All screenshots are here: [[https://github.com/jedie/jedie.github.io/tree/master/screenshots/django-for-runners|github.com/jedie/jedie.github.io/tree/master/screenshots/django-for-runners]])


== for-runers v0.6.0 2018-07-31 GPX Track.png ==
{{https://raw.githubusercontent.com/jedie/jedie.github.io/master/screenshots/django-for-runners/for-runers v0.6.0 2018-07-31 GPX Track.png|for-runers v0.6.0 2018-07-31 GPX Track.png}}


== for-runners v0.4.0 2018-6-26 GPX info.png ==
{{https://raw.githubusercontent.com/jedie/jedie.github.io/master/screenshots/django-for-runners/for-runners v0.4.0 2018-6-26 GPX info.png|for-runners v0.4.0 2018-6-26 GPX info.png}}


== for-runners v0.6.0 2018-07-19 Event Costs.png ==
{{https://raw.githubusercontent.com/jedie/jedie.github.io/master/screenshots/django-for-runners/for-runners v0.6.0 2018-07-19 Event Costs.png|for-runners v0.6.0 2018-07-19 Event Costs.png}}


== print a small overview ==

{{https://raw.githubusercontent.com/jedie/jedie.github.io/master/screenshots/django-for-runners/for-runners v0.10.0 2010-06-26 print small overview 1.png|for-runners v0.10.0 2010-06-26 print small overview 1.png}}

{{https://raw.githubusercontent.com/jedie/jedie.github.io/master/screenshots/django-for-runners/for-runners v0.10.0 2010-06-26 print small overview 2.png|for-runners v0.10.0 2010-06-26 print small overview 2.png}}


== run tests

{{{
~/Django-ForRunners$ make test

or:

~/Django-ForRunners$ make tox
}}}


**Note:**

To run all tests, you need:

* **Chromium Browser WebDriver** e.g.: {{{apt install chromium-chromedriver}}}
* **Firefox Browser WebDriver** aka **geckodriver**

install **geckodriver** e.g.:
{{{
~$ cd /tmp
/tmp$ wget https://github.com/mozilla/geckodriver/releases/download/v0.20.1/geckodriver-v0.20.1-linux64.tar.gz -O geckodriver.tar.gz
/tmp$ sudo sh -c 'tar -x geckodriver -zf geckodriver.tar.gz -O > /usr/bin/geckodriver'
/tmp$ sudo chmod +x /usr/bin/geckodriver
/tmp$ rm geckodriver.tar.gz
/tmp$ geckodriver --version
geckodriver 0.20.1
...
}}}



== some notes


=== GPX storage

Currently we store the unchanged GPX data in a TextField.


=== static files

We collect some JavaScript files, for easier startup. These files are:

|= Project Homepage |= License |= storage directory
| [[http://leafletjs.com|leafletjs.com]] | [[https://github.com/Leaflet/Leaflet/blob/master/LICENSE|Leaflet licensed under BSD]] | [[https://github.com/jedie/django-for-runners/tree/master/for_runners/static/leaflet|for_runners/static/leaflet/]]
| [[http://dygraphs.com|dygraphs.com]] | [[https://github.com/danvk/dygraphs/blob/master/LICENSE.txt|dygraphs licensed under MIT]] | [[https://github.com/jedie/django-for-runners/tree/master/for_runners/static/dygraphs|for_runners/static/dygraphs/]]
| [[http://www.chartjs.org|chartjs.org]] | [[https://github.com/chartjs/Chart.js/blob/master/LICENSE.md|Chart.js licensed under MIT]] | [[https://github.com/jedie/django-for-runners/tree/master/for_runners/static/chartjs|for_runners/static/chartjs/]]


=== Precision of coordinates

GPX files from Garmin (can) contain:

* latitude with 29 decimal places
* longitude with 28 decimal places
* elevation with 19 decimal places

The route on OpenStreetMap does not look more detailed, with more than 5 decimal places.

See also: https://wiki.openstreetmap.org/wiki/Precision_of_coordinates


== Django compatibility

|= django-for-runners |= django version |= python         |
| >=v0.11.0           | 2.2.x LTS       | 3.7, 3.8, 3.9   |
| >=v0.7.1            | 2.1             | 3.5, 3.6, 3.7   |
| v0.5.x              | 2.0             | 3.5, 3.6, 3.7   |

(See also combinations in [[https://github.com/jedie/django-for-runners/blob/master/tox.ini|tox.ini]] and [[https://github.com/jedie/django-for-runners/blob/master/.github/workflows/pythonapp.yml|github actions]])



== Backwards-incompatible changes

Older changes, see:

https://github.com/jedie/django-for-runners/blob/v0.10.1/README.creole#backwards-incompatible-changes

=== v0.12.0

Move main project sources into "/src/"
Add deployment setup into "/development/"

== history

* [[https://github.com/jedie/django-for-runners/compare/v0.12.1...master|compare v0.12.1...master]] **dev**
** tbc
* [[https://github.com/jedie/django-for-runners/compare/v0.12.0...v0.12.1|22.11.2021 - v0.12.1]]:
** update requirements
* [[https://github.com/jedie/django-for-runners/compare/v0.11.0...v0.12.0|17.01.2021 - v0.12.0]]:
** refactor project structure and add a deployment via docker-compose setup
** installation as YunoHost app: https://github.com/YunoHost-Apps/django-for-runners_ynh
** Add django-axes and django-processinfo
** Mock requests in tests
* [[https://github.com/jedie/django-for-runners/compare/v0.10.1...v0.11.0|04.07.2020 - v0.11.0]]:
** refactor gpx import code
** update tests
** Use poetry and add Makefile
** update code style
* [[https://github.com/jedie/django-for-runners/compare/v0.10.0...v0.10.1|09.08.2019 - v0.10.1]]:
** Enhance "Event Participation" admin view: Add start date and costs in table
* [[https://github.com/jedie/django-for-runners/compare/v0.9.0...v0.10.0|26.06.2019 - v0.10.0]]:
** NEW: GPX Admin action to print a small overview from one or a few tracks
** Accept optional server bind address, e.g.: {{{for_runners run-server 127.0.0.1:8080}}}
* [[https://github.com/jedie/django-for-runners/compare/v0.8.1...v0.9.0|02.04.2019 - v0.9.0]]:
** NEW: Update complete environment installation with: {{{for_runners update}}}
** Move the SQlite database to virtualenv root dir, e.g.: {{{~/Django-ForRunners/Django-ForRunners-database.sqlite3}}}
** NEW: save every gpx track to disk
** NEW: Backup/export via cli: {{{$ for_runners backup}}}
** NEW: export GPX Data via {{{django-import-export}}}
** Create xdg-open desktop starter under linux here: {{{~/Django-ForRunners/Django-ForRunners}}}
** refactor the startup process:
*** auto loop the server process
*** open web browser on first start
*** enable autotask
** rename {{{for_runners_test_project}}} to {{{for_runners_project}}}
* [[https://github.com/jedie/django-for-runners/compare/v0.8.0...v0.8.1|03.09.2018 - v0.8.1]]:
** Fix "try-out" section in README, again ;(
* [[https://github.com/jedie/django-for-runners/compare/v0.7.1...v0.8.0|03.09.2018 - v0.8.0]]:
** NEW: shell script for easier boot/install, see above
* [[https://github.com/jedie/django-for-runners/compare/v0.7.0...v0.7.1|02.09.2018 - v0.7.1]]:
** Update to Django 2.1
** Bugfix Tests
* [[https://github.com/jedie/django-for-runners/compare/v0.6.0...v0.7.0|02.09.2018 - v0.7.0]]:
** Use dygraphs in GPX Track change admin view
** Sync mouse over from Elevation/Headrate/Cadence dygraphs to leaflet open streep map
** Fix "try-out" section in README ([[https://github.com/jedie/django-for-runners/pull/1|Thanks adsworth for reporting]])
** Add links from gpx tracks to other admin change view
** Bugfixes
** internals:
*** refactor stuff around track duration/length
*** move manipluation of list_display and list_filter [[https://github.com/jedie/django-for-runners/pull/2|contributed by adsworth]]
* [[https://github.com/jedie/django-for-runners/compare/v0.5.0...v0.6.0|19.07.2018 - v0.6.0]]:
** NEW: event participation
** NEW: costs of event participation (e.g.: entry fee for the competition, cost of a T-Shirt etc.)
** NEW: Display statistics of events/costs per user and total
* [[https://github.com/jedie/django-for-runners/compare/v0.4.0...v0.5.0|04.07.2018 - v0.5.0]]:
** remove Django-CMS
** update to Django v2.0
** NOTE: The migrations are simply replaced! So you must delete your database, e.g.: {{{src/django-for-runners$ rm test_project_db.sqlite3}}}
** Add 'net duration' field, for the officially measured time and use it for calculations if available.
** Create django manage command to fill some base data: {{{$ ./manage.py fill_basedata}}}
** speedup by deactivating some django debug toolbar panels
* [[https://github.com/jedie/django-for-runners/compare/v0.3.0...v0.4.0|26.06.2018 - v0.4.0]]:
** combine track filters with statistic views
** NEW: GPX info (See length, point count and Average distance in meters between the points)
** NEW: Display GPX metadata
** Add 'creator' to every track and use it as changelist filter
** remove Streetmap image generated via [[https://pypi.org/project/geotiler/|geotiler]]
** Speedup by using a cache for gpxpy instances
* [[https://github.com/jedie/django-for-runners/compare/v0.2.0...v0.3.0|23.06.2018 - v0.3.0]]:
** Start adding statistics (See screenshot above)
** add weather information from [[https://www.metaweather.com/|metaweather.com]] to every track
* [[https://github.com/jedie/django-for-runners/compare/v0.1.1...v0.2.0|21.06.2018 - v0.2.0]]:
** Display elevations, heart_rates and cadence_values if available
** Add kilometer markers to OpenStreetMap
* [[https://github.com/jedie/django-for-runners/compare/v0.1.0...v0.1.1|15.06.2018 - v0.1.1]]:
** a few bugfixes
* [[https://github.com/jedie/django-for-runners/compare/v0.0.4...v0.1.0|15.06.2018 - v0.1.0]]:
** Render interactive OpenStreetMap track map with Leaflet JS
* [[https://github.com/jedie/django-for-runners/compare/v0.0.3...v0.0.4|12.06.2018 - v0.0.4]]:
** Better Events model
** GPX error handling
** more tests
** Bugfix for Python 3.5 (Geotiler needs Python 3.6 or later)
* [[https://github.com/jedie/django-for-runners/compare/v0.0.2...v0.0.3|12.06.2018 - v0.0.3]]:
** display min/average/max heart rate
** use autotask to generate the MAP in background
* [[https://github.com/jedie/django-for-runners/compare/v0.0.1...v0.0.2|31.05.2018 - v0.0.2]]:
** generate SVG 'icon' from GPX track
* v0.0.1 - 30.05.2018
** Just create a pre-alpha release to save the PyPi package name ;)


== links ==

| Homepage   | http://github.com/jedie/django-for-runners
| PyPi       | https://pypi.org/project/django-for-runners/


=== activity exporter ===

It's sometimes hard to find a working project for exporting activities.
So here tools that i use currently:

* [[https://github.com/rsjrny/Garmin-Connect-Export|Garmin-Connect-Export]] from rsjrny


=== alternatives (OpenSource only) ==

* https://github.com/pytrainer/pytrainer (Desktop Program)
* https://github.com/GoldenCheetah/GoldenCheetah/ (Desktop Program)

Online tools:

* https://www.j-berkemeier.de/ShowGPX.html (de)


== credits ==

The whole thing is based on many excellent projects. Especially the following:

* [[https://pypi.org/project/gpxpy/|gpxpy]] GPX file parser
* [[https://leafletjs.com|Leaflet JS]] A JS library for interactive maps used to render the track on [[https://openstreetmap.org/|OpenStreetMap]]
* [[http://dygraphs.com|dygraphs]] open source JavaScript charting library
* [[https://www.chartjs.org|Chart.js]] HTML5 Charts
* [[https://pypi.org/project/geopy/|geopy]] Get geo location names of the GPX track start/end point
* [[https://pypi.org/project/matplotlib/|matplotlib]] plotting 2D graphics
* [[https://pypi.org/project/autotask/|autotask]] schedule background jobs
* [[https://pypi.org/project/svgwrite/|svgwrite]] Generating SVG file


== donation ==

* [[https://www.paypal.me/JensDiemer|paypal.me/JensDiemer]]
* [[https://flattr.com/submit/auto?uid=jedie&url=https%3A%2F%2Fgithub.com%2Fjedie%2Fdjango-for-runners%2F|Flattr This!]]
* Send [[http://www.bitcoin.org/|Bitcoins]] to [[https://blockexplorer.com/address/1823RZ5Md1Q2X5aSXRC5LRPcYdveCiVX6F|1823RZ5Md1Q2X5aSXRC5LRPcYdveCiVX6F]]
