django-nose didn't work with django 1.1, so I went back to the nose plugin NoseDjango
[htsworkflow.git] / htsworkflow / frontend / experiments / models.py
1 import logging
2
3 from django.core.exceptions import ObjectDoesNotExist
4 from django.core import urlresolvers
5 from django.db import models
6
7 from htsworkflow.frontend.samples.models import *
8 #from htsworkflow.frontend.settings import options
9 from django.conf import settings
10
11 class ClusterStation(models.Model):
12   name = models.CharField(max_length=50, unique=True)
13
14   def __unicode__(self):
15     return unicode(self.name)
16
17 class Sequencer(models.Model):
18   name = models.CharField(max_length=50, unique=True)
19
20   def __unicode__(self):
21     return unicode(self.name)
22
23 default_pM = 5
24 try:
25   default_pM = int(settings.DEFAULT_PM)
26 except ValueError,e:
27   logging.error("invalid value for frontend.default_pm")
28
29 class FlowCell(models.Model):
30   
31   flowcell_id = models.CharField(max_length=20, unique=True, db_index=True)
32   run_date = models.DateTimeField()
33   advanced_run = models.BooleanField(default=False)
34   paired_end = models.BooleanField(default=False)
35   read_length = models.IntegerField(default=32) #Stanford is currenlty 25
36   control_lane = models.IntegerField(choices=[(1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8),(0,'All Lanes')], null=True)
37
38   cluster_station = models.ForeignKey(ClusterStation, default=3)
39   sequencer = models.ForeignKey(Sequencer, default=1)
40   
41   notes = models.TextField(blank=True)
42
43   def __unicode__(self):
44       return unicode(self.flowcell_id) 
45
46   def Create_LOG(self):
47     str = ''
48     str +='<a target=_balnk href="/experiments/'+self.flowcell_id+'" title="Create XLS like sheet for this Flowcell ..." ">Create LOG</a>'
49     try:
50       t = DataRun.objects.get(fcid=self.id)
51       str +='<br/><a target=_self href="/admin/experiments/datarun/?q='+self.flowcell_id+'" title="Check Data Runs ..." ">DataRun ..</a>'
52     except ObjectDoesNotExist:
53       str += '<br/><span style="color:red">not sequenced</span>'
54     return str
55   Create_LOG.allow_tags = True 
56
57   def Lanes(self):
58     library_url = '/admin/samples/library/%s' 
59     html = ['<table>']
60     #for i in range(1,9):
61     for lane in self.lane_set.all():
62         cluster_estimate = lane.cluster_estimate
63         if cluster_estimate is not None:
64             cluster_estimate = "%s k" % ((int(cluster_estimate)/1000), )
65         else:
66             cluster_estimate = 'None'
67         library_id = lane.library_id
68         library = lane.library
69         element = '<tr><td>%d</td><td><a href="%s">%s</a></td><td>%s</td></tr>'
70         expanded_library_url = library_url %(library_id,)
71         html.append(element % (lane.lane_number, expanded_library_url, library, cluster_estimate))
72     html.append('</table>')
73     return "\n".join(html)
74   Lanes.allow_tags = True
75
76   class Meta:
77     ordering = ["-run_date"]
78
79   def get_admin_url(self):
80     # that's the django way... except it didn't work
81     #return urlresolvers.reverse('admin_experiments_FlowCell_change', args=(self.id,))
82     return '/admin/experiments/flowcell/%s/' % (self.id,)
83
84   def flowcell_type(self):
85     """
86     Convert our boolean 'is paired' flag to a name
87     """
88     if self.paired_end:
89       return u"Paired"
90     else:
91       return u"Single"
92
93   @models.permalink
94   def get_absolute_url(self):
95       return ('htsworkflow.frontend.experiments.views.flowcell_detail',
96               [str(self.flowcell_id)])
97     
98 ### -----------------------
99 class DataRun(models.Model):
100   ConfTemplate = "CONFIG PARAMS WILL BE GENERATED BY THE PIPELINE SCRIPT.\nYOU'LL BE ABLE TO EDIT AFTER IF NEEDED."
101   run_folder = models.CharField(max_length=50,unique=True, db_index=True)
102   fcid = models.ForeignKey(FlowCell,verbose_name="Flowcell Id")
103   config_params = models.TextField(default=ConfTemplate)
104   run_start_time = models.DateTimeField()
105   RUN_STATUS_CHOICES = (
106       (0, 'Sequencer running'), ##Solexa Data Pipeline Not Yet Started'),
107       (1, 'Data Pipeline Started'),
108       (2, 'Data Pipeline Interrupted'),
109       (3, 'Data Pipeline Finished'),
110       (4, 'CollectReads Started'),
111       (5, 'CollectReads Finished'),
112       (6, 'QC Finished'),
113       (7, 'DONE'),
114     )
115   run_status = models.IntegerField(choices=RUN_STATUS_CHOICES, default=0)
116   run_note = models.TextField(blank=True)
117
118
119   def main_status(self):
120     str = '<div'
121     if self.run_status >= 5:
122       str += ' style="color:green">'
123       str += '<b>'+self.RUN_STATUS_CHOICES[self.run_status][1]+'</b>'
124       str += '<br/><br/>' #<span style="color:red;font-size:80%;">New!</span>'
125       str +='<br/><a target=_balnk href="'+settings.TASKS_PROJS_SERVER+'/Flowcells/'+self.fcid.flowcell_id+'/'+self.fcid.flowcell_id+'_QC_Summary.html" title="View QC Summaries of this run ..." ">View QC Page</a>'
126     else:
127       str += '>'+self.RUN_STATUS_CHOICES[self.run_status][1]
128
129     str += '</div>'
130     return str
131   main_status.allow_tags = True
132
133   main_status.allow_tags = True
134   
135   def Flowcell_Info(self):
136     str = '<b>'+self.fcid.__str__()+'</b>'
137     str += '  (c: '+self.fcid.cluster_mac_id+',  s: '+self.fcid.seq_mac_id+')'
138     str += '<div style="margin-top:5px;">'    
139     str +='<a title="View Lane List here ..."  onClick="el = document.getElementById(\'LanesOf'+self.fcid.__str__()+'\');if(el) (el.style.display==\'none\'?el.style.display=\'block\':el.style.display=\'none\')" style="cursor:pointer;color: #5b80b2;">View/hide lanes</a>'
140     str += '<div id="LanesOf'+self.fcid.__str__()+'" style="display:block;border:solid #cccccc 1px;width:350px">'
141     LanesList = '1: '+self.fcid.lane_1_library.__str__()+' ('+self.fcid.lane_1_library.library_species.use_genome_build+')<br/>2: '+self.fcid.lane_2_library.__str__()+' ('+self.fcid.lane_2_library.library_species.use_genome_build+')<br/>3: '+self.fcid.lane_3_library.__str__()+' ('+self.fcid.lane_3_library.library_species.use_genome_build+')<br/>4: '+self.fcid.lane_4_library.__str__()+' ('+self.fcid.lane_4_library.library_species.use_genome_build+')<br/>5: '+self.fcid.lane_5_library.__str__()+' ('+self.fcid.lane_5_library.library_species.use_genome_build+')<br/>6: '+self.fcid.lane_6_library.__str__()+' ('+self.fcid.lane_6_library.library_species.use_genome_build+')<br/>7: '+self.fcid.lane_7_library.__str__()+' ('+self.fcid.lane_7_library.library_species.use_genome_build+')<br/>8: '+self.fcid.lane_8_library.__str__()+' ('+self.fcid.lane_8_library.library_species.use_genome_build+')'
142     str += LanesList ## self.fcid.Lanes()
143     str += '</div>'
144     str += '<div><a title="open Flowcell record" href="/admin/exp_track/flowcell/'+self.fcid.id.__str__()+'/" target=_self>Edit Flowcell record</a>'
145     #str += '<span style="color:red;font-size:80%;margin-left:15px;margin-right:3px">New!</span>'
146     str +='<a style="margin-left:15px;" target=_balnk href="/exp_track/'+self.fcid.flowcell_id+'" title="View XLS like sheet for this Flowcell LOG ..." ">GA LOG Page</a>'
147     str += '</div>'
148     str += '</div>'    
149     return str
150   Flowcell_Info.allow_tags = True
151
152 LANE_STATUS_CODES = [(0, 'Failed'),
153                     (1, 'Marginal'),
154                     (2, 'Good'),]
155 LANE_STATUS_MAP = dict((int(k),v) for k,v in LANE_STATUS_CODES )
156 LANE_STATUS_MAP[None] = "Unknown"
157
158 class Lane(models.Model):
159   flowcell = models.ForeignKey(FlowCell)
160   lane_number = models.IntegerField(choices=[(1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8)])
161   library = models.ForeignKey(Library)
162   pM = models.DecimalField(max_digits=5, decimal_places=2,blank=False, null=False,default=default_pM)
163   cluster_estimate = models.IntegerField(blank=True, null=True)                                       
164   status = models.IntegerField(choices=LANE_STATUS_CODES, null=True, blank=True) 
165   comment = models.TextField(null=True, blank=True)
166
167   @models.permalink
168   def get_absolute_url(self):
169        return ('htsworkflow.frontend.experiments.views.flowcell_lane_detail',
170                [str(self.flowcell.flowcell_id), str(self.lane_number)])