|
| 1 | +'''Module that defines classes to describe experiments, reseachers and |
| 2 | + samples. Experiments can have multple researchers associated to them, |
| 3 | + and vice versa. Samples are assigned to experiments, but a sample can |
| 4 | + be used in a single experiment only. Object Relational Mapping is |
| 5 | + provided via SQLAlchemy.''' |
| 6 | + |
| 7 | +from sqlalchemy import (Column, ForeignKey, UniqueConstraint, |
| 8 | + Integer, String, DateTime, Table) |
| 9 | +from sqlalchemy.ext.declarative import declarative_base |
| 10 | +from sqlalchemy.orm import relationship, backref |
| 11 | + |
| 12 | +# Base class for all classes associated with tables in the database |
| 13 | +Base = declarative_base() |
| 14 | + |
| 15 | +# Table to hold the experiments-researchers many-to-many association |
| 16 | +staff_assignments = Table( |
| 17 | + 'staff_assignments', Base.metadata, Column( |
| 18 | + 'experiment_id', |
| 19 | + Integer, |
| 20 | + ForeignKey('experiments.experiment_id') |
| 21 | + ), |
| 22 | + Column( |
| 23 | + 'researcher_id', |
| 24 | + Integer, |
| 25 | + ForeignKey('researchers.researcher_id') |
| 26 | + ), |
| 27 | + UniqueConstraint('experiment_id', 'researcher_id') |
| 28 | +) |
| 29 | + |
| 30 | + |
| 31 | +class Experiment(Base): |
| 32 | + '''An experiment have a description, a start date, and when finished, |
| 33 | + an end date''' |
| 34 | + __tablename__ = 'experiments' |
| 35 | + experiment_id = Column(Integer, primary_key=True) |
| 36 | + start_date = Column(DateTime, nullable=False) |
| 37 | + end_date = Column(DateTime) |
| 38 | + description = Column(String(2048), nullable=False) |
| 39 | + researchers = relationship('Researcher', secondary=staff_assignments, |
| 40 | + backref='experiments') |
| 41 | + |
| 42 | + def __str__(self): |
| 43 | + '''string representation of an experiment''' |
| 44 | + fmt_str = 'id {id:d}: {desc:s},\n\tstarted on {start}' |
| 45 | + str_repr = fmt_str.format(id=self.experiment_id, |
| 46 | + desc=self.description, |
| 47 | + start=self.start_date) |
| 48 | + if self.end_date: |
| 49 | + str_repr = '{base:s}, ended on {end}'.format(base=str_repr, |
| 50 | + end=self.end_date) |
| 51 | + return str_repr |
| 52 | + |
| 53 | + |
| 54 | +class Researcher(Base): |
| 55 | + '''A researcher has a first name, a last name, and optionally, a |
| 56 | + u-number, and description''' |
| 57 | + __tablename__ = 'researchers' |
| 58 | + researcher_id = Column(Integer, primary_key=True) |
| 59 | + u_number = Column(String(20)) |
| 60 | + first_name = Column(String(20), nullable=False) |
| 61 | + last_name = Column(String(20), nullable=False) |
| 62 | + description = Column(String(20)) |
| 63 | + |
| 64 | + def __str__(self): |
| 65 | + '''string representation of a researcher''' |
| 66 | + fmt_str = 'id {id:d}: {last:s}, {first:s}' |
| 67 | + str_repr = fmt_str.format(id=self.researcher_id, |
| 68 | + last=self.last_name, |
| 69 | + first=self.first_name) |
| 70 | + if self.u_number: |
| 71 | + str_repr = '{base} ({u_nr})'.format(base=str_repr, |
| 72 | + u_nr=self.u_number) |
| 73 | + if self.description: |
| 74 | + str_repr = '{base}: {descr}'.format(base=str_repr, |
| 75 | + descr=self.description) |
| 76 | + |
| 77 | + return str_repr |
| 78 | + |
| 79 | + |
| 80 | +class Sample(Base): |
| 81 | + '''A sample is associated to an experiment through the latter's ID, |
| 82 | + and it has a description''' |
| 83 | + __tablename__ = 'samples' |
| 84 | + sample_id = Column(Integer, primary_key=True) |
| 85 | + experiment_id = Column(Integer, ForeignKey('experiments.experiment_id')) |
| 86 | + description = Column(String, nullable=False) |
| 87 | + experiment = relationship('Experiment', backref=backref('samples')) |
| 88 | + |
| 89 | + def __str__(self): |
| 90 | + '''string representation of a sample''' |
| 91 | + fmt_str = 'id {id:d}: {descr}' |
| 92 | + str_repr = fmt_str.format(id=self.sample_id, descr=self.description) |
| 93 | + if self.experiment_id: |
| 94 | + str_repr = '{base} used in {e_id:d}'.format(base=str_repr, |
| 95 | + e_id=self.experiment_id) |
| 96 | + return str_repr |
0 commit comments