From 5320dabda82655796b3c9bc7fa8ae4a8db4e6701 Mon Sep 17 00:00:00 2001 From: Jakob Klepp Date: Sun, 16 Feb 2020 13:39:09 +0100 Subject: [PATCH 1/3] 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 2/3] 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 3/3] 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