Skip to content

Commit

Permalink
Merge pull request #101 from matthiaskoenig/develop
Browse files Browse the repository at this point in the history
PKDB-v0.2.5
  • Loading branch information
matthiaskoenig authored Aug 31, 2018
2 parents 951f1e8 + 30c0845 commit c6fc623
Show file tree
Hide file tree
Showing 49 changed files with 3,149 additions and 1,328 deletions.
1 change: 1 addition & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ services:
web:
restart: always
environment:

- PKDB_SECRET_KEY="cgasj6yjpkagcgasj6yjpkagcgasj6yjpkag"
- PKDB_DEFAULT_PASSWORD="pkdb"

Expand Down
2 changes: 1 addition & 1 deletion pkdb_app/_version.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""
Definition of version string.
"""
__version__ = "0.2.0"
__version__ = "0.2.5"
97 changes: 13 additions & 84 deletions pkdb_app/behaviours.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
"""

from django.db import models
from django.core.exceptions import ValidationError

from pkdb_app.utils import CHAR_MAX_LENGTH
from .categoricals import UNITS_CHOICES
CHAR_MAX_LENGTH_LONG = CHAR_MAX_LENGTH * 3


class Sidable(models.Model):
Expand All @@ -17,80 +17,19 @@ class Meta:
abstract = True


# FIXME: This has to be more complicated.
'''
- multiple users can comment and every comment should be tracked to user with provenance information like
timestamp (last modified)
Comment(model):
text
user
timestamp
- Annotation (annotatable), at some point, but not now
'''


class Blankable(models.Model):
# when creating the BlankAble class object it will add a __blank_together__
# attribute corresponding to the same in {YourModel}.MyMeta.blank_together
def __new__(cls, *args, **kwargs):
new = super().__new__(cls)
if hasattr(cls, 'MyMeta'):
if hasattr(cls.MyMeta, 'blank_together'):
setattr(new, '__blank_together__', cls.MyMeta.blank_together)
return new

def save(self, *args, **kwargs):
# returns False if any but not all of the __blank_together__ fields
# are not blank
not_blank_together = not (any([getattr(self, field, None) for field in getattr(self, '__not_blank_together__', None)]) and \
not all([getattr(self, field, None) for field in getattr(self, '__not_blank_together__', None)]))
if not_blank_together:
raise ValidationError(f"{getattr(self, '__not_blank_together__', None)} one of them cannot be blank.")
return super().save(*args, **kwargs)

class Meta:
# prevents Django from having some bad behavior surrounding
# inheritance of models that are not explicitly abstract
abstract = True


class Describable(models.Model):
""" Add description field. """
description = models.TextField(blank=True, null=True)

class Meta:
abstract = True


class Hashable(models.Model):
""" Add hash key field. """
hash = models.CharField(max_length=CHAR_MAX_LENGTH, blank=True, null=True)

class Meta:
abstract = True


class Sourceable(models.Model):
#source = models.ForeignKey(DataFile, on_delete=False) # todo: to file_filed
#figure = models.CharField(max_length=CHAR_MAX_LENGTH*5,null=True, blank=True) # todo: to file_filed
class Externable(models.Model):
format = models.CharField(max_length=CHAR_MAX_LENGTH, null=True, blank=True)
subset_map = models.CharField(max_length=CHAR_MAX_LENGTH_LONG, null=True, blank=True)

class Meta:
abstract = True

@staticmethod
def fields():
return ["source", "figure", "format"]


class Valueable(models.Model):
""" Valuable.
Adds fields to store values with their statistics.
"""
count = models.IntegerField(null=True, blank=True) # how many participants in characteristics
value = models.FloatField(null=True, blank=True)
mean = models.FloatField(null=True, blank=True)
median = models.FloatField(null=True, blank=True)
Expand All @@ -104,30 +43,20 @@ class Valueable(models.Model):
class Meta:
abstract = True

#@staticmethod
#def fields():
# return ["value", "mean", "median", "min", "max", "sd", "se", "cv", "unit", ]


