0a65651abb02a54c4bb397ec93a12a058d73d20f
[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   gel_cut_size = models.IntegerField(default=225, blank=True, null=True)
178   insert_size = models.IntegerField(blank=True, null=True)
179   notes = models.TextField(blank=True)
180
181   bioanalyzer_summary = models.TextField(blank=True,default="")
182   bioanalyzer_concentration = models.DecimalField(max_digits=5, 
183                                 decimal_places=2, blank=True, null=True,
184                                 help_text=u"(ng/\u00b5l)")
185   bioanalyzer_image_url = models.URLField(blank=True,default="")
186   
187   def __unicode__(self):
188     return u'#%s: %s' % (self.id, self.library_name)
189   
190   class Meta:
191     verbose_name_plural = "libraries"
192     #ordering = ["-creation_date"] 
193     ordering = ["-id"]
194   
195   def antibody_name(self):
196     str ='<a target=_self href="/admin/samples/antibody/'+self.antibody.id.__str__()+'/" title="'+self.antibody.__str__()+'">'+self.antibody.nickname+'</a>' 
197     return str
198   antibody_name.allow_tags = True
199
200   def organism(self):
201     return self.library_species.common_name
202
203   def affiliation(self):
204     affs = self.affiliations.all().order_by('name')
205     tstr = ''
206     ar = []
207     for t in affs:
208         ar.append(t.__unicode__())
209     return '%s' % (", ".join(ar))
210     
211   def is_archived(self):
212     """
213     returns True if archived else False
214     """
215     if self.longtermstorage_set.count() > 0:
216         return True
217     else:
218         return False
219
220   def libtags(self):
221     affs = self.tags.all().order_by('tag_name')
222     ar = []
223     for t in affs:
224       ar.append(t.__unicode__())
225     return u'%s' % ( ", ".join(ar))
226
227   def DataRun(self):
228     str ='<a target=_self href="/admin/experiments/datarun/?q='+self.id+'" title="Check All Data Runs for This Specific Library ..." ">Data Run</a>' 
229     return str
230   DataRun.allow_tags = True
231
232   def aligned_m_reads(self):
233     return getLibReads(self.id)
234
235   def aligned_reads(self):
236     res = getLibReads(self.id)
237
238     # Check data sanity
239     if res[2] != "OK":
240       return u'<div style="border:solid red 2px">'+res[2]+'</div>'
241
242     rc = "%1.2f" % (res[1]/1000000.0)
243     # 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
244     if res[0] > 0:
245       bgcolor = '#ff3300'  # Red
246       rc_thr = [10000000,5000000,3000000]
247       if self.experiment_type == 'RNA-seq':
248         rc_thr = [20000000,10000000,6000000]
249
250       if res[1] > rc_thr[0]:
251         bgcolor = '#66ff66'  # Green
252       else:
253         if res[1] > rc_thr[1]:
254           bgcolor ='#00ccff'  # Blue
255         else:
256            if res[1] > rc_thr[2]: 
257              bgcolor ='#ffcc33'  # Orange
258       tstr = '<div style="background-color:'+bgcolor+';color:black">'
259       tstr += res[0].__unicode__()+' Lanes, '+rc+' M Reads'
260       tstr += '</div>'
261     else: tstr = 'not processed yet' 
262     return tstr
263   aligned_reads.allow_tags = True
264   
265   def public(self):
266     SITE_ROOT = '/'
267     summary_url = self.get_absolute_url()
268     return '<a href="%s">S</a>' % (summary_url,)
269   public.allow_tags = True
270     
271   @models.permalink
272   def get_absolute_url(self):
273     return ('htsworkflow.frontend.samples.views.library_to_flowcells', [str(self.id)])
274     
275   
276     
277
278
279 class HTSUser(User):
280     """
281     Provide some site-specific customization for the django user class
282     """
283     #objects = UserManager()
284
285     class Meta:
286         ordering = ['first_name', 'last_name', 'username']
287
288     def admin_url(self):
289         return '/admin/%s/%s/%d' % (self._meta.app_label, self._meta.module_name, self.id)
290
291     def __unicode__(self):
292         #return unicode(self.username) + u" (" + unicode(self.get_full_name()) + u")"
293         return unicode(self.get_full_name()) + u' (' + unicode(self.username) + ')'
294     
295 def HTSUserInsertID(sender, instance, **kwargs):
296     """
297     Force addition of HTSUsers when someone just modifies the auth_user object
298     """
299     u = HTSUser.objects.filter(pk=instance.id)
300     if len(u) == 0:
301         cursor = connection.cursor()
302         cursor.execute('INSERT INTO samples_htsuser (user_ptr_id) VALUES (%s);' % (instance.id,))
303         cursor.close()
304     
305 post_save.connect(HTSUserInsertID, sender=User)