3 from django.db import models as _models
4 from django.forms import ValidationError as _ValidationError
6 from . import LOG as LOG
7 from . import util as _util
10 class NamedItem (_models.Model):
11 name = _models.CharField(max_length=100)
12 abbrev = _models.CharField('abbreviation', max_length=20)
18 def __unicode__(self):
19 return u'{0.abbrev}'.format(self)
22 class NFPASpecial (NamedItem):
23 """An NFPA Special rating (e.g. 'OX', '-W-', 'SA', ...).
25 symbol = _models.CharField(max_length=3, blank=True, null=True)
27 def __unicode__(self):
29 return u'{0.symbol}'.format(self)
30 return super(NFPASpecial, self).__unicode__()
33 class CASNumber (NamedItem):
34 "Chemical Abstracts Service registery number"
35 cas = _models.CharField(
36 'CAS#', max_length=20, unique=True)
39 if not _util.valid_CASno(self.cas):
40 raise _ValidationError("invalid CAS number '{}'".format(self.cas))
43 class Chemical (NamedItem):
44 """A chemical (in the abstract, not an instance of the chemical)
46 Separating ``Chemical``\s from ``ChemicalInstance``\s avoids
47 duplicate information (e.g. you can have two bottles of acetic
50 cas = _models.ManyToManyField(
51 CASNumber, blank=True, null=True, related_name='chemicals')
52 msds = _models.FileField(
53 'Material safety data sheet', upload_to=_util.chemical_upload_to,
54 blank=True, null=True)
55 health = _models.PositiveIntegerField(
56 'NFPA health rating', blank=True, null=True)
57 fire = _models.PositiveIntegerField(
58 'NFPA fire rating', blank=True, null=True)
59 reactivity = _models.PositiveIntegerField(
60 'NFPA reactivity rating', blank=True, null=True)
61 special = _models.ManyToManyField(
62 NFPASpecial, blank=True, null=True, related_name='chemicals')
63 mutagen = _models.NullBooleanField()
64 carcinogen = _models.NullBooleanField()
65 teratogen = _models.NullBooleanField()
66 note = _models.TextField('notes', blank=True, null=True)
68 def cas_numbers(self):
69 if self.cas.count() == 0:
71 return ', '.join(cas.cas for cas in self.cas.all())
74 return ' '.join(str(special) for special in self.special.all())
77 class Location (NamedItem):
78 "A chemical storage location (e.g. 'acidic liquids')"
82 class Vendor (NamedItem):
84 url = _models.URLField('URL', blank=True, null=True)
85 note = _models.TextField('notes', blank=True, null=True)
88 class ChemicalInstance (_models.Model):
89 """An instance of a ``Chemical``
91 For example, 1L of acetic acid from Vendor X.
93 chemical = _models.ForeignKey(Chemical, related_name='chemical_instances')
94 location = _models.ForeignKey(Location, related_name='chemical_instances')
95 amount = _models.CharField(max_length=100)
96 vendor = _models.ForeignKey(Vendor, related_name='chemical_instances')
97 catalog = _models.CharField('vendor catalog number', max_length=100)
98 received = _models.DateField(auto_now_add=True, editable=True)
99 disposed = _models.DateField(blank=True, null=True)
102 ordering = ['chemical', 'received', 'disposed', 'id']