class ValueableMap(models.Model):
""" ValuableMap. """
count_map = models.CharField(max_length=CHAR_MAX_LENGTH, null=True, blank=True) # how many participants in characteristics
value_map = models.CharField(max_length=CHAR_MAX_LENGTH, null=True, blank=True)
value_map = models.CharField(max_length=CHAR_MAX_LENGTH_LONG, null=True, blank=True)

mean_map = models.CharField(max_length=CHAR_MAX_LENGTH, null=True, blank=True)
median_map = models.CharField(max_length=CHAR_MAX_LENGTH, null=True, blank=True)
min_map = models.CharField(max_length=CHAR_MAX_LENGTH, null=True, blank=True)
max_map = models.CharField(max_length=CHAR_MAX_LENGTH, null=True, blank=True)
sd_map = models.CharField(max_length=CHAR_MAX_LENGTH, null=True, blank=True)
se_map = models.CharField(max_length=CHAR_MAX_LENGTH, null=True, blank=True)
cv_map = models.CharField(max_length=CHAR_MAX_LENGTH, null=True, blank=True)
mean_map = models.CharField(max_length=CHAR_MAX_LENGTH_LONG, null=True, blank=True)
median_map = models.CharField(max_length=CHAR_MAX_LENGTH_LONG, null=True, blank=True)
min_map = models.CharField(max_length=CHAR_MAX_LENGTH_LONG, null=True, blank=True)
max_map = models.CharField(max_length=CHAR_MAX_LENGTH_LONG, null=True, blank=True)
sd_map = models.CharField(max_length=CHAR_MAX_LENGTH_LONG, null=True, blank=True)
se_map = models.CharField(max_length=CHAR_MAX_LENGTH_LONG, null=True, blank=True)
cv_map = models.CharField(max_length=CHAR_MAX_LENGTH_LONG, null=True, blank=True)

unit_map = models.CharField(max_length=CHAR_MAX_LENGTH, null=True, blank=True)
unit_map = models.CharField(max_length=CHAR_MAX_LENGTH_LONG, null=True, blank=True)

class Meta:
abstract = True

#@staticmethod
#def fields():
# return ["value_map", "mean_map", "median_map", "min_map", "max_map","sd_map", "se_map", "cv_map", "unit_map" ]

abstract = True
42 changes: 29 additions & 13 deletions pkdb_app/categoricals.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ def create_choices(list):
UnitType("µg*h/ml"), # -> mg*h/l
UnitType("µg/ml*h"), # -> mg*h/l
UnitType("mg*min/l"), # -> mg*h/l
UnitType("µg*min/ml"),
UnitType("µmol*h/l"), # -> mg*h/l (with molar weight)
UnitType("µmol/l*h"), # -> mg*h/l (with molar weight)
UnitType("µg/ml*h/kg"), # -> mg*h/l/kg
Expand Down Expand Up @@ -198,7 +199,9 @@ def create_choices(list):
"(AAMU+1X+1U)/17U",
"17U/17X",
"1U/(1U+1X)",
"1U/1X",
"AFMU/(AFMU+1U+1X)",
"AAMU/(AAMU+1U+1X)",
# caffeine interaction
"fluvoxamine",
"naringenin",
Expand All @@ -218,6 +221,10 @@ def create_choices(list):
# codeine
"codeine",

# chlorzoxazone (CYP2E1)
"chlorzoxazone",
"6-hydroxychlorzoxazone",

# misc
"tizanidine",
"venlafaxine",
Expand Down Expand Up @@ -269,6 +276,8 @@ def create_choices(list):
"digoxin",
"clozapine",

"carbon monoxide",

]
SUBSTANCES_DATA_CHOICES = [(t, t) for t in SUBSTANCES_DATA]

Expand Down Expand Up @@ -308,7 +317,7 @@ def create_choices(list):

# -------------- Medication --------------
CharacteristicType('medication', MEDICATION, BOOLEAN_TYPE, BOOLEAN_CHOICES, ["-"]),
CharacteristicType('medication type', MEDICATION, CATEGORIAL_TYPE, ["ibuprofen", "paracetamol", "aspirin", "clozapine"], ["-"]),
CharacteristicType('medication type', MEDICATION, CATEGORIAL_TYPE, ["ibuprofen", "paracetamol", "aspirin", "clozapine", "carbon monoxide"], ["-"]),
CharacteristicType('medication amount', MEDICATION, NUMERIC_TYPE, None, ["-"]),

