diff --git a/database/migrations/import_rmg_models.py b/bin/import_rmg_models.py similarity index 100% rename from database/migrations/import_rmg_models.py rename to bin/import_rmg_models.py diff --git a/database/admin.py b/database/admin.py index ff366c5f..ffaaaf94 100644 --- a/database/admin.py +++ b/database/admin.py @@ -24,6 +24,7 @@ "RevisionMixin", "User", "SpeciesRevision", + "ReactionRevision", "RevisionManagerMixin", ] and isinstance(obj, type) @@ -33,36 +34,45 @@ class RevisionAdmin(admin.ModelAdmin): - def get_readonly_fields(self, request, obj=None): return [f.name for f in obj._meta.fields] + def get_urls(self): + urls = super().get_urls() -class IsomerInline(TabularInline): - model = models.Species.isomers.through - readonly_fields = ("isomer",) + return [ + path( + f"{self.url_name}/", + self.admin_site.admin_view(self.approval_view.as_view()), + name=self.url_name, + ), + *urls, + ] + + def render_change_form(self, request, context, *args, **kwargs): + context.update({"url_name": f"admin:{self.url_name}"}) + + return super().render_change_form(request, context, *args, **kwargs) + + +class ImmutablePermissionMixin: can_delete = False def has_add_permission(self, request, obj=None): return False +class IsomerInline(ImmutablePermissionMixin, TabularInline): + model = models.Species.isomers.through + readonly_fields = ("isomer",) + + @admin.register(models.SpeciesRevision) class SpeciesRevisionAdmin(admin.ModelAdmin): exclude = ("hash", "isomers") inlines = [IsomerInline] - - def get_urls(self): - urls = super().get_urls() - - return [ - path( - r"species//approve", - self.admin_site.admin_view(views.RevisionApprovalView.as_view()), - name="species-approval", - ), - *urls, - ] + url_name = "species-revision" + approval_view = views.SpeciesRevisionApprovalView class StoichiometryInline(admin.TabularInline): @@ -70,11 +80,23 @@ class StoichiometryInline(admin.TabularInline): fields = ("species", "coeff") +class StoichiometryRevisionInline(ImmutablePermissionMixin, admin.TabularInline): + model = models.StoichiometryRevision + fields = ("species", "coeff") + + @admin.register(models.Reaction) class ReactionAdmin(admin.ModelAdmin): inlines = [StoichiometryInline] +@admin.register(models.ReactionRevision) +class ReactionRevisionAdmin(RevisionAdmin): + inlines = [StoichiometryRevisionInline] + url_name = "reaction-approval" + approval_view = views.ReactionRevisionApprovalView + + class AuthorshipInline(admin.TabularInline): model = models.Authorship fields = ("author", "order") diff --git a/database/forms.py b/database/forms.py index 7db5078f..6b00ce7a 100644 --- a/database/forms.py +++ b/database/forms.py @@ -22,4 +22,5 @@ class Meta: form=StoichiometryForm, can_delete=True, extra=1, + fields=("coeff", "species") ) diff --git a/database/migrations/0001_initial.py b/database/migrations/0001_initial.py index 33643c5c..51005b32 100644 --- a/database/migrations/0001_initial.py +++ b/database/migrations/0001_initial.py @@ -1,7 +1,6 @@ -# Generated by Django 3.0 on 2020-12-26 00:30 +# Generated by Django 3.0 on 2020-12-26 22:04 import database.models.kinetic_model -import database.models.mixins from django.conf import settings import django.contrib.postgres.fields from django.db import migrations, models @@ -100,13 +99,13 @@ class Migration(migrations.Migration): name='Reaction', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('created_on', models.DateTimeField(default=None, null=True)), + ('created_on', models.DateTimeField(blank=True, default=None, null=True)), ('revision', models.BooleanField(default=False)), ('status', models.CharField(blank=True, choices=[('A', 'Approved'), ('P', 'Pending'), ('D', 'Denied')], max_length=1)), - ('hash', models.CharField(max_length=32, unique=True)), + ('hash', models.CharField(max_length=32)), ('prime_id', models.CharField(blank=True, max_length=10, verbose_name='PrIMe ID')), ('reversible', models.BooleanField()), - ('created_by', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL)), + ('created_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL)), ], options={ 'ordering': ('prime_id',), @@ -133,15 +132,15 @@ class Migration(migrations.Migration): name='Species', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('created_on', models.DateTimeField(default=None, null=True)), + ('created_on', models.DateTimeField(blank=True, default=None, null=True)), ('revision', models.BooleanField(default=False)), ('status', models.CharField(blank=True, choices=[('A', 'Approved'), ('P', 'Pending'), ('D', 'Denied')], max_length=1)), ('hash', models.CharField(max_length=32)), ('prime_id', models.CharField(blank=True, max_length=9, verbose_name='PrIMe ID')), ('cas_number', models.CharField(blank=True, max_length=400, verbose_name='CAS Registry Number')), - ('created_by', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL)), + ('created_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL)), ('isomers', models.ManyToManyField(to='database.Isomer')), - ('target', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='database.Species')), + ('target', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='database.Species')), ], options={ 'verbose_name_plural': 'Species', @@ -280,14 +279,14 @@ class Migration(migrations.Migration): name='Stoichiometry', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('created_on', models.DateTimeField(default=None, null=True)), + ('created_on', models.DateTimeField(blank=True, default=None, null=True)), ('revision', models.BooleanField(default=False)), ('status', models.CharField(blank=True, choices=[('A', 'Approved'), ('P', 'Pending'), ('D', 'Denied')], max_length=1)), ('coeff', models.FloatField()), - ('created_by', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL)), + ('created_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL)), ('reaction', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='database.Reaction')), ('species', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='database.Species')), - ('target', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='database.Stoichiometry')), + ('target', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='database.Stoichiometry')), ], options={ 'verbose_name_plural': 'Stoichiometries', @@ -311,7 +310,7 @@ class Migration(migrations.Migration): migrations.AddField( model_name='reaction', name='target', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='database.Reaction'), + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='database.Reaction'), ), migrations.CreateModel( name='KineticsComment', @@ -388,7 +387,7 @@ class Migration(migrations.Migration): 'indexes': [], 'constraints': [], }, - bases=('database.reaction', database.models.mixins.RevisionManagerMixin), + bases=('database.reaction', models.Model), ), migrations.CreateModel( name='SpeciesRevision', @@ -399,7 +398,7 @@ class Migration(migrations.Migration): 'indexes': [], 'constraints': [], }, - bases=('database.species', database.models.mixins.RevisionManagerMixin), + bases=('database.species', models.Model), ), migrations.CreateModel( name='StoichiometryRevision', @@ -410,7 +409,7 @@ class Migration(migrations.Migration): 'indexes': [], 'constraints': [], }, - bases=('database.stoichiometry', database.models.mixins.RevisionManagerMixin), + bases=('database.stoichiometry', models.Model), ), migrations.CreateModel( name='Troe', diff --git a/database/models/mixins.py b/database/models/mixins.py index bcf33ece..46c6c2f1 100644 --- a/database/models/mixins.py +++ b/database/models/mixins.py @@ -28,13 +28,13 @@ class RevisionMixin(models.Model): (PENDING, "Pending"), (DENIED, "Denied"), ) - created_by = models.ForeignKey(User, null=True, on_delete=models.SET_NULL) - created_on = models.DateTimeField(default=None, null=True) + created_by = models.ForeignKey(User, null=True, blank=True, on_delete=models.SET_NULL) + created_on = models.DateTimeField(default=None, null=True, blank=True) revision = models.BooleanField(default=False) - target = models.ForeignKey("self", null=True, on_delete=models.SET_NULL) + target = models.ForeignKey("self", null=True, blank=True, on_delete=models.SET_NULL) status = models.CharField(choices=STATUS_CHOICES, max_length=1, blank=True) - # objects = NoRevisionManager() + objects = NoRevisionManager() class Meta: abstract = True diff --git a/database/models/reaction_species.py b/database/models/reaction_species.py index 91466128..4ed15b34 100644 --- a/database/models/reaction_species.py +++ b/database/models/reaction_species.py @@ -80,7 +80,7 @@ def formula(self): class Reaction(RevisionMixin): - hash = models.CharField(max_length=32, unique=True) + hash = models.CharField(max_length=32) species = models.ManyToManyField("Species", through="Stoichiometry") prime_id = models.CharField("PrIMe ID", blank=True, max_length=10) reversible = models.BooleanField() diff --git a/database/templates/admin/database/change_form.html b/database/templates/admin/database/change_form.html index 4c402de4..051feb9e 100644 --- a/database/templates/admin/database/change_form.html +++ b/database/templates/admin/database/change_form.html @@ -3,10 +3,12 @@ {% block submit_buttons_bottom %} {{ block.super }} -
+{% if original and original.revision %} + {% csrf_token %}
+{% endif %} {% endblock %} diff --git a/database/templates/database/revision.html b/database/templates/database/revision.html index 20a435d4..186b4046 100644 --- a/database/templates/database/revision.html +++ b/database/templates/database/revision.html @@ -6,13 +6,9 @@

