ENH: Sex fields as lookups (#55)

This commit is contained in:
Matthew Ryan Dillon 2018-03-03 12:10:17 -07:00 committed by GitHub
parent 4cd133f993
commit c52d4e736d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 182 additions and 9 deletions

View file

@ -35,6 +35,7 @@ router.register(r'sites', locations_viewsets.SiteViewSet)
router.register(r'study-locations', locations_viewsets.StudyLocationViewSet)
# Species
router.register(r'species', species_viewsets.SpeciesViewSet)
router.register(r'sexes', species_viewsets.SexViewSet)
router.register(r'collection-species',
species_viewsets.CollectionSpeciesViewSet)

View file

@ -1,6 +1,6 @@
from django.contrib import admin
from .models import Species, TrapSpecies, CollectionSpecies
from .models import Species, Sex, TrapSpecies, CollectionSpecies
class SpeciesAdmin(admin.ModelAdmin):
@ -12,6 +12,14 @@ class SpeciesAdmin(admin.ModelAdmin):
fields = ('common_name', 'genus', 'species', 'parasite', 'sort_order')
class SexAdmin(admin.ModelAdmin):
list_display = ('name', 'sort_order')
list_display_links = ('name',)
search_fields = ('name',)
list_per_page = 25
fields = ('name', 'sort_order')
class TrapSpeciesAdmin(admin.ModelAdmin):
list_display = ('collection_trap', 'species', 'sex', 'count',
'count_estimated')
@ -32,5 +40,6 @@ class CollectionSpeciesAdmin(admin.ModelAdmin):
admin.site.register(Species, SpeciesAdmin)
admin.site.register(Sex, SexAdmin)
admin.site.register(TrapSpecies, TrapSpeciesAdmin)
admin.site.register(CollectionSpecies, CollectionSpeciesAdmin)

View file

@ -0,0 +1,39 @@
from django.db import migrations, models
from django.forms import modelform_factory
class Migration(migrations.Migration):
def migrate(apps, schema_editor):
Sex = apps.get_model('species', 'Sex')
SexForm = modelform_factory(Sex, fields=('name', 'sort_order'))
for i, s in enumerate(['male', 'female', 'mixed', 'unknown']):
form = SexForm(dict(name=s, sort_order=i))
if form.is_valid():
form.save()
else:
print('sex', form.errors.as_data())
def rollback(apps, schema_editor):
Sex = apps.get_model('species', 'Sex')
Sex.objects.all().delete()
dependencies = [
('species', '0003_DATA_reset_sequences'),
]
operations = [
migrations.CreateModel(
name='Sex',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True,
serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=25, unique=True)),
('sort_order', models.IntegerField(blank=True, null=True)),
],
options={
'verbose_name_plural': 'sex',
'ordering': ['sort_order'],
},
),
migrations.RunPython(migrate, rollback),
]

View file

@ -0,0 +1,68 @@
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
def migrate(apps, schema_editor):
Sex = apps.get_model('species', 'Sex')
CollectionSpecies = apps.get_model('species', 'CollectionSpecies')
for cs in CollectionSpecies.objects.all():
if cs.old_sex:
if cs.old_sex == 'both':
s = 'mixed'
elif cs.old_sex not in ['male', 'female', 'mixed', 'unknown']:
s = 'unknown'
else:
s = cs.old_sex
cs.sex = Sex.objects.get(name=s)
cs.save()
def rollback(apps, schema_editor):
CollectionSpecies = apps.get_model('species', 'CollectionSpecies')
for cs in CollectionSpecies.objects.all():
if cs.sex:
cs.sex = None
cs.old_sex = ''
cs.save()
dependencies = [
('species', '0004_sex'),
]
operations = [
migrations.RenameField(
model_name='collectionspecies',
old_name='sex',
new_name='old_sex',
),
migrations.RenameField(
model_name='trapspecies',
old_name='sex',
new_name='old_sex',
),
migrations.AddField(
model_name='collectionspecies',
name='sex',
field=models.ForeignKey(
null=True, on_delete=django.db.models.deletion.CASCADE,
related_name='collection_species', to='species.Sex'),
),
migrations.AddField(
model_name='trapspecies',
name='sex',
field=models.ForeignKey(
null=True, on_delete=django.db.models.deletion.CASCADE,
related_name='trap_species', to='species.Sex'),
),
migrations.RunPython(migrate, rollback),
migrations.RemoveField(
model_name='collectionspecies',
name='old_sex',
),
migrations.RemoveField(
model_name='trapspecies',
name='old_sex',
),
]

View file