CharacteristicType('oral contraceptives', MEDICATION, BOOLEAN_TYPE, BOOLEAN_CHOICES, ["-"]),
Expand All @@ -318,19 +327,19 @@ def create_choices(list):
["year", "week", "day", "h"]),

# -------------- Caffeine --------------
CharacteristicType('caffeine', 'lifestyle', BOOLEAN_TYPE, BOOLEAN_CHOICES, ["-"]),
CharacteristicType('caffeine amount', 'lifestyle', NUMERIC_TYPE, None, ["mg/day"]),
CharacteristicType('caffeine amount (beverages)', 'lifestyle', NUMERIC_TYPE, None, ["1/day"]),
CharacteristicType('caffeine', LIFESTYLE, BOOLEAN_TYPE, BOOLEAN_CHOICES, ["-"]),
CharacteristicType('caffeine amount', LIFESTYLE, NUMERIC_TYPE, None, ["mg/day"]),
CharacteristicType('caffeine amount (beverages)', LIFESTYLE, NUMERIC_TYPE, None, ["1/day"]),

# -------------- Smoking --------------
CharacteristicType('smoking', 'lifestyle', BOOLEAN_TYPE, BOOLEAN_CHOICES, ["-"]),
CharacteristicType('smoking amount (cigarettes)', 'lifestyle', NUMERIC_TYPE, None, ["1/day"]),
CharacteristicType('smoking amount (packyears)', 'lifestyle', NUMERIC_TYPE, None, ["yr"]),
CharacteristicType('smoking duration (years)', 'lifestyle', NUMERIC_TYPE, None, ["yr"]),
CharacteristicType('smoking', LIFESTYLE, BOOLEAN_TYPE, BOOLEAN_CHOICES, ["-"]),
CharacteristicType('smoking amount (cigarettes)', LIFESTYLE, NUMERIC_TYPE, None, ["1/day"]),
CharacteristicType('smoking amount (packyears)', LIFESTYLE, NUMERIC_TYPE, None, ["yr"]),
CharacteristicType('smoking duration (years)', LIFESTYLE, NUMERIC_TYPE, None, ["yr"]),

# -------------- Alcohol --------------
CharacteristicType('alcohol', 'lifestyle', BOOLEAN_TYPE, BOOLEAN_CHOICES, ["-"]),
CharacteristicType('alcohol amount', 'lifestyle', NUMERIC_TYPE, None, ["-"]),
CharacteristicType('alcohol', LIFESTYLE, BOOLEAN_TYPE, BOOLEAN_CHOICES, ["-"]),
CharacteristicType('alcohol amount', LIFESTYLE, NUMERIC_TYPE, None, ["-"]),
CharacteristicType('alcohol abstinence', 'study protocol', BOOLEAN_TYPE, BOOLEAN_CHOICES, ["-"]),

# -------------- Biochemical data --------------
Expand All @@ -354,6 +363,7 @@ def create_choices(list):

"clearance",
"clearance_renal",
"clearance_unbound",
"vd", # Volume of distribution
"thalf", # half-life
"tmax", # time of maximum
Expand All @@ -363,6 +373,8 @@ def create_choices(list):
"kabs", # absorption rate
"fraction_absorbed", # "often also absolute bioavailability
"plasma_binding",

"recovery",
]

