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