Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 73 additions & 0 deletions backend/proteins/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

from fpbase.util import uncache_protein_page
from proteins.models import (
BleachCurve,
BleachMeasurement,
Camera,
Dye,
Expand All @@ -22,10 +23,12 @@
FluorState,
Light,
Lineage,
MaturationCurve,
Microscope,
OpticalConfig,
Organism,
OSERMeasurement,
PKACurve,
Protein,
ProteinCollection,
SnapGenePlasmid,
Expand Down Expand Up @@ -398,6 +401,7 @@ class BleachMeasurementAdmin(VersionAdmin):
model = BleachMeasurement
autocomplete_fields = ("state", "reference")
list_select_related = ("state", "state__protein")
search_fields = ("state__protein__name",)


@admin.register(State)
Expand Down Expand Up @@ -892,3 +896,72 @@ def get_form(self, request, obj=None, **kwargs):
qs = qs.exclude(id=obj.id)
form.base_fields["parent"].queryset = qs
return form


# ############ CURVE ADMINS ###############


class CurveAdmin(VersionAdmin):
"""Base admin for curve models."""

list_display = ("__str__", "status", "x_min", "x_max", "reference", "modified")
list_filter = ("status", "created", "modified")
autocomplete_fields = ("reference",)
readonly_fields = ("x_min", "x_max", "created", "modified")
fieldsets = [
(None, {"fields": ("status",)}),
("Data Range", {"fields": (("x_min", "x_max"),), "classes": ("collapse",)}),
(
"Provenance",
{"fields": ("reference", "source", "notes"), "classes": ("collapse",)},
),
(
"Metadata",
{
"fields": (("created", "created_by"), ("modified", "updated_by")),
"classes": ("collapse",),
},
),
]


@admin.register(PKACurve)
class PKACurveAdmin(CurveAdmin):
model = PKACurve
autocomplete_fields = (*CurveAdmin.autocomplete_fields, "state")
list_select_related = ("state", "state__protein", "reference")
search_fields = ("state__protein__name",)
fieldsets = [
(None, {"fields": ("state", "status")}),
*CurveAdmin.fieldsets[1:],
]


@admin.register(BleachCurve)
class BleachCurveAdmin(CurveAdmin):
model = BleachCurve
autocomplete_fields = (*CurveAdmin.autocomplete_fields, "bleach_measurement")
list_select_related = (
"bleach_measurement",
"bleach_measurement__state",
"bleach_measurement__state__protein",
"reference",
)
search_fields = ("bleach_measurement__state__protein__name",)
fieldsets = [
(None, {"fields": ("bleach_measurement", "status")}),
*CurveAdmin.fieldsets[1:],
]


@admin.register(MaturationCurve)
class MaturationCurveAdmin(CurveAdmin):
model = MaturationCurve
autocomplete_fields = (*CurveAdmin.autocomplete_fields, "state")
list_select_related = ("state", "state__protein", "reference")
search_fields = ("state__protein__name",)
list_display = (*CurveAdmin.list_display[:4], "temperature", *CurveAdmin.list_display[4:])
fieldsets = [
(None, {"fields": ("state", "status", "temperature")}),
*CurveAdmin.fieldsets[1:],
]
95 changes: 95 additions & 0 deletions backend/proteins/migrations/0061_curve_data_models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# Generated by Django 5.2.8 on 2026-01-06 16:25

import django.db.models.deletion
import django.utils.timezone
import model_utils.fields
from django.conf import settings
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('proteins', '0060_spectrum_optimized_storage'),
('references', '0009_curve_data_models'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]

operations = [
migrations.CreateModel(
name='BleachCurve',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created', model_utils.fields.AutoCreatedField(default=django.utils.timezone.now, editable=False, verbose_name='created')),
('modified', model_utils.fields.AutoLastModifiedField(default=django.utils.timezone.now, editable=False, verbose_name='modified')),
('status', model_utils.fields.StatusField(choices=[('approved', 'approved'), ('pending', 'pending'), ('rejected', 'rejected')], default='approved', max_length=100, no_check_for_status=True, verbose_name='status')),
('status_changed', model_utils.fields.MonitorField(default=django.utils.timezone.now, monitor='status', verbose_name='status changed')),
('x_values', models.BinaryField(help_text='X values as float32 binary array')),
('y_values', models.BinaryField(help_text='Y values as float32 binary array')),
('x_min', models.FloatField(blank=True, help_text='Minimum X value', null=True)),
('x_max', models.FloatField(blank=True, help_text='Maximum X value', null=True)),
('source', models.CharField(blank=True, help_text='Source of the curve data', max_length=128)),
('notes', models.TextField(blank=True, help_text='Additional notes or conditions')),
('bleach_measurement', models.ForeignKey(help_text='BleachMeasurement this curve belongs to', on_delete=django.db.models.deletion.CASCADE, related_name='curves', to='proteins.bleachmeasurement')),
('created_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='%(class)s_author', to=settings.AUTH_USER_MODEL)),
('reference', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='%(class)s_curves', to='references.reference')),
('updated_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='%(class)s_modifier', to=settings.AUTH_USER_MODEL)),
],
options={
'verbose_name': 'Bleach Curve',
'verbose_name_plural': 'Bleach Curves',
'indexes': [models.Index(fields=['bleach_measurement_id', 'status'], name='bleachcurve_meas_status_idx')],
},
),
migrations.CreateModel(
name='MaturationCurve',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created', model_utils.fields.AutoCreatedField(default=django.utils.timezone.now, editable=False, verbose_name='created')),
('modified', model_utils.fields.AutoLastModifiedField(default=django.utils.timezone.now, editable=False, verbose_name='modified')),
('status', model_utils.fields.StatusField(choices=[('approved', 'approved'), ('pending', 'pending'), ('rejected', 'rejected')], default='approved', max_length=100, no_check_for_status=True, verbose_name='status')),
('status_changed', model_utils.fields.MonitorField(default=django.utils.timezone.now, monitor='status', verbose_name='status changed')),
('x_values', models.BinaryField(help_text='X values as float32 binary array')),
('y_values', models.BinaryField(help_text='Y values as float32 binary array')),
('x_min', models.FloatField(blank=True, help_text='Minimum X value', null=True)),
('x_max', models.FloatField(blank=True, help_text='Maximum X value', null=True)),
('source', models.CharField(blank=True, help_text='Source of the curve data', max_length=128)),
('notes', models.TextField(blank=True, help_text='Additional notes or conditions')),
('temperature', models.FloatField(blank=True, help_text='Temperature in °C during maturation measurement', null=True)),
('created_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='%(class)s_author', to=settings.AUTH_USER_MODEL)),
('reference', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='%(class)s_curves', to='references.reference')),
('state', models.ForeignKey(help_text='Protein state this curve belongs to', on_delete=django.db.models.deletion.CASCADE, related_name='maturation_curves', to='proteins.state')),
('updated_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='%(class)s_modifier', to=settings.AUTH_USER_MODEL)),
],
options={
'verbose_name': 'Maturation Curve',
'verbose_name_plural': 'Maturation Curves',
'indexes': [models.Index(fields=['state_id', 'status'], name='matcurve_state_status_idx')],
},
),
migrations.CreateModel(
name='PKACurve',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created', model_utils.fields.AutoCreatedField(default=django.utils.timezone.now, editable=False, verbose_name='created')),
('modified', model_utils.fields.AutoLastModifiedField(default=django.utils.timezone.now, editable=False, verbose_name='modified')),
('status', model_utils.fields.StatusField(choices=[('approved', 'approved'), ('pending', 'pending'), ('rejected', 'rejected')], default='approved', max_length=100, no_check_for_status=True, verbose_name='status')),
('status_changed', model_utils.fields.MonitorField(default=django.utils.timezone.now, monitor='status', verbose_name='status changed')),
('x_values', models.BinaryField(help_text='X values as float32 binary array')),
('y_values', models.BinaryField(help_text='Y values as float32 binary array')),
('x_min', models.FloatField(blank=True, help_text='Minimum X value', null=True)),
('x_max', models.FloatField(blank=True, help_text='Maximum X value', null=True)),
('source', models.CharField(blank=True, help_text='Source of the curve data', max_length=128)),
('notes', models.TextField(blank=True, help_text='Additional notes or conditions')),
('created_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='%(class)s_author', to=settings.AUTH_USER_MODEL)),
('reference', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='%(class)s_curves', to='references.reference')),
('state', models.ForeignKey(help_text='Protein state this curve belongs to', on_delete=django.db.models.deletion.CASCADE, related_name='pka_curves', to='proteins.state')),
('updated_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='%(class)s_modifier', to=settings.AUTH_USER_MODEL)),
],
options={
'verbose_name': 'pKa Curve',
'verbose_name_plural': 'pKa Curves',
'indexes': [models.Index(fields=['state_id', 'status'], name='pkacurve_state_status_idx')],
},
),
]
4 changes: 4 additions & 0 deletions backend/proteins/models/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from proteins.models.bleach import BleachMeasurement
from proteins.models.collection import ProteinCollection
from proteins.models.curve import BleachCurve, MaturationCurve, PKACurve
from proteins.models.dye import Dye, DyeState
from proteins.models.efficiency import OcFluorEff
from proteins.models.excerpt import Excerpt
Expand All @@ -15,6 +16,7 @@
from proteins.models.transition import StateTransition

__all__ = [
"BleachCurve",
"BleachMeasurement",
"Camera",
"Dye",
Expand All @@ -26,11 +28,13 @@
"FluorescenceMeasurement",
"Light",
"Lineage",
"MaturationCurve",
"Microscope",
"OSERMeasurement",
"OcFluorEff",
"OpticalConfig",
"Organism",
"PKACurve",
"Protein",
"ProteinCollection",
"SnapGenePlasmid",
Expand Down
Loading
Loading