Define the unicode() function for HTSUser to also report the users full name.
[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 class Library(models.Model):
131   id = models.CharField(max_length=10, primary_key=True)
132   library_name = models.CharField(max_length=100, unique=True)
133   library_species = models.ForeignKey(Species)
134   # new field 2008 Mar 5, alter table samples_library add column "hidden" NOT NULL default 0;
135   hidden = models.BooleanField()
136   # new field 2009 Oct 6, alter table samples_library add column "account_number" varchar(100) NULL
137   account_number = models.CharField(max_length=100, null=True, blank=True)
138   cell_line = models.ForeignKey(Cellline, blank=True, null=True, verbose_name="Background")
139   condition = models.ForeignKey(Condition, blank=True, null=True)
140   antibody = models.ForeignKey(Antibody,blank=True,null=True)
141   # New field Aug/25/08. SQL: alter table fctracker_library add column "lib_affiliation" varchar(256)  NULL;
142   affiliations = models.ManyToManyField(Affiliation,related_name='library_affiliations',null=True)
143   # new field Nov/14/08
144   tags = models.ManyToManyField(Tag,related_name='library_tags',blank=True,null=True)
145   # New field Aug/19/08
146   # SQL to add column: alter table fctracker_library add column "replicate" smallint unsigned NULL;
147   REPLICATE_NUM = ((1,1),(2,2),(3,3),(4,4))
148   replicate =  models.PositiveSmallIntegerField(choices=REPLICATE_NUM,default=1) 
149   experiment_type = models.ForeignKey(ExperimentType)
150   library_type = models.ForeignKey(LibraryType, blank=True, null=True)
151   creation_date = models.DateField(blank=True, null=True)
152   made_for = models.CharField(max_length=50, blank=True, 
153       verbose_name='ChIP/DNA/RNA Made By')
154   made_by = models.CharField(max_length=50, blank=True, default="Lorian")
155   
156   PROTOCOL_END_POINTS = (
157       ('?', 'Unknown'),
158       ('Sample', 'Raw sample'),
159       ('Progress', 'In progress'),
160       ('1A', 'Ligation, then gel'),
161       ('PCR', 'Ligation, then PCR'),
162       ('1Ab', 'Ligation, PCR, then gel'),
163       ('1Aa', 'Ligation, gel, then PCR'),
164       ('2A', 'Ligation, PCR, gel, PCR'),
165       ('Done', 'Completed'),
166     )
167   stopping_point = models.CharField(max_length=25, choices=PROTOCOL_END_POINTS, default='Done')
168   amplified_from_sample = models.ForeignKey('self', blank=True, null=True, related_name='amplified_into_sample')  
169   
170   undiluted_concentration = models.DecimalField("Concentration", 
171       max_digits=5, decimal_places=2, blank=True, null=True,
172       help_text=u"Undiluted concentration (ng/\u00b5l)") 
173       # note \u00b5 is the micro symbol in unicode
174   successful_pM = models.DecimalField(max_digits=9, decimal_places=1, blank=True, null=True)
175   ten_nM_dilution = models.BooleanField()
176   avg_lib_size = models.IntegerField(default=225, blank=True, null=True)
177   notes = models.TextField(blank=True)
178   
179   def __unicode__(self):
180     return u'#%s: %s' % (self.id, self.library_name)
181   
182   class Meta:
183     verbose_name_plural = "libraries"
184     #ordering = ["-creation_date"] 
185     ordering = ["-id"]
186   
187   def antibody_name(self):
188     str ='<a target=_self href="/admin/samples/antibody/'+self.antibody.id.__str__()+'/" title="'+self.antibody.__str__()+'">'+self.antibody.nickname+'</a>' 
189     return str
190   antibody_name.allow_tags = True
191
192   def organism(self):
193     return self.library_species.common_name
194
195   def affiliation(self):
196     affs = self.affiliations.all().order_by('name')
197     tstr = ''
198     ar = []
199     for t in affs:
200         ar.append(t.__unicode__())
201     return '%s' % (", ".join(ar))
202     
203   def is_archived(self):
204     """
205     returns True if archived else False
206     """
207     if self.longtermstorage_set.count() > 0:
208         return True
209     else:
210         return False
211
212   def libtags(self):
213     affs = self.tags.all().order_by('tag_name')
214     ar = []
215     for t in affs:
216       ar.append(t.__unicode__())
217     return u'%s' % ( ", ".join(ar))
218
219   def DataRun(self):
220     str ='<a target=_self href="/admin/experiments/datarun/?q='+self.id+'" title="Check All Data Runs for This Specific Library ..." ">Data Run</a>' 
221     return str
222   DataRun.allow_tags = True
223
224   def aligned_m_reads(self):
225     return getLibReads(self.id)
226
227   def aligned_reads(self):
228     res = getLibReads(self.id)
229
230     # Check data sanity
231     if res[2] != "OK":
232       return u'<div style="border:solid red 2px">'+res[2]+'</div>'
233
234     rc = "%1.2f" % (res[1]/1000000.0)
235     # 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
236     if res[0] > 0:
237       bgcolor = '#ff3300'  # Red
238       rc_thr = [10000000,5000000,3000000]
239       if self.experiment_type == 'RNA-seq':
240         rc_thr = [20000000,10000000,6000000]
241
242       if res[1] > rc_thr[0]:
243         bgcolor = '#66ff66'  # Green
244       else:
245         if res[1] > rc_thr[1]:
246           bgcolor ='#00ccff'  # Blue
247         else:
248            if res[1] > rc_thr[2]: 
249              bgcolor ='#ffcc33'  # Orange
250       tstr = '<div style="background-color:'+bgcolor+';color:black">'
251       tstr += res[0].__unicode__()+' Lanes, '+rc+' M Reads'
252       tstr += '</div>'
253     else: tstr = 'not processed yet' 
254     return tstr
255   aligned_reads.allow_tags = True
256
257   def public(self):
258     SITE_ROOT = '/'
259     summary_url = self.get_absolute_url()
260     return '<a href="%s">S</a>' % (summary_url,)
261   public.allow_tags = True
262
263   @models.permalink
264   def get_absolute_url(self):
265     return ('htsworkflow.frontend.samples.views.library_to_flowcells', [str(self.id)])
266
267 class HTSUser(User):
268     """
269     Provide some site-specific customization for the django user class
270     """
271     #objects = UserManager()
272
273     class Meta:
274         ordering = ['username']
275
276     def admin_url(self):
277         return '/admin/%s/%s/%d' % (self._meta.app_label, self._meta.module_name, self.id)
278
279     def __unicode__(self):
280         return unicode(self.username) + u" (" + unicode(self.get_full_name()) + u")"
281     
282 def HTSUserInsertID(sender, instance, **kwargs):
283     """
284     Force addition of HTSUsers when someone just modifies the auth_user object
285     """
286     u = HTSUser.objects.filter(pk=instance.id)
287     if len(u) == 0:
288         cursor = connection.cursor()
289         cursor.execute('INSERT INTO samples_htsuser (user_ptr_id) VALUES (%s);' % (instance.id,))
290         cursor.close()
291     
292 post_save.connect(HTSUserInsertID, sender=User)