OUTPUT_TISSUE_DATA = [
Expand All @@ -377,9 +389,14 @@ def create_choices(list):
# class, value, dtype (numeric, boolean, categorial), choices
INTERVENTION_DATA = [
CharacteristicType('dosing', 'dosing', NUMERIC_TYPE, None, ["mg", "mg/kg"]),
CharacteristicType('smoking cessation', 'lifestyle', NUMERIC_TYPE, None, ["-"]),
CharacteristicType('female cycle', 'cycle', STRING_TYPE, None, ["-"]),
CharacteristicType('smoking cessation', LIFESTYLE, NUMERIC_TYPE, None, ["-"]),
CharacteristicType('oral contraceptives', MEDICATION, BOOLEAN_TYPE, BOOLEAN_CHOICES, ["-"]),
CharacteristicType('smoking', 'lifestyle', BOOLEAN_TYPE, BOOLEAN_CHOICES, ["-"]),
CharacteristicType('abstinence', 'study protocol', CATEGORIAL_TYPE, SUBSTANCES_DATA+["alcohol", "smoking", "grapefruit juice"],
["year", "week", "day", "h"]),
CharacteristicType('medication type', MEDICATION, CATEGORIAL_TYPE, ["ibuprofen", "paracetamol", "aspirin", "clozapine", "carbon monoxide"], ["-"]),
]

def dict_and_choices(data):
data_dict = {item.value: item for item in data}
data_choices = [(ctype.value, ctype.value) for ctype in data]
Expand All @@ -390,4 +407,3 @@ def dict_and_choices(data):
CHARACTERISTIC_CATEGORIES_UNDERSCORE = set([c.replace(' ', '_') for c in CHARACTERISTIC_CATEGORIES])
CHARACTERISTIC_DICT, CHARACTERISTIC_CHOICES = dict_and_choices(CHARACTERISTIC_DATA)
INTERVENTION_DICT, INTERVENTION_CHOICES = dict_and_choices(INTERVENTION_DATA)

41 changes: 21 additions & 20 deletions pkdb_app/comments/models.py
Original file line number Diff line number Diff line change
@@ -1,42 +1,43 @@
from django.db import models

# Create your models here.
from pkdb_app.interventions.models import Intervention, InterventionSet, Timecourse, OutputSet, Output
from pkdb_app.interventions.models import InterventionEx, InterventionSet, TimecourseEx, OutputSet, OutputEx
from pkdb_app.studies.models import Reference, Study
from pkdb_app.subjects.models import Individual, IndividualSet, Characteristica, GroupSet, Group
from pkdb_app.subjects.models import IndividualEx, IndividualSet, CharacteristicaEx, GroupSet, GroupEx
from pkdb_app.users.models import User



class Comment(models.Model):

text = models.TextField(blank=True, null=True)
user = models.ForeignKey(User, related_name="comments", on_delete=False)
time = models.DateTimeField(auto_created=True)
user = models.ForeignKey(User, related_name="comments", blank=True, null=True, on_delete = models.CASCADE)
date_time = models.DateTimeField(auto_now_add=True, blank=True)
####

individual = models.ForeignKey(Individual,related_name="comments",blank=True, null=True, on_delete=False)
individualset = models.ForeignKey(IndividualSet,related_name="comments",blank=True, null=True, on_delete=False)
group = models.ForeignKey(Group,related_name="comments", blank=True, null=True,on_delete=False)
groupset = models.ForeignKey(GroupSet,related_name="comments",blank=True, null=True, on_delete=False)
characteristica = models.ForeignKey(Characteristica,related_name="comments",blank=True, null=True, on_delete=False)
individual_ex = models.ForeignKey(IndividualEx, related_name="comments", blank=True, null=True, on_delete=models.CASCADE)
individualset = models.ForeignKey(IndividualSet,related_name="comments",blank=True, null=True, on_delete=models.CASCADE)
group_ex = models.ForeignKey(GroupEx,related_name="comments", blank=True, null=True,on_delete=models.CASCADE)
groupset = models.ForeignKey(GroupSet,related_name="comments",blank=True, null=True, on_delete=models.CASCADE)
characteristica_ex = models.ForeignKey(CharacteristicaEx,related_name="comments",blank=True, null=True, on_delete=models.CASCADE)


output = models.ForeignKey(Output,related_name="comments",blank=True, null=True, on_delete=False)
outputset = models.ForeignKey(OutputSet,related_name="comments",blank=True, null=True, on_delete=False)
timecourse = models.ForeignKey(Timecourse,related_name="comments", blank=True, null=True,on_delete=False)
output_ex = models.ForeignKey(OutputEx,related_name="comments",blank=True, null=True, on_delete=models.CASCADE)
outputset = models.ForeignKey(OutputSet,related_name="comments",blank=True, null=True, on_delete=models.CASCADE)
timecourse_ex = models.ForeignKey(TimecourseEx,related_name="comments", blank=True, null=True,on_delete=models.CASCADE)

intervention = models.ForeignKey(Intervention,related_name="comments",blank=True, null=True, on_delete=False)
interventionset = models.ForeignKey(InterventionSet,related_name="comments", blank=True, null=True,on_delete=False)
intervention_ex = models.ForeignKey(InterventionEx,related_name="comments",blank=True, null=True, on_delete=models.CASCADE)
interventionset = models.ForeignKey(InterventionSet,related_name="comments", blank=True, null=True,on_delete=models.CASCADE)


reference = models.ForeignKey(Reference,related_name="comments",blank=True, null=True, on_delete=False)
study = models.ForeignKey(Study, related_name="comments",blank=True, null=True,on_delete=False)
reference = models.ForeignKey(Reference,related_name="comments",blank=True, null=True, on_delete=models.CASCADE)
study = models.ForeignKey(Study, related_name="comments",blank=True, null=True,on_delete=models.CASCADE)


class Description(models.Model):
text = models.TextField(blank=True, null=True)

groupset = models.ForeignKey(GroupSet,related_name="descriptions",blank=True, null=True, on_delete=False)
interventionset = models.ForeignKey(InterventionSet,related_name="descriptions", blank=True, null=True,on_delete=False)
outputset = models.ForeignKey(OutputSet,related_name="descriptions",blank=True, null=True, on_delete=False)
individualset = models.ForeignKey(IndividualSet,related_name="descriptions",blank=True, null=True, on_delete=False)
groupset = models.ForeignKey(GroupSet,related_name="descriptions",blank=True, null=True, on_delete=models.CASCADE)
interventionset = models.ForeignKey(InterventionSet,related_name="descriptions", blank=True, null=True,on_delete=models.CASCADE)
outputset = models.ForeignKey(OutputSet,related_name="descriptions",blank=True, null=True, on_delete=models.CASCADE)
individualset = models.ForeignKey(IndividualSet,related_name="descriptions",blank=True, null=True, on_delete=models.CASCADE)
34 changes: 31 additions & 3 deletions pkdb_app/comments/serializers.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,44 @@
from rest_framework import serializers

from pkdb_app.comments.models import Description
from pkdb_app.comments.models import Description, Comment
from pkdb_app.serializers import WrongKeyValidationSerializer
from pkdb_app.users.models import User


class DescriptionsSerializer(serializers.ModelSerializer):
class DescriptionSerializer(serializers.ModelSerializer):

class Meta:
fields = ["text"]
model = Description

def to_internal_value(self, data):
return {"text": data}
return super().to_internal_value({"text": data})

def to_representation(self, instance):
return instance.text

class CommentSerializer(WrongKeyValidationSerializer):

class Meta:
fields = ["text","user"]
model = Comment

def _validate_comment(self, data):
if not (isinstance(data, list) and len(data) == 2):
raise serializers.ValidationError({"comments": "comment must be a list of the form ['username', 'comment']", "detail":{data}})

def to_internal_value(self, data):
self._validate_comment(data)
user = self.get_or_val_error(User, username=data[0])
return {"text": data[1],"user":user}

def to_representation(self, instance):
return [instance.user.username,instance.text]

###############################################################################################
# Read Serializer
###############################################################################################
class DescriptionReadSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
fields = ["pk","text"]
model = Description
16 changes: 15 additions & 1 deletion pkdb_app/comments/views.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
from django.shortcuts import render

# Create your views here.
from rest_framework import viewsets, filters
from rest_framework.permissions import AllowAny

from pkdb_app.comments.models import Description
from pkdb_app.comments.serializers import DescriptionReadSerializer


class DescriptionReadViewSet(viewsets.ModelViewSet):

queryset = Description.objects.all()
serializer_class = DescriptionReadSerializer
filter_backends = (filters.SearchFilter,)
filter_fields = ('text',)
search_fields = filter_fields
permission_classes = (AllowAny,)
Loading

0 comments on commit c6fc623

Please sign in to comment.