@ -17,13 +17,26 @@ class Species(models.Model):
verbose_name_plural = 'species'
class Sex(models.Model):
name = models.CharField(max_length=25, unique=True)
sort_order = models.IntegerField(blank=True, null=True)
def __str__(self):
return self.name
class Meta:
ordering = ['sort_order']
verbose_name_plural = 'sex'
class TrapSpecies(models.Model):
collection_trap = models.ForeignKey('collections_ccdb.CollectionTrap',
related_name='trap_species',
on_delete=models.CASCADE)
species = models.ForeignKey(Species, related_name='trap_species',
on_delete=models.CASCADE)
sex = models.CharField(max_length=25, blank=True)
sex = models.ForeignKey(Sex, related_name='trap_species',
on_delete=models.CASCADE, null=True)
count = models.IntegerField(blank=True, null=True)
count_estimated = models.BooleanField(default=False)
@ -40,7 +53,8 @@ class CollectionSpecies(models.Model):
on_delete=models.CASCADE)
species = models.ForeignKey(Species, related_name='collection_species',
on_delete=models.CASCADE)
sex = models.CharField(max_length=25, blank=True)
sex = models.ForeignKey(Sex, related_name='collection_species',
on_delete=models.CASCADE, null=True)
count = models.IntegerField(blank=True, null=True)
count_estimated = models.BooleanField(default=False)

View file

@ -1,6 +1,6 @@
from rest_framework_json_api import serializers
from .models import Species, CollectionSpecies
from .models import Species, Sex, CollectionSpecies
class SpeciesSerializer(serializers.ModelSerializer):
@ -9,10 +9,17 @@ class SpeciesSerializer(serializers.ModelSerializer):
fields = ('common_name', 'genus', 'species', 'parasite', 'sort_order')
class SexSerializer(serializers.ModelSerializer):
class Meta:
model = Sex
fields = ('name', 'sort_order')
class CollectionSpeciesSerializer(serializers.ModelSerializer):
included_serializers = {
'collection': 'ccdb.collections_ccdb.serializers.CollectionSerializer',
'species': 'ccdb.species.serializers.SpeciesSerializer',
'sex': 'ccdb.species.serializers.SexSerializer',
}
class Meta:

View file

@ -1,7 +1,7 @@
from factory import DjangoModelFactory, Sequence, SubFactory
from factory.fuzzy import FuzzyText, FuzzyChoice, FuzzyInteger
from ..models import Species, TrapSpecies, CollectionSpecies
from ..models import Species, Sex, TrapSpecies, CollectionSpecies
from ccdb.collections_ccdb.tests.factories import (CollectionFactory,
CollectionTrapFactory)
@ -17,13 +17,21 @@ class SpeciesFactory(DjangoModelFactory):
sort_order = Sequence(lambda n: n)
class SexFactory(DjangoModelFactory):
class Meta:
model = Sex
name = Sequence(lambda n: 'sex{}'.format(n))
sort_order = Sequence(lambda n: n)
class TrapSpeciesFactory(DjangoModelFactory):
class Meta:
model = TrapSpecies
collection_trap = SubFactory(CollectionTrapFactory)
species = SubFactory(SpeciesFactory)
sex = FuzzyText(length=25)
sex = SubFactory(SexFactory)
count = FuzzyInteger(0)
count_estimated = FuzzyChoice(choices=[True, False])
@ -34,6 +42,6 @@ class CollectionSpeciesFactory(DjangoModelFactory):
collection = SubFactory(CollectionFactory)
species = SubFactory(SpeciesFactory)
sex = FuzzyText(length=25)
sex = SubFactory(SexFactory)
count = FuzzyInteger(0)
count_estimated = FuzzyChoice(choices=[True, False])

View file

@ -1,7 +1,8 @@
from rest_framework import viewsets
from .models import Species, CollectionSpecies
from .serializers import SpeciesSerializer, CollectionSpeciesSerializer
from .models import Species, Sex, CollectionSpecies
from .serializers import (SpeciesSerializer, SexSerializer,
CollectionSpeciesSerializer)
class SpeciesViewSet(viewsets.ModelViewSet):
@ -9,6 +10,11 @@ class SpeciesViewSet(viewsets.ModelViewSet):
serializer_class = SpeciesSerializer
class SexViewSet(viewsets.ModelViewSet):
queryset = Sex.objects.all()
serializer_class = SexSerializer
class CollectionSpeciesViewSet(viewsets.ModelViewSet):
queryset = CollectionSpecies.objects.all()
serializer_class = CollectionSpeciesSerializer

View file

@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.9 on 2018-02-28 12:46
from __future__ import unicode_literals
import django.contrib.auth.validators
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('users', '0003_remove_user_timezone'),
]
operations = [
migrations.AlterField(
model_name='user',
name='username',
field=models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username'),
),
]