Added a 'Print Labels' action to the Library Admin Page.
[htsworkflow.git] / htsworkflow / frontend / samples / models.py
1 import urlparse
2 from django.db import models
3 from django.contrib.auth.models import User, UserManager
4 from django.db.models.signals import pre_save, post_save
5 from django.db import connection
6 from htsworkflow.frontend import settings
7 from htsworkflow.frontend.reports.libinfopar import *
8
9 # Create your models here.
10
11 class Antibody(models.Model):
12     antigene = models.CharField(max_length=500, db_index=True)
13     # New field Aug/20/08
14     # SQL to add column: 
15     # alter table fctracker_antibody add column "nickname" varchar(20) NULL;
16     nickname = models.CharField(
17         max_length=20,
18         blank=True,
19         null=True, 
20         db_index=True,
21         verbose_name = 'Short Name'
22     )
23     catalog = models.CharField(max_length=50, unique=True, db_index=True)
24     antibodies = models.CharField(max_length=500, db_index=True)
25     source = models.CharField(max_length=500, blank=True, db_index=True)
26     biology = models.TextField(blank=True)
27     notes = models.TextField(blank=True)
28     def __unicode__(self):
29         return u'%s - %s (%s)' % (self.antigene, self.antibodies, self.catalog)
30     class Meta:
31         verbose_name_plural = "antibodies"
32         ordering = ["antigene"]
33
34 class Cellline(models.Model):
35     cellline_name = models.CharField(max_length=100, unique=True, db_index=True)
36     nickname = models.CharField(max_length=20,
37         blank=True,
38         null=True, 
39         db_index=True,
40         verbose_name = 'Short Name')
41     notes = models.TextField(blank=True)
42     def __unicode__(self):
43         return unicode(self.cellline_name)
44
45     class Meta:
46         ordering = ["cellline_name"]
47
48 class Condition(models.Model):
49     condition_name = models.CharField(
50         max_length=2000, unique=True, db_index=True)
51     nickname = models.CharField(max_length=20,
52         blank=True,
53         null=True, 
54         db_index=True,
55         verbose_name = 'Short Name')
56     notes = models.TextField(blank=True)
57
58     def __unicode__(self):
59         return unicode(self.condition_name)
60
61     class Meta:
62         ordering = ["condition_name"]
63
64 class ExperimentType(models.Model):
65   name = models.CharField(max_length=50, unique=True)
66
67   def __unicode__(self):
68     return unicode(self.name)
69
70 class Tag(models.Model): 
71   tag_name = models.CharField(max_length=100, db_index=True,blank=False,null=False) 
72   TAG_CONTEXT = ( 
73       #('Antibody','Antibody'), 
74       #('Cellline', 'Cellline'), 
75       #('Condition', 'Condition'), 
76       ('Library', 'Library'), 
77       ('ANY','ANY'), 
78   ) 
79   context = models.CharField(max_length=50, 
80       choices=TAG_CONTEXT, default='Library') 
81  
82   def __unicode__(self): 
83     return u'%s' % (self.tag_name) 
84  
85   class Meta: 
86     ordering = ["context","tag_name"] 
87  
88 class Species(models.Model):
89   scientific_name = models.CharField(max_length=256, 
90       unique=False, 
91       db_index=True
92   )
93   common_name = models.CharField(max_length=256, blank=True)
94   #use_genome_build = models.CharField(max_length=100, blank=False, null=False)
95
96   def __unicode__(self):
97     return u'%s (%s)' % (self.scientific_name, self.common_name)
98   
99   class Meta:
100     verbose_name_plural = "species"
101     ordering = ["scientific_name"]
102   
103 class Affiliation(models.Model):
104   name = models.CharField(max_length=256, db_index=True, verbose_name='Name')
105   contact = models.CharField(max_length=256, null=True, blank=True,verbose_name='Lab Name')  
106   email = models.EmailField(null=True,blank=True)
107   users = models.ManyToManyField('HTSUser', null=True, blank=True)
108   users.admin_order_field = "username"
109   
110   def __unicode__(self):
111     str = unicode(self.name)
112     if self.contact is not None and len(self.contact) > 0:
113       str += u' ('+self.contact+u')' 
114     return str
115
116   def Users(self):
117       users = self.users.all().order_by('username')
118       return ", ".join([unicode(a) for a in users ])
119
120   class Meta:
121     ordering = ["name","contact"]
122     unique_together = (("name", "contact"),)
123
124 class LibraryType(models.Model):
125   name = models.CharField(max_length=255, unique=True)
126
127   def __unicode__(self):
128     return unicode(self.name)
129
130
131 class Library(models.Model):
132   id = models.CharField(max_length=10, primary_key=True)
133   library_name = models.CharField(max_length=100, unique=True)
134   library_species = models.ForeignKey(Species)
135   # new field 2008 Mar 5, alter table samples_library add column "hidden" NOT NULL default 0;
136   hidden = models.BooleanField()
137   # new field 2009 Oct 6, alter table samples_library add column "account_number" varchar(100) NULL
138   account_number = models.CharField(max_length=100, null=True, blank=True)
139   cell_line = models.ForeignKey(Cellline, blank=True, null=True, verbose_name="Background")
140   condition = models.ForeignKey(Condition, blank=True, null=True)
141   antibody = models.ForeignKey(Antibody,blank=True,null=True)
142   # New field Aug/25/08. SQL: alter table fctracker_library add column "lib_affiliation" varchar(256)  NULL;
143   affiliations = models.ManyToManyField(Affiliation,related_name='library_affiliations',null=True)
144   # new field Nov/14/08
145   tags = models.ManyToManyField(Tag,related_name='library_tags',blank=True,null=True)
146   # New field Aug/19/08
147   # SQL to add column: alter table fctracker_library add column "replicate" smallint unsigned NULL;
148   REPLICATE_NUM = ((1,1),(2,2),(3,3),(4,4))
149   replicate =  models.PositiveSmallIntegerField(choices=REPLICATE_NUM,default=1) 
150   experiment_type = models.ForeignKey(ExperimentType)
151   library_type = models.ForeignKey(LibraryType, blank=True, null=True)
152   creation_date = models.DateField(blank=True, null=True)
153   made_for = models.CharField(max_length=50, blank=True, 
154       verbose_name='ChIP/DNA/RNA Made By')
155   made_by = models.CharField(max_length=50, blank=True, default="Lorian")
156   
157   PROTOCOL_END_POINTS = (
158       ('?', 'Unknown'),
159       ('Sample', 'Raw sample'),
160       ('Progress', 'In progress'),
161       ('1A', 'Ligation, then gel'),
162       ('PCR', 'Ligation, then PCR'),
163       ('1Ab', 'Ligation, PCR, then gel'),
164       ('1Aa', 'Ligation, gel, then PCR'),
165       ('2A', 'Ligation, PCR, gel, PCR'),
166       ('Done', 'Completed'),
167     )
168   stopping_point = models.CharField(max_length=25, choices=PROTOCOL_END_POINTS, default='Done')
169   amplified_from_sample = models.ForeignKey('self', blank=True, null=True, related_name='amplified_into_sample')  
170   
171   undiluted_concentration = models.DecimalField("Concentration", 
172       max_digits=5, decimal_places=2, blank=True, null=True,
173       help_text=u"Undiluted concentration (ng/\u00b5l)") 
174       # note \u00b5 is the micro symbol in unicode
175   successful_pM = models.DecimalField(max_digits=9, decimal_places=1, blank=True, null=True)
176   ten_nM_dilution = models.BooleanField()
177   avg_lib_size = models.IntegerField(default=225, blank=True, null=True)
178   notes = models.TextField(blank=True)
179   
180   def __unicode__(self):
181     return u'#%s: %s' % (self.id, self.library_name)
182   
183   class Meta:
184     verbose_name_plural = "libraries"
185     #ordering = ["-creation_date"] 
186     ordering = ["-id"]
187   
188   def antibody_name(self):
189     str ='<a target=_self href="/admin/samples/antibody/'+self.antibody.id.__str__()+'/" title="'+self.antibody.__str__()+'">'+self.antibody.nickname+'</a>' 
190     return str
191   antibody_name.allow_tags = True
192
193   def organism(self):
194     return self.library_species.common_name
195
196   def affiliation(self):
197     affs = self.affiliations.all().order_by('name')
198     tstr = ''
199     ar = []
200     for t in affs:
201         ar.append(t.__unicode__())
202     return '%s' % (", ".join(ar))
203     
204   def is_archived(self):
205     """
206     returns True if archived else False
207     """
208     if self.longtermstorage_set.count() > 0:
209         return True
210     else:
211         return False
212
213   def libtags(self):
214     affs = self.tags.all().order_by('tag_name')
215     ar = []
216     for t in affs:
217       ar.append(t.__unicode__())
218     return u'%s' % ( ", ".join(ar))
219
220   def DataRun(self):
221     str ='<a target=_self href="/admin/experiments/datarun/?q='+self.id+'" title="Check All Data Runs for This Specific Library ..." ">Data Run</a>' 
222     return str
223   DataRun.allow_tags = True
224
225   def aligned_m_reads(self):
226     return getLibReads(self.id)
227
228   def aligned_reads(self):
229     res = getLibReads(self.id)
230
231     # Check data sanity
232     if res[2] != "OK":
233       return u'<div style="border:solid red 2px">'+res[2]+'</div>'
234
235     rc = "%1.2f" % (res[1]/1000000.0)
236     # Color Scheme: green is more than 10M, blue is more than 5M, orange is more than 3M and red is less. For RNAseq, all those thresholds should be doubled
237     if res[0] > 0:
238       bgcolor = '#ff3300'  # Red
239       rc_thr = [10000000,5000000,3000000]
240       if self.experiment_type == 'RNA-seq':
241         rc_thr = [20000000,10000000,6000000]
242
243       if res[1] > rc_thr[0]:
244         bgcolor = '#66ff66'  # Green
245       else:
246         if res[1] > rc_thr[1]:
247           bgcolor ='#00ccff'  # Blue
248         else:
249            if res[1] > rc_thr[2]: 
250              bgcolor ='#ffcc33'  # Orange
251       tstr = '<div style="background-color:'+bgcolor+';color:black">'
252       tstr += res[0].__unicode__()+' Lanes, '+rc+' M Reads'
253       tstr += '</div>'
254     else: tstr = 'not processed yet' 
255     return tstr
256   aligned_reads.allow_tags = True
257   
258   def public(self):
259     SITE_ROOT = '/'
260     summary_url = self.get_absolute_url()
261     return '<a href="%s">S</a>' % (summary_url,)
262   public.allow_tags = True
263     
264   @models.permalink
265   def get_absolute_url(self):
266     return ('htsworkflow.frontend.samples.views.library_to_flowcells', [str(self.id)])
267     
268   
269     
270
271
272 class HTSUser(User):
273     """
274     Provide some site-specific customization for the django user class
275     """
276     #objects = UserManager()
277
278     class Meta:
279         ordering = ['first_name', 'last_name', 'username']
280
281     def admin_url(self):
282         return '/admin/%s/%s/%d' % (self._meta.app_label, self._meta.module_name, self.id)
283
284     def __unicode__(self):
285         #return unicode(self.username) + u" (" + unicode(self.get_full_name()) + u")"
286         return unicode(self.get_full_name()) + u' (' + unicode(self.username) + ')'
287     
288 def HTSUserInsertID(sender, instance, **kwargs):
289     """
290     Force addition of HTSUsers when someone just modifies the auth_user object
291     """
292     u = HTSUser.objects.filter(pk=instance.id)
293     if len(u) == 0:
294         cursor = connection.cursor()
295         cursor.execute('INSERT INTO samples_htsuser (user_ptr_id) VALUES (%s);' % (instance.id,))
296         cursor.close()
297     
298 post_save.connect(HTSUserInsertID, sender=User)