{{ name }} {{ object.id }} Revision

{% csrf_token %} - {% if formset %} - {% for form in formset %} - {{ form|crispy }} - {% endfor %} - {% else %} - {{ form|crispy }} - {% endif %} + {{ formset.management_form }} + {{ formset }} + {{ form|crispy }}
{% endblock %} diff --git a/database/views.py b/database/views.py index b7a09099..0758fd4b 100644 --- a/database/views.py +++ b/database/views.py @@ -1,3 +1,4 @@ +from database.models.revisions import ReactionRevision import functools from itertools import zip_longest from collections import defaultdict @@ -26,7 +27,9 @@ Source, Reaction, Kinetics, - SpeciesRevision + SpeciesRevision, + Stoichiometry, + StoichiometryRevision, ) from .filters import SpeciesFilter, ReactionFilter, SourceFilter from .forms import RegistrationForm, StoichiometryFormSet @@ -385,7 +388,7 @@ def get_formset(self): else: return self.formset_class(instance=instance) - def post(self, request): + def post(self, request, **kwargs): form = self.get_form() formset = self.get_formset() self.object = self.get_object() @@ -432,9 +435,16 @@ def post(self, request, pk): return HttpResponseRedirect(self.get_url()) + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context["url_name"] = self.url_name + + return context + class SpeciesRevisionApprovalView(RevisionApprovalView): model = SpeciesRevision + url_name = "species-approval" def get_url(self): return reverse("admin:database_speciesrevision_changelist") @@ -446,3 +456,28 @@ def update_model(self, revision): species.isomers.clear() species.isomers.add(*revision.isomers.all()) species.save() + + +class ReactionRevisionApprovalView(RevisionApprovalView): + model = ReactionRevision + url_name = "reaction-approval" + + def get_url(self): + return reverse("admin:database_reactionrevision_changelist") + + def update_model(self, revision): + reaction = revision.target + reaction.prime_id = revision.prime_id + reaction.reversible = revision.reversible + reaction.stoichiometry_set.delete() + reaction.save() + new_stoichs = StoichiometryRevision.objects.filter(reaction=revision) + print(new_stoichs) + for stoich in new_stoichs: + stoich.revision = False + stoich.created_on = None + stoich.created_by = None + stoich.status = "" + stoich.reaction = reaction + print(stoich) + stoich.save()