From 5a21ef5986f4eb6c710141e2994b4f5eb3fa22a1 Mon Sep 17 00:00:00 2001 From: Jakob Klepp Date: Sat, 15 Feb 2020 11:34:08 +0100 Subject: [PATCH 1/7] Create mycelium project --- .gitignore | 6 + django_mycelium/__init__.py | 0 django_mycelium/asgi.py | 16 +++ django_mycelium/settings.py | 122 ++++++++++++++++ django_mycelium/urls.py | 21 +++ django_mycelium/wsgi.py | 16 +++ manage.py | 21 +++ mycelium/__init__.py | 0 mycelium/admin.py | 3 + mycelium/apps.py | 5 + mycelium/migrations/__init__.py | 0 mycelium/models.py | 3 + mycelium/tests.py | 3 + mycelium/views.py | 3 + requirements.nix | 243 ++++++++++++++++++++++++++++++++ requirements.txt | 4 + requirements_frozen.txt | 7 + requirements_override.nix | 5 + 18 files changed, 478 insertions(+) create mode 100644 .gitignore create mode 100644 django_mycelium/__init__.py create mode 100644 django_mycelium/asgi.py create mode 100644 django_mycelium/settings.py create mode 100644 django_mycelium/urls.py create mode 100644 django_mycelium/wsgi.py create mode 100755 manage.py create mode 100644 mycelium/__init__.py create mode 100644 mycelium/admin.py create mode 100644 mycelium/apps.py create mode 100644 mycelium/migrations/__init__.py create mode 100644 mycelium/models.py create mode 100644 mycelium/tests.py create mode 100644 mycelium/views.py create mode 100644 requirements.nix create mode 100644 requirements.txt create mode 100644 requirements_frozen.txt create mode 100644 requirements_override.nix diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b393d99 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +.idea +*.sqlite3 +result +*.pyc +*.pyo +__pycache__ diff --git a/django_mycelium/__init__.py b/django_mycelium/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/django_mycelium/asgi.py b/django_mycelium/asgi.py new file mode 100644 index 0000000..2ae49fe --- /dev/null +++ b/django_mycelium/asgi.py @@ -0,0 +1,16 @@ +""" +ASGI config for django_mycelium project. + +It exposes the ASGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/3.0/howto/deployment/asgi/ +""" + +import os + +from django.core.asgi import get_asgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'django_mycelium.settings') + +application = get_asgi_application() diff --git a/django_mycelium/settings.py b/django_mycelium/settings.py new file mode 100644 index 0000000..9b29f20 --- /dev/null +++ b/django_mycelium/settings.py @@ -0,0 +1,122 @@ +""" +Django settings for django_mycelium project. + +Generated by 'django-admin startproject' using Django 3.0. + +For more information on this file, see +https://docs.djangoproject.com/en/3.0/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/3.0/ref/settings/ +""" + +import os + +# Build paths inside the project like this: os.path.join(BASE_DIR, ...) +BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/3.0/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = 'owwylmqm5n@0h0ko((1$+ti7l#6q6hni4x0w^9)dk)5y6_r^c3' + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True + +ALLOWED_HOSTS = [] + + +# Application definition + +INSTALLED_APPS = [ + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', + 'mycelium.apps.MyceliumConfig', +] + +MIDDLEWARE = [ + 'django.middleware.security.SecurityMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', +] + +ROOT_URLCONF = 'django_mycelium.urls' + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [os.path.join(BASE_DIR, 'templates')] + , + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.debug', + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + ], + }, + }, +] + +WSGI_APPLICATION = 'django_mycelium.wsgi.application' + + +# Database +# https://docs.djangoproject.com/en/3.0/ref/settings/#databases + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), + } +} + + +# Password validation +# https://docs.djangoproject.com/en/3.0/ref/settings/#auth-password-validators + +AUTH_PASSWORD_VALIDATORS = [ + { + 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + }, +] + + +# Internationalization +# https://docs.djangoproject.com/en/3.0/topics/i18n/ + +LANGUAGE_CODE = 'en-us' + +TIME_ZONE = 'UTC' + +USE_I18N = True + +USE_L10N = True + +USE_TZ = True + + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/3.0/howto/static-files/ + +STATIC_URL = '/static/' diff --git a/django_mycelium/urls.py b/django_mycelium/urls.py new file mode 100644 index 0000000..78d0bea --- /dev/null +++ b/django_mycelium/urls.py @@ -0,0 +1,21 @@ +"""django_mycelium URL Configuration + +The `urlpatterns` list routes URLs to views. For more information please see: + https://docs.djangoproject.com/en/3.0/topics/http/urls/ +Examples: +Function views + 1. Add an import: from my_app import views + 2. Add a URL to urlpatterns: path('', views.home, name='home') +Class-based views + 1. Add an import: from other_app.views import Home + 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') +Including another URLconf + 1. Import the include() function: from django.urls import include, path + 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) +""" +from django.contrib import admin +from django.urls import path + +urlpatterns = [ + path('admin/', admin.site.urls), +] diff --git a/django_mycelium/wsgi.py b/django_mycelium/wsgi.py new file mode 100644 index 0000000..b7ef549 --- /dev/null +++ b/django_mycelium/wsgi.py @@ -0,0 +1,16 @@ +""" +WSGI config for django_mycelium project. + +It exposes the WSGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/3.0/howto/deployment/wsgi/ +""" + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'django_mycelium.settings') + +application = get_wsgi_application() diff --git a/manage.py b/manage.py new file mode 100755 index 0000000..e695678 --- /dev/null +++ b/manage.py @@ -0,0 +1,21 @@ +#!/nix/store/k5rdcbcwwpvj7l9f1yvd5mfggcfz16kk-python3-3.7.5/bin/python +"""Django's command-line utility for administrative tasks.""" +import os +import sys + + +def main(): + os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'django_mycelium.settings') + try: + from django.core.management import execute_from_command_line + except ImportError as exc: + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) from exc + execute_from_command_line(sys.argv) + + +if __name__ == '__main__': + main() diff --git a/mycelium/__init__.py b/mycelium/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/mycelium/admin.py b/mycelium/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/mycelium/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/mycelium/apps.py b/mycelium/apps.py new file mode 100644 index 0000000..ac45c29 --- /dev/null +++ b/mycelium/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class MyceliumConfig(AppConfig): + name = 'mycelium' diff --git a/mycelium/migrations/__init__.py b/mycelium/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/mycelium/models.py b/mycelium/models.py new file mode 100644 index 0000000..71a8362 --- /dev/null +++ b/mycelium/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/mycelium/tests.py b/mycelium/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/mycelium/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/mycelium/views.py b/mycelium/views.py new file mode 100644 index 0000000..91ea44a --- /dev/null +++ b/mycelium/views.py @@ -0,0 +1,3 @@ +from django.shortcuts import render + +# Create your views here. diff --git a/requirements.nix b/requirements.nix new file mode 100644 index 0000000..bfe27fb --- /dev/null +++ b/requirements.nix @@ -0,0 +1,243 @@ +# generated using pypi2nix tool (version: 2.0.4) +# See more at: https://github.com/nix-community/pypi2nix +# +# COMMAND: +# pypi2nix -V python3 -r requirements.txt +# + +{ pkgs ? import {}, + overrides ? ({ pkgs, python }: self: super: {}) +}: + +let + + inherit (pkgs) makeWrapper; + inherit (pkgs.stdenv.lib) fix' extends inNixShell; + + pythonPackages = + import "${toString pkgs.path}/pkgs/top-level/python-packages.nix" { + inherit pkgs; + inherit (pkgs) stdenv; + python = pkgs.python3; + }; + + commonBuildInputs = []; + commonDoCheck = false; + + withPackages = pkgs': + let + pkgs = builtins.removeAttrs pkgs' ["__unfix__"]; + interpreterWithPackages = selectPkgsFn: pythonPackages.buildPythonPackage { + name = "python3-interpreter"; + buildInputs = [ makeWrapper ] ++ (selectPkgsFn pkgs); + buildCommand = '' + mkdir -p $out/bin + ln -s ${pythonPackages.python.interpreter} \ + $out/bin/${pythonPackages.python.executable} + for dep in ${builtins.concatStringsSep " " + (selectPkgsFn pkgs)}; do + if [ -d "$dep/bin" ]; then + for prog in "$dep/bin/"*; do + if [ -x "$prog" ] && [ -f "$prog" ]; then + ln -s $prog $out/bin/`basename $prog` + fi + done + fi + done + for prog in "$out/bin/"*; do + wrapProgram "$prog" --prefix PYTHONPATH : "$PYTHONPATH" + done + pushd $out/bin + ln -s ${pythonPackages.python.executable} python + ln -s ${pythonPackages.python.executable} \ + python3 + popd + ''; + passthru.interpreter = pythonPackages.python; + }; + + interpreter = interpreterWithPackages builtins.attrValues; + in { + __old = pythonPackages; + inherit interpreter; + inherit interpreterWithPackages; + mkDerivation = args: pythonPackages.buildPythonPackage (args // { + nativeBuildInputs = (args.nativeBuildInputs or []) ++ args.buildInputs; + }); + packages = pkgs; + overrideDerivation = drv: f: + pythonPackages.buildPythonPackage ( + drv.drvAttrs // f drv.drvAttrs // { meta = drv.meta; } + ); + withPackages = pkgs'': + withPackages (pkgs // pkgs''); + }; + + python = withPackages {}; + + generated = self: { + "asgiref" = python.mkDerivation { + name = "asgiref-3.2.3"; + src = pkgs.fetchurl { + url = "https://files.pythonhosted.org/packages/80/c4/83a01607f2d10024c172097126264c8e00c6a4827b35d631ece9625e6ba2/asgiref-3.2.3.tar.gz"; + sha256 = "7e06d934a7718bf3975acbf87780ba678957b87c7adc056f13b6215d610695a0"; +}; + doCheck = commonDoCheck; + format = "setuptools"; + buildInputs = commonBuildInputs ++ [ ]; + propagatedBuildInputs = [ ]; + meta = with pkgs.stdenv.lib; { + homepage = "http://github.com/django/asgiref/"; + license = licenses.bsdOriginal; + description = "ASGI specs, helper code, and adapters"; + }; + }; + + "django" = python.mkDerivation { + name = "django-3.0"; + src = pkgs.fetchurl { + url = "https://files.pythonhosted.org/packages/f8/46/b3b8c61f867827fff2305db40659495dcd64fb35c399e75c53f23c113871/Django-3.0.tar.gz"; + sha256 = "d98c9b6e5eed147bc51f47c014ff6826bd1ab50b166956776ee13db5a58804ae"; +}; + doCheck = commonDoCheck; + format = "setuptools"; + buildInputs = commonBuildInputs ++ [ ]; + propagatedBuildInputs = [ + self."asgiref" + self."pytz" + self."sqlparse" + ]; + meta = with pkgs.stdenv.lib; { + homepage = "https://www.djangoproject.com/"; + license = licenses.bsdOriginal; + description = "A high-level Python Web framework that encourages rapid development and clean, pragmatic design."; + }; + }; + + "django-filter" = python.mkDerivation { + name = "django-filter-2.2.0"; + src = pkgs.fetchurl { + url = "https://files.pythonhosted.org/packages/dc/75/af3f0c2682d2603617ee3061b36395a64fb9d70c327bb759de43e643e5b3/django-filter-2.2.0.tar.gz"; + sha256 = "c3deb57f0dd7ff94d7dce52a047516822013e2b441bed472b722a317658cfd14"; +}; + doCheck = commonDoCheck; + format = "setuptools"; + buildInputs = commonBuildInputs ++ [ ]; + propagatedBuildInputs = [ + self."django" + ]; + meta = with pkgs.stdenv.lib; { + homepage = "https://github.com/carltongibson/django-filter/tree/master"; + license = licenses.bsdOriginal; + description = "Django-filter is a reusable Django application for allowing users to filter querysets dynamically."; + }; + }; + + "djangorestframework" = python.mkDerivation { + name = "djangorestframework-3.11.0"; + src = pkgs.fetchurl { + url = "https://files.pythonhosted.org/packages/80/f6/f742b0352d4ade1934fcb2a12f6fd669922415bea3d5d2d6596dc47abe14/djangorestframework-3.11.0.tar.gz"; + sha256 = "e782087823c47a26826ee5b6fa0c542968219263fb3976ec3c31edab23a4001f"; +}; + doCheck = commonDoCheck; + format = "setuptools"; + buildInputs = commonBuildInputs ++ [ ]; + propagatedBuildInputs = [ + self."django" + ]; + meta = with pkgs.stdenv.lib; { + homepage = "https://www.django-rest-framework.org/"; + license = licenses.bsdOriginal; + description = "Web APIs for Django, made easy."; + }; + }; + + "markdown" = python.mkDerivation { + name = "markdown-3.2"; + src = pkgs.fetchurl { + url = "https://files.pythonhosted.org/packages/3a/0b/6deec230d8c30f1ae569e4cfca5fd202d912dbf61f338d4d86b284a40812/Markdown-3.2.tar.gz"; + sha256 = "5ad7180c3ec16422a764568ad6409ec82460c40d1631591fa53d597033cc98bf"; +}; + doCheck = commonDoCheck; + format = "setuptools"; + buildInputs = commonBuildInputs ++ [ ]; + propagatedBuildInputs = [ + self."setuptools" + ]; + meta = with pkgs.stdenv.lib; { + homepage = "https://Python-Markdown.github.io/"; + license = licenses.bsdOriginal; + description = "Python implementation of Markdown."; + }; + }; + + "pytz" = python.mkDerivation { + name = "pytz-2019.3"; + src = pkgs.fetchurl { + url = "https://files.pythonhosted.org/packages/82/c3/534ddba230bd4fbbd3b7a3d35f3341d014cca213f369a9940925e7e5f691/pytz-2019.3.tar.gz"; + sha256 = "b02c06db6cf09c12dd25137e563b31700d3b80fcc4ad23abb7a315f2789819be"; +}; + doCheck = commonDoCheck; + format = "setuptools"; + buildInputs = commonBuildInputs ++ [ ]; + propagatedBuildInputs = [ ]; + meta = with pkgs.stdenv.lib; { + homepage = "http://pythonhosted.org/pytz"; + license = licenses.mit; + description = "World timezone definitions, modern and historical"; + }; + }; + + "setuptools" = python.mkDerivation { + name = "setuptools-45.2.0"; + src = pkgs.fetchurl { + url = "https://files.pythonhosted.org/packages/68/75/d1d7b7340b9eb6e0388bf95729e63c410b381eb71fe8875cdfd949d8f9ce/setuptools-45.2.0.zip"; + sha256 = "89c6e6011ec2f6d57d43a3f9296c4ef022c2cbf49bab26b407fe67992ae3397f"; +}; + doCheck = commonDoCheck; + format = "setuptools"; + buildInputs = commonBuildInputs ++ [ ]; + propagatedBuildInputs = [ ]; + meta = with pkgs.stdenv.lib; { + homepage = "https://github.com/pypa/setuptools"; + license = licenses.mit; + description = "Easily download, build, install, upgrade, and uninstall Python packages"; + }; + }; + + "sqlparse" = python.mkDerivation { + name = "sqlparse-0.3.0"; + src = pkgs.fetchurl { + url = "https://files.pythonhosted.org/packages/63/c8/229dfd2d18663b375975d953e2bdc06d0eed714f93dcb7732f39e349c438/sqlparse-0.3.0.tar.gz"; + sha256 = "7c3dca29c022744e95b547e867cee89f4fce4373f3549ccd8797d8eb52cdb873"; +}; + doCheck = commonDoCheck; + format = "setuptools"; + buildInputs = commonBuildInputs ++ [ ]; + propagatedBuildInputs = [ ]; + meta = with pkgs.stdenv.lib; { + homepage = "https://github.com/andialbrecht/sqlparse"; + license = licenses.bsdOriginal; + description = "Non-validating SQL parser"; + }; + }; + }; + localOverridesFile = ./requirements_override.nix; + localOverrides = import localOverridesFile { inherit pkgs python; }; + commonOverrides = [ + (let src = pkgs.fetchFromGitHub { owner = "nix-community"; repo = "pypi2nix-overrides"; rev = "ebc21a64505989717dc395ad92f0a4d7021c44bc"; sha256 = "1p1bqm80anxsnh2k26y0f066z3zpngwxpff1jldzzkbhvw8zw77i"; } ; in import "${src}/overrides.nix" { inherit pkgs python; }) + ]; + paramOverrides = [ + (overrides { inherit pkgs python; }) + ]; + allOverrides = + (if (builtins.pathExists localOverridesFile) + then [localOverrides] else [] ) ++ commonOverrides ++ paramOverrides; + +in python.withPackages + (fix' (pkgs.lib.fold + extends + generated + allOverrides + ) + ) \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..349a45e --- /dev/null +++ b/requirements.txt @@ -0,0 +1,4 @@ +django==3 +djangorestframework +markdown +django-filter diff --git a/requirements_frozen.txt b/requirements_frozen.txt new file mode 100644 index 0000000..a4b1f73 --- /dev/null +++ b/requirements_frozen.txt @@ -0,0 +1,7 @@ +asgiref==3.2.3 +Django==3.0 +django-filter==2.2.0 +djangorestframework==3.11.0 +Markdown==3.2 +pytz==2019.3 +sqlparse==0.3.0 diff --git a/requirements_override.nix b/requirements_override.nix new file mode 100644 index 0000000..3b704ef --- /dev/null +++ b/requirements_override.nix @@ -0,0 +1,5 @@ +{ pkgs, python }: + +self: super: { + +} \ No newline at end of file From 1ffd079c1ce766b20c323d136d8738406a6b8c2a Mon Sep 17 00:00:00 2001 From: Jakob Klepp Date: Sat, 15 Feb 2020 11:49:35 +0100 Subject: [PATCH 2/7] Format gnerated code files with black --- django_mycelium/asgi.py | 2 +- django_mycelium/settings.py | 83 +++++++++++++++++-------------------- django_mycelium/urls.py | 4 +- django_mycelium/wsgi.py | 2 +- manage.py | 4 +- mycelium/apps.py | 2 +- 6 files changed, 44 insertions(+), 53 deletions(-) diff --git a/django_mycelium/asgi.py b/django_mycelium/asgi.py index 2ae49fe..dc19ae7 100644 --- a/django_mycelium/asgi.py +++ b/django_mycelium/asgi.py @@ -11,6 +11,6 @@ import os from django.core.asgi import get_asgi_application -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'django_mycelium.settings') +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "django_mycelium.settings") application = get_asgi_application() diff --git a/django_mycelium/settings.py b/django_mycelium/settings.py index 9b29f20..1d8890e 100644 --- a/django_mycelium/settings.py +++ b/django_mycelium/settings.py @@ -20,7 +20,7 @@ BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # See https://docs.djangoproject.com/en/3.0/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = 'owwylmqm5n@0h0ko((1$+ti7l#6q6hni4x0w^9)dk)5y6_r^c3' +SECRET_KEY = "owwylmqm5n@0h0ko((1$+ti7l#6q6hni4x0w^9)dk)5y6_r^c3" # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True @@ -31,54 +31,53 @@ ALLOWED_HOSTS = [] # Application definition INSTALLED_APPS = [ - 'django.contrib.admin', - 'django.contrib.auth', - 'django.contrib.contenttypes', - 'django.contrib.sessions', - 'django.contrib.messages', - 'django.contrib.staticfiles', - 'mycelium.apps.MyceliumConfig', + "django.contrib.admin", + "django.contrib.auth", + "django.contrib.contenttypes", + "django.contrib.sessions", + "django.contrib.messages", + "django.contrib.staticfiles", + "mycelium.apps.MyceliumConfig", ] MIDDLEWARE = [ - 'django.middleware.security.SecurityMiddleware', - 'django.contrib.sessions.middleware.SessionMiddleware', - 'django.middleware.common.CommonMiddleware', - 'django.middleware.csrf.CsrfViewMiddleware', - 'django.contrib.auth.middleware.AuthenticationMiddleware', - 'django.contrib.messages.middleware.MessageMiddleware', - 'django.middleware.clickjacking.XFrameOptionsMiddleware', + "django.middleware.security.SecurityMiddleware", + "django.contrib.sessions.middleware.SessionMiddleware", + "django.middleware.common.CommonMiddleware", + "django.middleware.csrf.CsrfViewMiddleware", + "django.contrib.auth.middleware.AuthenticationMiddleware", + "django.contrib.messages.middleware.MessageMiddleware", + "django.middleware.clickjacking.XFrameOptionsMiddleware", ] -ROOT_URLCONF = 'django_mycelium.urls' +ROOT_URLCONF = "django_mycelium.urls" TEMPLATES = [ { - 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [os.path.join(BASE_DIR, 'templates')] - , - 'APP_DIRS': True, - 'OPTIONS': { - 'context_processors': [ - 'django.template.context_processors.debug', - 'django.template.context_processors.request', - 'django.contrib.auth.context_processors.auth', - 'django.contrib.messages.context_processors.messages', - ], + "BACKEND": "django.template.backends.django.DjangoTemplates", + "DIRS": [os.path.join(BASE_DIR, "templates")], + "APP_DIRS": True, + "OPTIONS": { + "context_processors": [ + "django.template.context_processors.debug", + "django.template.context_processors.request", + "django.contrib.auth.context_processors.auth", + "django.contrib.messages.context_processors.messages", + ] }, - }, + } ] -WSGI_APPLICATION = 'django_mycelium.wsgi.application' +WSGI_APPLICATION = "django_mycelium.wsgi.application" # Database # https://docs.djangoproject.com/en/3.0/ref/settings/#databases DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.sqlite3', - 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), + "default": { + "ENGINE": "django.db.backends.sqlite3", + "NAME": os.path.join(BASE_DIR, "db.sqlite3"), } } @@ -88,26 +87,20 @@ DATABASES = { AUTH_PASSWORD_VALIDATORS = [ { - 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', - }, - { - 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', - }, - { - 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', - }, - { - 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator" }, + {"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator"}, + {"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator"}, + {"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator"}, ] # Internationalization # https://docs.djangoproject.com/en/3.0/topics/i18n/ -LANGUAGE_CODE = 'en-us' +LANGUAGE_CODE = "en-us" -TIME_ZONE = 'UTC' +TIME_ZONE = "UTC" USE_I18N = True @@ -119,4 +112,4 @@ USE_TZ = True # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/3.0/howto/static-files/ -STATIC_URL = '/static/' +STATIC_URL = "/static/" diff --git a/django_mycelium/urls.py b/django_mycelium/urls.py index 78d0bea..de2e137 100644 --- a/django_mycelium/urls.py +++ b/django_mycelium/urls.py @@ -16,6 +16,4 @@ Including another URLconf from django.contrib import admin from django.urls import path -urlpatterns = [ - path('admin/', admin.site.urls), -] +urlpatterns = [path("admin/", admin.site.urls)] diff --git a/django_mycelium/wsgi.py b/django_mycelium/wsgi.py index b7ef549..5f19dfb 100644 --- a/django_mycelium/wsgi.py +++ b/django_mycelium/wsgi.py @@ -11,6 +11,6 @@ import os from django.core.wsgi import get_wsgi_application -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'django_mycelium.settings') +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "django_mycelium.settings") application = get_wsgi_application() diff --git a/manage.py b/manage.py index e695678..071de8e 100755 --- a/manage.py +++ b/manage.py @@ -5,7 +5,7 @@ import sys def main(): - os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'django_mycelium.settings') + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "django_mycelium.settings") try: from django.core.management import execute_from_command_line except ImportError as exc: @@ -17,5 +17,5 @@ def main(): execute_from_command_line(sys.argv) -if __name__ == '__main__': +if __name__ == "__main__": main() diff --git a/mycelium/apps.py b/mycelium/apps.py index ac45c29..98b2b50 100644 --- a/mycelium/apps.py +++ b/mycelium/apps.py @@ -2,4 +2,4 @@ from django.apps import AppConfig class MyceliumConfig(AppConfig): - name = 'mycelium' + name = "mycelium" From 98e5725281a2215b21d3add04e540dc521ed358f Mon Sep 17 00:00:00 2001 From: Jakob Klepp Date: Sat, 15 Feb 2020 12:16:26 +0100 Subject: [PATCH 3/7] Add rest_framework --- Readme.md | 11 +++++++++++ django_mycelium/settings.py | 1 + django_mycelium/urls.py | 10 +++++++++- requirements.nix | 25 +++++++++++++++++++++---- requirements.txt | 1 + requirements_frozen.txt | 3 ++- 6 files changed, 45 insertions(+), 6 deletions(-) create mode 100644 Readme.md diff --git a/Readme.md b/Readme.md new file mode 100644 index 0000000..c17a30d --- /dev/null +++ b/Readme.md @@ -0,0 +1,11 @@ +- Update `requirements.nix`: + +```sh +pypi2nix -V python3 -r requirements.txt +``` + +- Generate interpreter: + +```sh +nix build -f requirements.nix interpreter +``` diff --git a/django_mycelium/settings.py b/django_mycelium/settings.py index 1d8890e..a72c95b 100644 --- a/django_mycelium/settings.py +++ b/django_mycelium/settings.py @@ -37,6 +37,7 @@ INSTALLED_APPS = [ "django.contrib.sessions", "django.contrib.messages", "django.contrib.staticfiles", + "rest_framework", "mycelium.apps.MyceliumConfig", ] diff --git a/django_mycelium/urls.py b/django_mycelium/urls.py index de2e137..105f374 100644 --- a/django_mycelium/urls.py +++ b/django_mycelium/urls.py @@ -15,5 +15,13 @@ Including another URLconf """ from django.contrib import admin from django.urls import path +from rest_framework.schemas import get_schema_view -urlpatterns = [path("admin/", admin.site.urls)] +urlpatterns = [ + path("admin/", admin.site.urls), + path( + "openapi", + get_schema_view(title="Mycelium", description="API", version="0.1.0"), + name="openapi-schema", + ), +] diff --git a/requirements.nix b/requirements.nix index bfe27fb..bb3395a 100644 --- a/requirements.nix +++ b/requirements.nix @@ -153,10 +153,10 @@ let }; "markdown" = python.mkDerivation { - name = "markdown-3.2"; + name = "markdown-3.2.1"; src = pkgs.fetchurl { - url = "https://files.pythonhosted.org/packages/3a/0b/6deec230d8c30f1ae569e4cfca5fd202d912dbf61f338d4d86b284a40812/Markdown-3.2.tar.gz"; - sha256 = "5ad7180c3ec16422a764568ad6409ec82460c40d1631591fa53d597033cc98bf"; + url = "https://files.pythonhosted.org/packages/98/79/ce6984767cb9478e6818bd0994283db55c423d733cc62a88a3ffb8581e11/Markdown-3.2.1.tar.gz"; + sha256 = "90fee683eeabe1a92e149f7ba74e5ccdc81cd397bd6c516d93a8da0ef90b6902"; }; doCheck = commonDoCheck; format = "setuptools"; @@ -188,6 +188,23 @@ let }; }; + "pyyaml" = python.mkDerivation { + name = "pyyaml-5.3"; + src = pkgs.fetchurl { + url = "https://files.pythonhosted.org/packages/3d/d9/ea9816aea31beeadccd03f1f8b625ecf8f645bd66744484d162d84803ce5/PyYAML-5.3.tar.gz"; + sha256 = "e9f45bd5b92c7974e59bcd2dcc8631a6b6cc380a904725fce7bc08872e691615"; +}; + doCheck = commonDoCheck; + format = "setuptools"; + buildInputs = commonBuildInputs ++ [ ]; + propagatedBuildInputs = [ ]; + meta = with pkgs.stdenv.lib; { + homepage = "https://github.com/yaml/pyyaml"; + license = licenses.mit; + description = "YAML parser and emitter for Python"; + }; + }; + "setuptools" = python.mkDerivation { name = "setuptools-45.2.0"; src = pkgs.fetchurl { @@ -225,7 +242,7 @@ let localOverridesFile = ./requirements_override.nix; localOverrides = import localOverridesFile { inherit pkgs python; }; commonOverrides = [ - (let src = pkgs.fetchFromGitHub { owner = "nix-community"; repo = "pypi2nix-overrides"; rev = "ebc21a64505989717dc395ad92f0a4d7021c44bc"; sha256 = "1p1bqm80anxsnh2k26y0f066z3zpngwxpff1jldzzkbhvw8zw77i"; } ; in import "${src}/overrides.nix" { inherit pkgs python; }) + (let src = pkgs.fetchFromGitHub { owner = "nix-community"; repo = "pypi2nix-overrides"; rev = "fbbcadd9e5fedade659ba2585893d3a8cbba8e56"; sha256 = "1fmqib6j08lswfw0agbgy1hdib3rfmrzx2x5zyzrqbkvc80a734b"; } ; in import "${src}/overrides.nix" { inherit pkgs python; }) ]; paramOverrides = [ (overrides { inherit pkgs python; }) diff --git a/requirements.txt b/requirements.txt index 349a45e..ebb318e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,3 +2,4 @@ django==3 djangorestframework markdown django-filter +pyyaml diff --git a/requirements_frozen.txt b/requirements_frozen.txt index a4b1f73..77bb201 100644 --- a/requirements_frozen.txt +++ b/requirements_frozen.txt @@ -2,6 +2,7 @@ asgiref==3.2.3 Django==3.0 django-filter==2.2.0 djangorestframework==3.11.0 -Markdown==3.2 +Markdown==3.2.1 pytz==2019.3 +PyYAML==5.3 sqlparse==0.3.0 From 824d04c65dff008f774823ce5e0ce3e8767bde29 Mon Sep 17 00:00:00 2001 From: Jakob Klepp Date: Sun, 16 Feb 2020 13:08:58 +0100 Subject: [PATCH 4/7] Add species model --- mycelium/models.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/mycelium/models.py b/mycelium/models.py index 71a8362..d742988 100644 --- a/mycelium/models.py +++ b/mycelium/models.py @@ -1,3 +1,10 @@ from django.db import models # Create your models here. +class Species(models.Model): + scientific_name = models.CharField(max_length=255) + genera = models.CharField(max_length=255) + familia = models.CharField(max_length=255) + ordo = models.CharField(max_length=255) + classis = models.CharField(max_length=255) + From 5320dabda82655796b3c9bc7fa8ae4a8db4e6701 Mon Sep 17 00:00:00 2001 From: Jakob Klepp Date: Sun, 16 Feb 2020 13:39:09 +0100 Subject: [PATCH 5/7] Add requirement psycopg2 --- Readme.md | 2 +- django_mycelium/settings.py | 1 + requirements.nix | 21 +++++++++++++++++++-- requirements.txt | 3 ++- requirements_frozen.txt | 1 + 5 files changed, 24 insertions(+), 4 deletions(-) diff --git a/Readme.md b/Readme.md index c17a30d..8548c2c 100644 --- a/Readme.md +++ b/Readme.md @@ -1,7 +1,7 @@ - Update `requirements.nix`: ```sh -pypi2nix -V python3 -r requirements.txt +pypi2nix -V python3 -r requirements.txt -E postgresql_11 ``` - Generate interpreter: diff --git a/django_mycelium/settings.py b/django_mycelium/settings.py index a72c95b..349d42d 100644 --- a/django_mycelium/settings.py +++ b/django_mycelium/settings.py @@ -38,6 +38,7 @@ INSTALLED_APPS = [ "django.contrib.messages", "django.contrib.staticfiles", "rest_framework", + "translatable_fields", "mycelium.apps.MyceliumConfig", ] diff --git a/requirements.nix b/requirements.nix index bb3395a..7f7ef5e 100644 --- a/requirements.nix +++ b/requirements.nix @@ -2,7 +2,7 @@ # See more at: https://github.com/nix-community/pypi2nix # # COMMAND: -# pypi2nix -V python3 -r requirements.txt +# pypi2nix -V python3 -r requirements.txt -E postgresql_11 # { pkgs ? import {}, @@ -21,7 +21,7 @@ let python = pkgs.python3; }; - commonBuildInputs = []; + commonBuildInputs = with pkgs; [ postgresql_11 ]; commonDoCheck = false; withPackages = pkgs': @@ -171,6 +171,23 @@ let }; }; + "psycopg2" = python.mkDerivation { + name = "psycopg2-2.8.4"; + src = pkgs.fetchurl { + url = "https://files.pythonhosted.org/packages/84/d7/6a93c99b5ba4d4d22daa3928b983cec66df4536ca50b22ce5dcac65e4e71/psycopg2-2.8.4.tar.gz"; + sha256 = "f898e5cc0a662a9e12bde6f931263a1bbd350cfb18e1d5336a12927851825bb6"; +}; + doCheck = commonDoCheck; + format = "setuptools"; + buildInputs = commonBuildInputs ++ [ ]; + propagatedBuildInputs = [ ]; + meta = with pkgs.stdenv.lib; { + homepage = "http://initd.org/psycopg/"; + license = licenses.lgpl2; + description = "psycopg2 - Python-PostgreSQL Database Adapter"; + }; + }; + "pytz" = python.mkDerivation { name = "pytz-2019.3"; src = pkgs.fetchurl { diff --git a/requirements.txt b/requirements.txt index ebb318e..cebf6c3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,6 @@ django==3 +django-filter djangorestframework markdown -django-filter +psycopg2 pyyaml diff --git a/requirements_frozen.txt b/requirements_frozen.txt index 77bb201..fa0a422 100644 --- a/requirements_frozen.txt +++ b/requirements_frozen.txt @@ -3,6 +3,7 @@ Django==3.0 django-filter==2.2.0 djangorestframework==3.11.0 Markdown==3.2.1 +psycopg2==2.8.4 pytz==2019.3 PyYAML==5.3 sqlparse==0.3.0 From 03cf228b7949b006cd7b07e5732eb9ee2b7fb6b6 Mon Sep 17 00:00:00 2001 From: Jakob Klepp Date: Sun, 16 Feb 2020 14:50:38 +0100 Subject: [PATCH 6/7] Create datamodel --- mycelium/migrations/0001_initial.py | 34 +++++++++ .../migrations/0002_auto_20200216_1349.py | 74 +++++++++++++++++++ mycelium/models.py | 37 ++++++++++ 3 files changed, 145 insertions(+) create mode 100644 mycelium/migrations/0001_initial.py create mode 100644 mycelium/migrations/0002_auto_20200216_1349.py diff --git a/mycelium/migrations/0001_initial.py b/mycelium/migrations/0001_initial.py new file mode 100644 index 0000000..242fea5 --- /dev/null +++ b/mycelium/migrations/0001_initial.py @@ -0,0 +1,34 @@ +# Generated by Django 3.0 on 2020-02-16 12:47 + +from django.db import migrations, models +import translatable_fields.models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [] + + operations = [ + migrations.CreateModel( + name="Species", + fields=[ + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("name", translatable_fields.models.TranslatableField()), + ("scientific_name", models.CharField(max_length=255)), + ("genera", models.CharField(max_length=255)), + ("familia", models.CharField(max_length=255)), + ("ordo", models.CharField(max_length=255)), + ("classis", models.CharField(max_length=255)), + ], + ) + ] diff --git a/mycelium/migrations/0002_auto_20200216_1349.py b/mycelium/migrations/0002_auto_20200216_1349.py new file mode 100644 index 0000000..a63011a --- /dev/null +++ b/mycelium/migrations/0002_auto_20200216_1349.py @@ -0,0 +1,74 @@ +# Generated by Django 3.0 on 2020-02-16 13:49 + +from django.db import migrations, models +import django.db.models.deletion +import translatable_fields.models + + +class Migration(migrations.Migration): + + dependencies = [ + ('mycelium', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='Culture', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('species', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='mycelium.Species')), + ], + ), + migrations.CreateModel( + name='Ingredient', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', translatable_fields.models.TranslatableField()), + ('description', translatable_fields.models.TranslatableField()), + ], + ), + migrations.CreateModel( + name='Step', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', translatable_fields.models.TranslatableField()), + ('description', translatable_fields.models.TranslatableField()), + ], + ), + migrations.CreateModel( + name='Substrate', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', translatable_fields.models.TranslatableField()), + ], + ), + migrations.CreateModel( + name='IngredientInSubstrate', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('amount', models.FloatField()), + ('ingredient', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mycelium.Ingredient')), + ('substrate', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mycelium.Substrate')), + ], + ), + migrations.CreateModel( + name='CultureStep', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('date', models.DateTimeField()), + ('notes', translatable_fields.models.TranslatableField()), + ('culture_id', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mycelium.Culture')), + ('step_id', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mycelium.Step')), + ], + ), + migrations.AddField( + model_name='culture', + name='steps', + field=models.ManyToManyField(through='mycelium.CultureStep', to='mycelium.Step'), + ), + migrations.AddField( + model_name='culture', + name='substrate', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='mycelium.Substrate'), + ), + ] diff --git a/mycelium/models.py b/mycelium/models.py index d742988..da30056 100644 --- a/mycelium/models.py +++ b/mycelium/models.py @@ -1,10 +1,47 @@ from django.db import models # Create your models here. +from translatable_fields.models import TranslatableField + + class Species(models.Model): + name = TranslatableField() + scientific_name = models.CharField(max_length=255) genera = models.CharField(max_length=255) familia = models.CharField(max_length=255) ordo = models.CharField(max_length=255) classis = models.CharField(max_length=255) + +class Ingredient(models.Model): + name = TranslatableField() + description = TranslatableField() + + +class Substrate(models.Model): + name = TranslatableField() + + +class IngredientInSubstrate(models.Model): + amount = models.FloatField() + substrate = models.ForeignKey(Substrate, on_delete=models.CASCADE) + ingredient = models.ForeignKey(Ingredient, on_delete=models.CASCADE) + + +class Step(models.Model): + name = TranslatableField() + description = TranslatableField() + + +class Culture(models.Model): + substrate = models.ForeignKey(Substrate, null=True, on_delete=models.SET_NULL) + species = models.ForeignKey(Species, null=True, on_delete=models.SET_NULL) + steps = models.ManyToManyField(Step, through="CultureStep", through_fields=("culture_id", "step_id")) + + +class CultureStep(models.Model): + culture_id = models.ForeignKey(Culture, on_delete=models.CASCADE) + step_id = models.ForeignKey(Step, on_delete=models.CASCADE) + date = models.DateTimeField() + notes = TranslatableField() From 41e3969e8f520bea81c4920f9eb30430037d11b3 Mon Sep 17 00:00:00 2001 From: Jakob Klepp Date: Sun, 16 Feb 2020 17:12:42 +0100 Subject: [PATCH 7/7] Adjust admin interface --- Readme.md | 2 +- django_mycelium/settings.py | 4 +- mycelium/admin.py | 57 +++++++ .../migrations/0002_auto_20200216_1349.py | 150 ++++++++++++++---- .../migrations/0003_auto_20200216_1542.py | 44 +++++ mycelium/models.py | 12 +- requirements.nix | 21 ++- requirements.txt | 1 + requirements_frozen.txt | 1 + 9 files changed, 253 insertions(+), 39 deletions(-) create mode 100644 mycelium/migrations/0003_auto_20200216_1542.py diff --git a/Readme.md b/Readme.md index 8548c2c..3e92a67 100644 --- a/Readme.md +++ b/Readme.md @@ -1,7 +1,7 @@ - Update `requirements.nix`: ```sh -pypi2nix -V python3 -r requirements.txt -E postgresql_11 +pypi2nix -V python3 -r requirements.txt --default-overrides -E postgresql_11 -E "pkgconfig zlib libjpeg openjpeg libtiff freetype lcms2 libwebp tcl" ``` - Generate interpreter: diff --git a/django_mycelium/settings.py b/django_mycelium/settings.py index 349d42d..e1bcaf3 100644 --- a/django_mycelium/settings.py +++ b/django_mycelium/settings.py @@ -100,7 +100,9 @@ AUTH_PASSWORD_VALIDATORS = [ # Internationalization # https://docs.djangoproject.com/en/3.0/topics/i18n/ -LANGUAGE_CODE = "en-us" +LANGUAGE_CODE = "en" + +LANGUAGES = (("de", "Deutsch"), ("en", "English")) TIME_ZONE = "UTC" diff --git a/mycelium/admin.py b/mycelium/admin.py index 8c38f3f..f9a50d7 100644 --- a/mycelium/admin.py +++ b/mycelium/admin.py @@ -1,3 +1,60 @@ from django.contrib import admin # Register your models here. +from django import forms +from django.contrib.admin import ModelAdmin +from django.contrib.postgres.forms import JSONField + +from mycelium.models import Species, Ingredient, Substrate, Step, Culture +from translatable_fields.widgets import TranslatableWidget + + +class SpeciesForm(forms.ModelForm): + name = JSONField(widget=TranslatableWidget(widget=forms.TextInput)) + fields = ("name", "scientific_name", "genera", "familia", "ordo", "classis") + + +class SpeciesAdmin(ModelAdmin): + form = SpeciesForm + + +admin.site.register(Species, SpeciesAdmin) + + +class IngredientForm(forms.ModelForm): + name = JSONField(widget=TranslatableWidget(widget=forms.TextInput)) + description = JSONField(widget=TranslatableWidget(widget=forms.TextInput)) + fields = ("name", "description", "image") + + +class IngredientAdmin(ModelAdmin): + form = IngredientForm + + +admin.site.register(Ingredient, IngredientAdmin) + + +class SubstrateForm(forms.ModelForm): + name = JSONField(widget=TranslatableWidget(widget=forms.TextInput)) + fields = ("name",) + + +class SubstrateAdmin(ModelAdmin): + form = SubstrateForm + + +admin.site.register(Substrate, SubstrateAdmin) + + +class StepForm(forms.ModelForm): + name = JSONField(widget=TranslatableWidget(widget=forms.TextInput)) + description = JSONField(widget=TranslatableWidget(widget=forms.TextInput)) + fields = ("name", "description") + + +class StepAdmin(ModelAdmin): + form = StepForm + + +admin.site.register(Step, StepAdmin) +admin.site.register(Culture) diff --git a/mycelium/migrations/0002_auto_20200216_1349.py b/mycelium/migrations/0002_auto_20200216_1349.py index a63011a..4ea5a1f 100644 --- a/mycelium/migrations/0002_auto_20200216_1349.py +++ b/mycelium/migrations/0002_auto_20200216_1349.py @@ -7,68 +7,150 @@ import translatable_fields.models class Migration(migrations.Migration): - dependencies = [ - ('mycelium', '0001_initial'), - ] + dependencies = [("mycelium", "0001_initial")] operations = [ migrations.CreateModel( - name='Culture', + name="Culture", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('species', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='mycelium.Species')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "species", + models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to="mycelium.Species", + ), + ), ], ), migrations.CreateModel( - name='Ingredient', + name="Ingredient", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', translatable_fields.models.TranslatableField()), - ('description', translatable_fields.models.TranslatableField()), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("name", translatable_fields.models.TranslatableField()), + ("description", translatable_fields.models.TranslatableField()), ], ), migrations.CreateModel( - name='Step', + name="Step", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', translatable_fields.models.TranslatableField()), - ('description', translatable_fields.models.TranslatableField()), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("name", translatable_fields.models.TranslatableField()), + ("description", translatable_fields.models.TranslatableField()), ], ), migrations.CreateModel( - name='Substrate', + name="Substrate", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', translatable_fields.models.TranslatableField()), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("name", translatable_fields.models.TranslatableField()), ], ), migrations.CreateModel( - name='IngredientInSubstrate', + name="IngredientInSubstrate", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('amount', models.FloatField()), - ('ingredient', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mycelium.Ingredient')), - ('substrate', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mycelium.Substrate')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("amount", models.FloatField()), + ( + "ingredient", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="mycelium.Ingredient", + ), + ), + ( + "substrate", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="mycelium.Substrate", + ), + ), ], ), migrations.CreateModel( - name='CultureStep', + name="CultureStep", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('date', models.DateTimeField()), - ('notes', translatable_fields.models.TranslatableField()), - ('culture_id', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mycelium.Culture')), - ('step_id', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mycelium.Step')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("date", models.DateTimeField()), + ("notes", translatable_fields.models.TranslatableField()), + ( + "culture_id", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="mycelium.Culture", + ), + ), + ( + "step_id", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, to="mycelium.Step" + ), + ), ], ), migrations.AddField( - model_name='culture', - name='steps', - field=models.ManyToManyField(through='mycelium.CultureStep', to='mycelium.Step'), + model_name="culture", + name="steps", + field=models.ManyToManyField( + through="mycelium.CultureStep", to="mycelium.Step" + ), ), migrations.AddField( - model_name='culture', - name='substrate', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='mycelium.Substrate'), + model_name="culture", + name="substrate", + field=models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to="mycelium.Substrate", + ), ), ] diff --git a/mycelium/migrations/0003_auto_20200216_1542.py b/mycelium/migrations/0003_auto_20200216_1542.py new file mode 100644 index 0000000..78fd9fa --- /dev/null +++ b/mycelium/migrations/0003_auto_20200216_1542.py @@ -0,0 +1,44 @@ +# Generated by Django 3.0 on 2020-02-16 15:42 + +from django.db import migrations, models +import django.db.models.deletion +import translatable_fields.models + + +class Migration(migrations.Migration): + + dependencies = [("mycelium", "0002_auto_20200216_1349")] + + operations = [ + migrations.CreateModel( + name="CultureType", + fields=[ + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("name", translatable_fields.models.TranslatableField()), + ("description", translatable_fields.models.TranslatableField()), + ("image", models.ImageField(null=True, upload_to="")), + ], + ), + migrations.AddField( + model_name="ingredient", + name="image", + field=models.ImageField(null=True, upload_to=""), + ), + migrations.AddField( + model_name="culture", + name="culture_type", + field=models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to="mycelium.CultureType", + ), + ), + ] diff --git a/mycelium/models.py b/mycelium/models.py index da30056..eb26547 100644 --- a/mycelium/models.py +++ b/mycelium/models.py @@ -17,6 +17,7 @@ class Species(models.Model): class Ingredient(models.Model): name = TranslatableField() description = TranslatableField() + image = models.ImageField(null=True) class Substrate(models.Model): @@ -34,10 +35,19 @@ class Step(models.Model): description = TranslatableField() +class CultureType(models.Model): + name = TranslatableField() + description = TranslatableField() + image = models.ImageField(null=True) + + class Culture(models.Model): substrate = models.ForeignKey(Substrate, null=True, on_delete=models.SET_NULL) species = models.ForeignKey(Species, null=True, on_delete=models.SET_NULL) - steps = models.ManyToManyField(Step, through="CultureStep", through_fields=("culture_id", "step_id")) + culture_type = models.ForeignKey(CultureType, null=True, on_delete=models.SET_NULL) + steps = models.ManyToManyField( + Step, through="CultureStep", through_fields=("culture_id", "step_id") + ) class CultureStep(models.Model): diff --git a/requirements.nix b/requirements.nix index 7f7ef5e..baafea5 100644 --- a/requirements.nix +++ b/requirements.nix @@ -2,7 +2,7 @@ # See more at: https://github.com/nix-community/pypi2nix # # COMMAND: -# pypi2nix -V python3 -r requirements.txt -E postgresql_11 +# pypi2nix -V python3 -r requirements.txt --default-overrides -E postgresql_11 -E 'pkgconfig zlib libjpeg openjpeg libtiff freetype lcms2 libwebp tcl' # { pkgs ? import {}, @@ -21,7 +21,7 @@ let python = pkgs.python3; }; - commonBuildInputs = with pkgs; [ postgresql_11 ]; + commonBuildInputs = with pkgs; [ postgresql_11 pkgconfig zlib libjpeg openjpeg libtiff freetype lcms2 libwebp tcl ]; commonDoCheck = false; withPackages = pkgs': @@ -171,6 +171,23 @@ let }; }; + "pillow" = python.mkDerivation { + name = "pillow-7.0.0"; + src = pkgs.fetchurl { + url = "https://files.pythonhosted.org/packages/39/47/f28067b187dd664d205f75b07dcc6e0e95703e134008a14814827eebcaab/Pillow-7.0.0.tar.gz"; + sha256 = "4d9ed9a64095e031435af120d3c910148067087541131e82b3e8db302f4c8946"; +}; + doCheck = commonDoCheck; + format = "setuptools"; + buildInputs = commonBuildInputs ++ [ ]; + propagatedBuildInputs = [ ]; + meta = with pkgs.stdenv.lib; { + homepage = "https://python-pillow.org"; + license = "HPND"; + description = "Python Imaging Library (Fork)"; + }; + }; + "psycopg2" = python.mkDerivation { name = "psycopg2-2.8.4"; src = pkgs.fetchurl { diff --git a/requirements.txt b/requirements.txt index cebf6c3..2e3f8eb 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,5 +2,6 @@ django==3 django-filter djangorestframework markdown +Pillow psycopg2 pyyaml diff --git a/requirements_frozen.txt b/requirements_frozen.txt index fa0a422..0879ac1 100644 --- a/requirements_frozen.txt +++ b/requirements_frozen.txt @@ -3,6 +3,7 @@ Django==3.0 django-filter==2.2.0 djangorestframework==3.11.0 Markdown==3.2.1 +Pillow==7.0.0 psycopg2==2.8.4 pytz==2019.3 PyYAML==5.3