Coverage for rest_api/models.py: 92%
249 statements
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-10 03:22 +0000
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-10 03:22 +0000
1from enum import Enum
3from django.db import models
4from django.db.models import Q
5from django.db.models import UniqueConstraint
6from django.utils import timezone
7from django.utils.translation import gettext_lazy as _
10class Sequence(models.Model):
11 """
12 Represents a genetic sequence (sample) identified by a unique hash.
14 Attributes:
15 seqhash (CharField): Identifier for the sequence (max length 200).
16 length (IntegerField, optional): Length of the sequence
17 init_upload_date (DateTimeField, auto_now=True): Timestamp of the initial upload.
18 last_update_date (DateTimeField, optional): Timestamp of the last update to the sequence.
19 """
21 seqhash = models.CharField(max_length=200)
22 name = models.CharField(unique=True, max_length=200)
23 init_upload_date = models.DateTimeField(auto_now=True)
24 last_update_date = models.DateTimeField(blank=True, null=True)
25 length = models.IntegerField(blank=True, null=True)
27 class Meta:
28 db_table = "sequence"
29 indexes = [
30 models.Index(fields=["name"]),
31 models.Index(fields=["init_upload_date"]),
32 models.Index(fields=["last_update_date"]),
33 ]
36class Alignment(models.Model):
37 """
38 Represents an alignment between a sequence and a replicon.
40 Attributes:
41 replicon (ForeignKey): Reference to the associated Replicon
42 sequence (ForeignKey): Reference to the Sequence aligned with Replicon
44 Constraints:
45 - Unique constraint on (replicon, sequence) to prevent duplicate alignments.
47 Indexes:
48 - Index on (replicon, sequence) to optimize queries.
49 """
51 replicon = models.ForeignKey("Replicon", models.CASCADE)
52 sequence = models.ForeignKey("Sequence", models.CASCADE, related_name="alignments")
54 class Meta:
55 indexes = [
56 models.Index(
57 fields=["replicon", "sequence"],
58 )
59 ]
60 constraints = [
61 UniqueConstraint(
62 name="unique_alignment",
63 fields=["replicon", "sequence"],
64 ),
65 ]
66 db_table = "alignment"
69class AnnotationType(models.Model):
70 """
71 Represents an annotation for nucleotide mutations, classified using SnpEff.
73 Attributes:
74 seq_ontology (CharField): Sequence ontology term describing the annotation (max length 50).
75 region (CharField, optional): Genomic region affected (max length 50, nullable).
76 impact (CharField): Impact classification (e.g., HIGH, MODERATE, LOW) (max length 20).
77 mutations (ManyToManyField): Related nucleotide mutations annotated with this type.
79 Constraints:
80 - Ensures unique annotations based on (seq_ontology, region, impact).
81 - Allows uniqueness for (seq_ontology, impact) when region is NULL.
82 """
84 seq_ontology = models.CharField(max_length=50)
85 region = models.CharField(max_length=50, blank=True, null=True)
86 impact = models.CharField(max_length=20)
87 mutations = models.ManyToManyField("NucleotideMutation", related_name="annotations")
89 def __str__(self) -> str:
90 return f"{self.seq_ontology} {self.impact} {self.region if self.region else ''}".strip()
92 class Meta:
93 db_table = "annotation_type"
94 constraints = [
95 UniqueConstraint(
96 name="unique_annotation",
97 fields=["seq_ontology", "region", "impact"],
98 ),
99 UniqueConstraint(
100 name="unique_annotation_null_region",
101 fields=["seq_ontology", "impact"],
102 condition=models.Q(region__isnull=True),
103 ),
104 ]
107class Replicon(models.Model):
108 """
109 Represents a replicon, a genetic element/segment/chromosome
110 Filled with information from the gene bank file via gbk_import
112 Attributes:
113 length (BigIntegerField, optional): Length of the replicon in base pairs.
114 sequence (TextField): Full nucleotide sequence of the replicon.
115 accession (CharField, unique, required): (NCBI) accession of sequence.
116 description (CharField, optional): Additional description of the replicon.
117 type (CharField, optional): Type of replicon (e.g., chromosome, plasmid).
118 segment_number (BigIntegerField, optional): Segment number if applicable.
119 reference (ForeignKey): id of linked reference genome.
121 Constraints:
122 - Ensures unique accession numbers if provided.
123 """
125 length = models.BigIntegerField(blank=True, null=True)
126 sequence = models.TextField()
127 accession = models.CharField(max_length=50, unique=True)
128 description = models.CharField(max_length=400, blank=True, null=True)
129 type = models.CharField(max_length=50, blank=True, null=True)
130 segment_number = models.BigIntegerField(blank=True, null=True)
131 reference = models.ForeignKey("Reference", models.CASCADE)
133 class Meta:
134 db_table = "replicon"
137class Gene(models.Model):
138 """
139 Represents a gene located on a replicon.
140 Filled with information from the gene bank file via gbk_import
142 Attributes:
143 description (CharField, optional): Functional description of the gene (max length 100).
144 start (BigIntegerField): Start position on the replicon (counting starts with 0).
145 end (BigIntegerField): End position on the replicon.
146 forward_strand (BooleanField): Indicates if the gene is on the forward strand.
147 symbol (CharField, optional): Gene symbol/name or abbreviation (max length 50).
148 accession (CharField): unique gene identifier, locus_tag or gene name (=symbol) per replicon
149 sequence (TextField, optional): Nucleotide sequence of the gene.
150 replicon (ForeignKey): Reference to the replicon where the gene is located.
151 type (TextChoices, optional): Classification of the gene (e.g., CDS, rRNA, tRNA).
153 Constraints:
154 - Ensures each gene is associated with a specific replicon.
155 """
157 description = models.CharField(max_length=100, blank=True, null=True)
158 start = models.BigIntegerField()
159 end = models.BigIntegerField()
160 forward_strand = models.BooleanField()
161 symbol = models.CharField(max_length=50, unique=False, blank=False, null=False)
162 accession = models.CharField(max_length=100, blank=False, null=False)
163 sequence = models.TextField(blank=True, null=True)
164 replicon = models.ForeignKey(Replicon, models.CASCADE)
166 class GeneTypes(models.TextChoices):
167 CDS = "CDS"
168 rRNA = "rRNA"
169 tRNA = "tRNA"
170 ncRNA = "ncRNA"
171 miRNA = "miRNA"
172 misc_RNA = "misc_RNA"
173 # tmRNA = "tmRNA"
175 type = models.CharField(choices=GeneTypes, blank=True, null=True)
177 class Meta:
178 db_table = "gene"
179 constraints = [
180 models.UniqueConstraint(
181 fields=["replicon", "accession"], name="unique_accession_per_replicon"
182 ),
183 ]
186class CDS(models.Model):
187 """
188 Represents a Coding Sequence (CDS) associated with a gene.
189 Filled with information from the gene bank file via gbk_import
191 Attributes:
192 accession (CharField, required, unique): Unique accession nid of gene.
193 sequence (TextField, optional): Nucleotide sequence of the CDS.
194 gene (ForeignKey): Reference to the associated gene (CASCADE deletion).
195 description (CharField, optional): Functional description of the CDS (max length 100).
197 Constraints:
198 - Ensures each CDS is linked to a specific gene.
199 - Enforces uniqueness on the accession number if provided.
200 """
202 accession = models.CharField(max_length=50, unique=True)
203 sequence = models.TextField(blank=True, null=True)
204 gene = models.ForeignKey(Gene, models.CASCADE)
205 description = models.CharField(max_length=100, blank=True, null=True)
207 class Meta:
208 db_table = "cds"
211class CDSSegment(models.Model):
212 """
213 Represents a segment of a Coding Sequence (CDS), useful for cases where
214 - a CDS is split across multiple regions of a gene
215 - or multiple CDSs from one gene
216 - or ribosomal slippage
217 Filled with information from the gene bank file via gbk_import
219 Attributes:
220 cds (ForeignKey): Reference to the associated CDS (CASCADE deletion).
221 order (BigIntegerField): Defines the sequential order of segments for final CDS product.
222 start (BigIntegerField): Start position of the segment within the nt sequence.
223 end (BigIntegerField): End position of the segment within the nt sequence.
224 forward_strand (BooleanField): Indicates whether the segment is on the forward strand.
226 Constraints:
227 - Ensures each segment of a CDS has a unique order within the same CDS.
228 """
230 cds = models.ForeignKey(CDS, models.CASCADE, related_name="cds_segments")
231 order = models.BigIntegerField()
232 start = models.BigIntegerField()
233 end = models.BigIntegerField()
234 forward_strand = models.BooleanField()
236 class Meta:
237 db_table = "cds_segment"
238 constraints = [
239 UniqueConstraint(
240 name="unique_cds_segment",
241 fields=["cds", "order"],
242 ),
243 ]
246class Peptide(models.Model):
247 """
248 Represents peptides that are generated from larger cds by cutting them into different parts
249 Filled with information from the gene bank file via gbk_import
251 Attributes:
252 cds (ForeignKey): Reference to the associated CDS (CASCADE deletion).
253 description (CharField, optional): Description (product tag) of peptide=final virus protein (enum mat_peptide or sig_peptide).
255 """
257 cds = models.ForeignKey(CDS, models.CASCADE, related_name="peptides")
258 description = models.CharField(max_length=100, blank=True, null=True)
260 class PeptideTypes(models.TextChoices):
261 mat_peptide = "mat_peptide"
262 sig_peptide = "sig_peptide"
264 type = models.CharField(choices=PeptideTypes)
266 class Meta:
267 db_table = "peptide"
270class PeptideSegment(models.Model):
271 """
272 Represents a segment of a Peptide, if CDS has joins, here too
274 Filled with information from the gene bank file via gbk_import
276 Attributes:
277 cds (ForeignKey): Reference to the associated CDS (CASCADE deletion).
278 order (BigIntegerField): Defines the sequential order of segments for final CDS product.
279 start (BigIntegerField): Start position of the segment within the nt sequence.
280 end (BigIntegerField): End position of the segment within the nt sequence.
281 forward_strand (BooleanField): Indicates whether the segment is on the forward strand.
283 Constraints:
284 - Ensures each segment of a CDS has a unique order within the same CDS.
285 """
287 peptide = models.ForeignKey(
288 Peptide, models.CASCADE, related_name="peptide_segments"
289 )
290 order = models.BigIntegerField()
291 start = models.BigIntegerField()
292 end = models.BigIntegerField()
293 start_cds = models.BigIntegerField()
294 end_cds = models.BigIntegerField()
296 class Meta:
297 db_table = "peptide_segment"
298 constraints = [
299 UniqueConstraint(
300 name="unique_peptide_segment",
301 fields=["peptide", "order"],
302 ),
303 ]
306class GeneSegment(models.Model):
307 """
308 Represents a segment of a gene, useful for split or modular genes.
309 Filled with information from the gene bank file via gbk_import
311 Attributes:
312 gene (ForeignKey): Reference to the associated gene (CASCADE deletion).
313 order (BigIntegerField): Defines the order of segments within the gene.
314 start (BigIntegerField): Start position of the segment within the gene.
315 end (BigIntegerField): End position of the segment within the gene.
316 forward_strand (BooleanField): Indicates if the segment is on the forward strand.
318 Constraints:
319 - Ensures each gene segment has a unique order within its gene.
320 """
322 gene = models.ForeignKey(Gene, models.CASCADE)
323 order = models.BigIntegerField()
324 start = models.BigIntegerField()
325 end = models.BigIntegerField()
326 forward_strand = models.BooleanField()
328 class Meta:
329 db_table = "gene_segment"
330 constraints = [
331 UniqueConstraint(
332 name="unique_gene_segment",
333 fields=["gene", "order"],
334 ),
335 ]
338class Lineage(models.Model):
339 """
340 Represents the hierarchical lineage information of a pathogen.
341 Import via cli command and import_lineage.py
343 Attributes:
344 name (CharField): The name of the lineage.
345 parent (ForeignKey): A reference to the parent lineage (if any), forming a tree-like structure.
347 Methods:
348 get_sublineages: Returns all sublineages, including direct children and recursive descendants.
349 get_sublineages_from_list (static): A helper method to retrieve sublineages from a list of lineages.
351 Constraints:
352 - Ensures uniqueness of lineage name and parent combination.
353 - Allows lineage to have unique names with a null parent.
354 """
356 name = models.CharField(max_length=50) # not unique because of recombinants
357 parent = models.ForeignKey("self", models.CASCADE, blank=True, null=True)
358 reference = models.ForeignKey("Reference", models.CASCADE)
360 def get_sublineages(self) -> set:
361 lineages = set([self])
362 lineages.update(
363 Lineage.get_sublineages_from_list(
364 Lineage.objects.filter(name=self.name, reference=self.reference_id)
365 )
366 )
367 return lineages
369 @staticmethod
370 def get_sublineages_from_list(lineages):
371 # Iterative breadth-first descent over the name-based parent links.
372 # Values are materialised each round (plain lists, not lazy querysets) to
373 # avoid pathologically nested subqueries, and a visited-guard guarantees
374 # termination. Stays within the same reference(s): lineage names collide
375 # across pathogens (e.g. RSV-A "A" vs Influenza H3N2 "A").
376 ref_ids = set(lineages.values_list("reference_id", flat=True))
377 frontier = set(lineages.values_list("name", flat=True))
378 seen_names = set(frontier)
379 lineages_set = set()
380 while frontier:
381 children = list(
382 Lineage.objects.filter(
383 parent__name__in=frontier, reference_id__in=ref_ids
384 )
385 )
386 lineages_set.update(children)
387 frontier = {c.name for c in children if c.name not in seen_names}
388 seen_names.update(frontier)
389 return lineages_set
391 def __str__(self) -> str:
392 return self.name
394 class Meta:
395 db_table = "lineage"
396 constraints = [
397 UniqueConstraint(
398 name="unique_lineage",
399 fields=["name", "parent", "reference"],
400 ),
401 UniqueConstraint(
402 name="unique_lineage_parent_null",
403 fields=["name", "reference"],
404 condition=models.Q(parent__isnull=True),
405 ),
406 ]
409class Reference(models.Model):
410 """
411 Represents a reference of a organism used for sequence alignment.
412 Filled with information from the gene bank file via gbk_import
414 Attributes:
415 name (CharField, optional, unique): Name of the gene bank file (max length 50).
416 accession (CharField, required, unique): Accession number of the gene bank file (max length 50).
417 description (CharField, optional): Description of the reference (max length 400).
418 organism (CharField, required): Name of the organism from which the reference is derived (max length 50).
419 mol_type (CharField, optional): Type of molecule (e.g., DNA, RNA) for the reference (max length 50).
420 isolate (CharField, optional): Isolate or strain information (max length 50).
421 host (CharField, optional): Host organism for the reference sequence (max length 50).
422 db_xref (CharField, optional, unique): Database cross-reference identifier (max length 50).
423 country (CharField, optional): Country of origin of the sample (max length 50).
424 collection_date (DateField, optional): Date when the sample was collected.
425 translation_id (IntegerField): ID used for translation of the reference sequence.
427 Constraints:
428 - Ensures unique identifiers for name, accession, and db_xref.
429 """
431 name = models.CharField(max_length=600, unique=True, blank=True, null=True)
432 accession = models.CharField(max_length=50, unique=True)
433 description = models.CharField(max_length=400, blank=True, null=True)
434 organism = models.CharField(max_length=50)
435 mol_type = models.CharField(max_length=50, blank=True, null=True)
436 isolate = models.CharField(max_length=50, blank=True, null=True)
437 host = models.CharField(max_length=50, blank=True, null=True)
438 db_xref = models.CharField(max_length=50, blank=True, null=True, unique=True)
439 country = models.CharField(max_length=50, blank=True, null=True)
440 collection_date = models.DateField(blank=True, null=True)
441 translation_id = models.IntegerField()
443 class Meta:
444 db_table = "reference"
447class Property(models.Model):
448 """
449 Represents a customizable property that can be defined by users to capture flexible data characteristics.
451 Attributes:
452 name (CharField, unique): The name of the property, must be unique.
453 datatype (CharField): The data type of the property (e.g., integer, string, etc.).
454 querytype (CharField, optional): The type of query that can be performed with the property (e.g., range, exact match).
455 description (CharField, optional): A description of the property for documentation purposes.
456 default (CharField, optional): provide default property value
458 Constraints:
459 - Ensures that the property name is unique.
460 """
462 name = models.CharField(max_length=50, unique=True)
463 datatype = models.CharField(max_length=50)
464 querytype = models.CharField(max_length=50, blank=True, null=True)
465 description = models.CharField(max_length=400, blank=True, null=True)
466 default = models.CharField(max_length=50, blank=True, null=True)
468 class Meta:
469 db_table = "property"
472class Sample(models.Model):
473 """
474 Represents a sample that has undergone sequencing and via cli: alignment, mutation calling, and annotation.
475 Metadata fields (sequencing_tech, country, host, zip_code, lab, lineage, collection_date, data_set) filled via metadata import of csv.
476 Other fields via sample_entry_job.py, sample_import.py
478 Attributes:
479 name (CharField, unique): Unique identifier for the sample.
480 datahash (CharField): (Not used at the moment) hash all metadata (include property metadata) for comparison before updating
481 sequences (ManyToManyField): The sequences associated with the sample.
482 sequencing_tech (CharField, optional): Sequencing technology used.
483 country (CharField, optional): Country of origin for the sample.
484 host (CharField, optional): The host organism of the sample.
485 zip_code (CharField, optional): The postal code where the sample was collected.
486 lab (CharField, optional): The lab where the sample was processed.
487 lineage (CharField, optional): Lineage identifier for the sample.
488 genome_completeness (CharField, optional): Indicator of the genome completeness.
489 collection_date (DateField, optional): The date the sample was collected.
490 data_set (CharField, optional): The data set the sample is part of, e.g. rKI, Gisaid.
491 properties (ManyToManyField, optional): User-defined properties assigned to the sample.
493 Constraints:
494 - Ensures that each sample has a unique name.
495 """
497 name = models.CharField(max_length=100, unique=True)
498 lineage = models.CharField(max_length=50, blank=True, null=True)
499 genome_completeness = models.CharField(max_length=50, blank=True, null=True)
500 collection_date = models.DateField(blank=True, null=True)
501 data_set = models.CharField(max_length=50, blank=True, null=True)
502 sequencing_tech = models.CharField(max_length=50, blank=True, null=True)
503 country = models.CharField(max_length=50, blank=True, null=True)
504 host = models.CharField(max_length=50, blank=True, null=True)
505 zip_code = models.CharField(max_length=50, blank=True, null=True)
506 lab = models.CharField(max_length=50, blank=True, null=True)
507 init_upload_date = models.DateTimeField(auto_now=True)
508 last_update_date = models.DateTimeField(blank=True, null=True)
509 datahash = models.CharField(max_length=50)
511 sequences = models.ManyToManyField(Sequence, related_name="samples")
513 class Meta:
514 db_table = "sample"
515 indexes = [
516 models.Index(fields=["name"]),
517 models.Index(fields=["sequencing_tech"]),
518 models.Index(fields=["country"]),
519 models.Index(fields=["host"]),
520 models.Index(fields=["zip_code"]),
521 models.Index(fields=["lab"]),
522 models.Index(fields=["lineage"]),
523 models.Index(fields=["genome_completeness"]),
524 models.Index(fields=["collection_date"]),
525 models.Index(fields=["data_set"]),
526 models.Index(fields=["init_upload_date"]),
527 models.Index(fields=["last_update_date"]),
528 ]
530 def save(self, *args, **kwargs):
531 if self.pk: # Check if this is an update to an existing record
532 self.last_update_date = timezone.now()
533 super().save(*args, **kwargs)
536class Sample2Property(models.Model):
537 """
538 Represents a relationship between a sample and a property, allowing the association
539 of multiple properties to a single sample, with flexibility in value types.
541 Attributes:
542 property (ForeignKey): The property being associated with the sample.
543 sample (ForeignKey): The sample to which the property is associated.
544 value_integer (BigIntegerField, optional): Integer value for the property.
545 value_float (FloatField, optional): Floating-point value for the property.
546 value_text (TextField, optional): Text value for the property.
547 value_varchar (CharField, optional): Varchar value for the property.
548 value_blob (BinaryField, optional): Binary data value for the property.
549 value_date (DateField, optional): Date value for the property.
550 value_zip (CharField, optional): Zip code value for the property.
552 Constraints:
553 - Ensures that each combination of property and sample is unique.
554 """
556 property = models.ForeignKey(Property, models.CASCADE)
557 sample = models.ForeignKey(Sample, models.CASCADE, related_name="properties")
558 value_integer = models.BigIntegerField(blank=True, null=True)
559 value_float = models.FloatField(blank=True, null=True)
560 value_text = models.TextField(blank=True, null=True)
561 value_varchar = models.CharField(max_length=400, blank=True, null=True)
562 value_blob = models.BinaryField(blank=True, null=True)
563 value_date = models.DateField(blank=True, null=True)
564 value_zip = models.CharField(max_length=100, blank=True, null=True)
566 class Meta:
567 db_table = "sample2property"
568 constraints = [
569 UniqueConstraint(
570 name="unique_property2sample",
571 fields=["property", "sample"],
572 ),
573 ]
576class NucleotideMutation(models.Model):
577 """
578 Represents a nucleotide mutation within a replicon, storing the reference nt
579 and alternative nucleotides, along with mutation position(s). Stores alignments
580 that contain this mutation.
582 Attributes:
583 replicon (ForeignKey): The replicon in which the mutation is located.
584 ref (TextField): The reference nucleotide(s) .
585 alt (TextField): The alternative nucleotide.
586 start (BigIntegerField): The starting position of the mutation in ref(couting is 0 based).
587 end (BigIntegerField): The ending position of the mutation in ref.
588 is_frameshift (BooleanField): Indicates if the mutation is a frameshift mutation.
589 alignments (ManyToManyField): Many-to-many relationship with Alignment (representing samples) instances.
591 Constraints:
592 - Ensures that the combination of `ref`, `alt`, `start`, `end`, and `replicon`
593 is unique for each mutation in the replicon.
594 """
596 replicon = models.ForeignKey(Replicon, models.CASCADE, blank=True, null=True)
597 ref = models.TextField()
598 alt = models.TextField()
599 start = models.BigIntegerField()
600 end = models.BigIntegerField()
601 is_frameshift = models.BooleanField(default=False)
603 alignments = models.ManyToManyField(
604 Alignment,
605 related_name="nucleotide_mutations",
606 )
608 def __str__(self) -> str:
609 return f"{self.start}-{self.end} {self.ref}>{self.alt} {self.is_frameshift}"
611 class Meta:
612 db_table = "nucleotide_mutation"
613 indexes = [
614 models.Index(fields=["start"]),
615 models.Index(fields=["end"]),
616 models.Index(fields=["ref"]),
617 models.Index(fields=["alt"]),
618 ]
619 constraints = [
620 UniqueConstraint(
621 name="unique_nt_mutation",
622 fields=["ref", "alt", "start", "end", "replicon"],
623 )
624 ]
627class AminoAcidMutation(models.Model):
628 """
629 Represents an amino acid mutation, storing information about the mutation's
630 position in ref, the reference and alternative amino acids,
631 and links to nucleotide mutations resulting in cds mutation.
632 Alignments represent samples with this cds mutation
634 Attributes:
635 cds (ForeignKey): The coding sequence in which the mutation is located.
636 ref (TextField): The reference amino acid
637 alt (TextField): The alternative amino acid/ the mutation
638 start (BigIntegerField): The start position of the mutation in ref.
639 end (BigIntegerField): The end position of the mutation in ref.
640 parent (ManyToManyField): Many-to-many relationship with nucleotide mutations (multiple mutations can result in one amino acid mutation).
641 alignments (ManyToManyField): Many-to-many relationship with alignments (samples) containing this mutation.
643 Constraints:
644 - Ensures that the combination of `ref`, `alt`, `start`, `end`, `cds`, and `replicon`
645 is unique for each mutation in the replicon and CDS.
646 """
648 cds = models.ForeignKey(CDS, models.CASCADE)
649 ref = models.TextField()
650 alt = models.TextField()
651 start = models.BigIntegerField()
652 end = models.BigIntegerField()
653 parent = models.ManyToManyField(NucleotideMutation)
654 alignments = models.ManyToManyField(
655 Alignment,
656 related_name="amino_acid_mutations",
657 )
659 def __str__(self) -> str:
660 return f"{self.start}-{self.end} {self.ref}>{self.alt}"
662 class Meta:
663 db_table = "amino_acid_mutation"
664 indexes = [
665 models.Index(fields=["cds"]),
666 models.Index(fields=["start"]),
667 models.Index(fields=["end"]),
668 models.Index(fields=["ref"]),
669 models.Index(fields=["alt"]),
670 ]
671 constraints = [
672 UniqueConstraint(
673 name="unique_aa_mutation",
674 fields=["ref", "alt", "start", "end", "cds"],
675 ),
676 ]
679class ProcessingJob(models.Model):
680 class ImportType(models.TextChoices):
681 QUEUED = "Q", _("Queued")
682 IN_PROGRESS = "IP", _("In Progress")
683 COMPLETED = "C", _("Completed")
684 FAILED = "F", _("Failed")
686 job_name = models.CharField(max_length=255, unique=True)
687 status = models.CharField(
688 max_length=2,
689 choices=ImportType.choices,
690 default=ImportType.QUEUED,
691 )
692 entry_time = models.DateTimeField(auto_now=True, unique=True)
694 class Meta:
695 db_table = "processing_job"
698class FileProcessing(models.Model):
699 file_name = models.CharField(max_length=255, unique=True)
700 processing_job = models.ForeignKey(
701 "ProcessingJob", on_delete=models.CASCADE, related_name="files"
702 )
704 class Meta:
705 db_table = "file_processing"
708class ImportLog(models.Model):
709 class ImportType(models.TextChoices):
710 UNKNOWN = "NUL", _("Unknown")
711 SAMPLE = "SMP", _("Sample")
712 ANNOTATION = "ANN", _("Annotation")
713 GENEBANK = "GBK", _("Genebank")
714 SAMPLE_ANNOTATION_ARCHIVE = "SAA", _("Sample Annotation Archive")
715 PROPERTY = "PTY", _("Property")
717 type = models.CharField(
718 max_length=3,
719 choices=ImportType.choices,
720 default=ImportType.UNKNOWN,
721 )
722 file = models.ForeignKey(
723 FileProcessing,
724 to_field="file_name",
725 on_delete=models.CASCADE,
726 )
727 updated = models.DateTimeField(auto_now=True)
728 success = models.BooleanField()
729 exception_text = models.TextField(blank=True, null=True)
730 stack_trace = models.TextField(blank=True, null=True)
732 class Meta:
733 db_table = "import_log"
734 constraints = [
735 UniqueConstraint(
736 name="unique_import_log",
737 fields=["file", "updated"],
738 ),
739 ]