diff --git a/Readme.md b/Readme.md index c17a30d..3e92a67 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 --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 a72c95b..e1bcaf3 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", ] @@ -99,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/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..4ea5a1f --- /dev/null +++ b/mycelium/migrations/0002_auto_20200216_1349.py @@ -0,0 +1,156 @@ +# 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/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 d742988..eb26547 100644 --- a/mycelium/models.py +++ b/mycelium/models.py @@ -1,10 +1,57 @@ 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() + image = models.ImageField(null=True) + + +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 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) + 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): + culture_id = models.ForeignKey(Culture, on_delete=models.CASCADE) + step_id = models.ForeignKey(Step, on_delete=models.CASCADE) + date = models.DateTimeField() + notes = TranslatableField() diff --git a/requirements.nix b/requirements.nix index bb3395a..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 +# 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 = []; + commonBuildInputs = with pkgs; [ postgresql_11 pkgconfig zlib libjpeg openjpeg libtiff freetype lcms2 libwebp tcl ]; commonDoCheck = false; withPackages = pkgs': @@ -171,6 +171,40 @@ 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 { + 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..2e3f8eb 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,7 @@ django==3 +django-filter djangorestframework markdown -django-filter +Pillow +psycopg2 pyyaml diff --git a/requirements_frozen.txt b/requirements_frozen.txt index 77bb201..0879ac1 100644 --- a/requirements_frozen.txt +++ b/requirements_frozen.txt @@ -3,6 +3,8 @@ 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 sqlparse==0.3.0