Skip to content

Integrate tissues app#90

Open
TheSinnerAR wants to merge 2 commits intodevfrom
feature/tissue-support
Open

Integrate tissues app#90
TheSinnerAR wants to merge 2 commits intodevfrom
feature/tissue-support

Conversation

@TheSinnerAR
Copy link
Collaborator

Tissue Support

Adds a new tissues Django app providing read-only reference data for tissue types,
and integrates it into UserFile and CGDSStudy as a ManyToMany relationship.


New app: tissues

Model: Tissue

  • Fields: name (unique), code (unique) — code is the name uppercased with spaces
    replaced by underscores (e.g. Cervix UteriCERVIX_UTERI)
  • delete() is overridden to raise PermissionDenied — tissues cannot be deleted
  • Ordered alphabetically by name

Admin

  • Read-only: has_add_permission, has_change_permission and has_delete_permission
    all return False

Initial data (19 tissues)
Loaded via migration 0002_tissue_code_and_initial_data, sourced from GTEx tissue names:
Adrenal Gland, Bladder, Blood, Brain, Breast, Cervix Uteri, Colon,
Esophagus, Kidney, Liver, Lung, Ovary, Pancreas, Prostate, Skin,
Stomach, Testis, Thyroid, Uterus


Integration

UserFile and CGDSStudy both have a new tissues = ManyToManyField(Tissue, blank=True)
field. A file or study can have zero or more tissues assigned.

Serializers

Operation Field Type
Read (GET) tissues [{id, name, code}, ...]
Write (POST/PATCH) tissue_ids [1, 2, ...]

Filters
Both list endpoints accept ?tissues=<id> as a query parameter (via DjangoFilterBackend).


Endpoints

Method URL Description
GET /tissues/ List all tissues. Supports ?search=
GET /user-files/?tissues=<id> Filter user files by tissue
PATCH /user-files/<id>/ Assign tissues via {"tissue_ids": [1, 2]}
GET /cgds/studies/?tissues=<id> Filter CGDS studies by tissue
PATCH /cgds/studies/<id>/ Assign tissues via {"tissue_ids": [1, 2]}

Migrations

App Migration Description
tissues 0001_initial Creates tissues_tissue table
tissues 0002_tissue_code_and_initial_data Adds code field, loads 19 tissues
user_files 0017_remove_userfile_tissue_userfile_tissues FK → ManyToMany
datasets_synchronization 0038_remove_cgdsstudy_tissue_cgdsstudy_tissues FK → ManyToMany

Introduce a new read-only tissues app (model, admin, serializer, views, URLs, app config) with initial migration and a data migration loading a list of tissue names. Add tissue ForeignKey fields to CGDSStudy and UserFile with corresponding migrations. Update serializers to accept tissue_id (writable PK) and include nested tissue representation on retrieve; persist tissue on updates/creates. Expose tissues in the REST API and enable filtering by tissue for CGDSStudy and UserFile (DjangoFilterBackend imports and filterset_fields). Register the app in settings and project URLs, and add a frontend URL constant for tissues. Admin/UI prevents adding/changing/deleting tissues (read-only).
Convert Tissue FK to ManyToMany on CGDSStudy and UserFile and update related code. Models updated to use tissues M2M; serializers changed (tissue_id -> tissue_ids, nested tissues in responses, create/update now set M2M relations); views' filterset_fields switched to 'tissues'; admin updated to filter and edit M2M with filter_horizontal and a user-facing tissue list column. Added migrations to replace FK with M2M for datasets_synchronization and user_files, and a new tissues migration that adds a unique code field and loads standardized initial tissue data (replacing the previous locale-specific seed). Run migrations after pulling these changes.
version = serializers.IntegerField(read_only=True)
is_last_version = serializers.SerializerMethodField(method_name='get_is_last_version')
# tissue_ids: writable list of PKs; tissues: read-only nested list (set in to_representation)
tissue_ids = serializers.PrimaryKeyRelatedField(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tanto esto como el to_representation debería ser eliminado. Acá poner directamente Tissues, el frontend debe recibir y enviar los IDs siempre. Si necesita saber cuál es cual, debe traer desde otro endpoint los Tissues y cargarlos en el select que corresponde. Pero esto de mandar todo el tiempo el mismo campo con diferente estructura es poco escalable: por cada FK que tengamos vamos a tener dos campos

def get_is_last_version(study: CGDSStudy) -> bool:
return study.version == study.get_last_version()

def to_representation(self, instance: CGDSStudy):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Eliminar

filter_horizontal = ('tissues',)

def tissue_list(self, obj):
return ', '.join(t.name for t in obj.tissues.all())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Optimizar a ', '.join(obj.tissues.values_list('name', flat=True))

class UserFileSerializer(serializers.ModelSerializer):
user = UserSimpleSerializer(many=False, read_only=True)
survival_columns = SurvivalColumnsTupleUserFileSimpleSerializer(many=True, read_only=True)
tissue_ids = serializers.PrimaryKeyRelatedField(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Idem comentario anterior, dejar siempre el campo tissues como IDs tanto para recibir como para enviar al frontend

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants