ENH: Sex fields as lookups (#55)
This commit is contained in:
parent
4cd133f993
commit
c52d4e736d
9 changed files with 182 additions and 9 deletions
|
@ -35,6 +35,7 @@ router.register(r'sites', locations_viewsets.SiteViewSet)
|
||||||
router.register(r'study-locations', locations_viewsets.StudyLocationViewSet)
|
router.register(r'study-locations', locations_viewsets.StudyLocationViewSet)
|
||||||
# Species
|
# Species
|
||||||
router.register(r'species', species_viewsets.SpeciesViewSet)
|
router.register(r'species', species_viewsets.SpeciesViewSet)
|
||||||
|
router.register(r'sexes', species_viewsets.SexViewSet)
|
||||||
router.register(r'collection-species',
|
router.register(r'collection-species',
|
||||||
species_viewsets.CollectionSpeciesViewSet)
|
species_viewsets.CollectionSpeciesViewSet)
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
|
|
||||||
from .models import Species, TrapSpecies, CollectionSpecies
|
from .models import Species, Sex, TrapSpecies, CollectionSpecies
|
||||||
|
|
||||||
|
|
||||||
class SpeciesAdmin(admin.ModelAdmin):
|
class SpeciesAdmin(admin.ModelAdmin):
|
||||||
|
@ -12,6 +12,14 @@ class SpeciesAdmin(admin.ModelAdmin):
|
||||||
fields = ('common_name', 'genus', 'species', 'parasite', 'sort_order')
|
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):
|
class TrapSpeciesAdmin(admin.ModelAdmin):
|
||||||
list_display = ('collection_trap', 'species', 'sex', 'count',
|
list_display = ('collection_trap', 'species', 'sex', 'count',
|
||||||
'count_estimated')
|
'count_estimated')
|
||||||
|
@ -32,5 +40,6 @@ class CollectionSpeciesAdmin(admin.ModelAdmin):
|
||||||
|
|
||||||
|
|
||||||
admin.site.register(Species, SpeciesAdmin)
|
admin.site.register(Species, SpeciesAdmin)
|
||||||
|
admin.site.register(Sex, SexAdmin)
|
||||||
admin.site.register(TrapSpecies, TrapSpeciesAdmin)
|
admin.site.register(TrapSpecies, TrapSpeciesAdmin)
|
||||||
admin.site.register(CollectionSpecies, CollectionSpeciesAdmin)
|
admin.site.register(CollectionSpecies, CollectionSpeciesAdmin)
|
||||||
|
|
39
ccdb/species/migrations/0004_sex.py
Normal file
39
ccdb/species/migrations/0004_sex.py
Normal 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),
|
||||||
|
]
|
68
ccdb/species/migrations/0005_replace_sex_fields.py
Normal file
68
ccdb/species/migrations/0005_replace_sex_fields.py
Normal 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',
|
||||||
|
),
|
||||||
|
]
|
|
@ -17,13 +17,26 @@ class Species(models.Model):
|
||||||
verbose_name_plural = 'species'
|
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):
|
class TrapSpecies(models.Model):
|
||||||
collection_trap = models.ForeignKey('collections_ccdb.CollectionTrap',
|
collection_trap = models.ForeignKey('collections_ccdb.CollectionTrap',
|
||||||
related_name='trap_species',
|
related_name='trap_species',
|
||||||
on_delete=models.CASCADE)
|
on_delete=models.CASCADE)
|
||||||
species = models.ForeignKey(Species, related_name='trap_species',
|
species = models.ForeignKey(Species, related_name='trap_species',
|
||||||
on_delete=models.CASCADE)
|
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 = models.IntegerField(blank=True, null=True)
|
||||||
count_estimated = models.BooleanField(default=False)
|
count_estimated = models.BooleanField(default=False)
|
||||||
|
|
||||||
|
@ -40,7 +53,8 @@ class CollectionSpecies(models.Model):
|
||||||
on_delete=models.CASCADE)
|
on_delete=models.CASCADE)
|
||||||
species = models.ForeignKey(Species, related_name='collection_species',
|
species = models.ForeignKey(Species, related_name='collection_species',
|
||||||
on_delete=models.CASCADE)
|
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 = models.IntegerField(blank=True, null=True)
|
||||||
count_estimated = models.BooleanField(default=False)
|
count_estimated = models.BooleanField(default=False)
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
from rest_framework_json_api import serializers
|
from rest_framework_json_api import serializers
|
||||||
|
|
||||||
from .models import Species, CollectionSpecies
|
from .models import Species, Sex, CollectionSpecies
|
||||||
|
|
||||||
|
|
||||||
class SpeciesSerializer(serializers.ModelSerializer):
|
class SpeciesSerializer(serializers.ModelSerializer):
|
||||||
|
@ -9,10 +9,17 @@ class SpeciesSerializer(serializers.ModelSerializer):
|
||||||
fields = ('common_name', 'genus', 'species', 'parasite', 'sort_order')
|
fields = ('common_name', 'genus', 'species', 'parasite', 'sort_order')
|
||||||
|
|
||||||
|
|
||||||
|
class SexSerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = Sex
|
||||||
|
fields = ('name', 'sort_order')
|
||||||
|
|
||||||
|
|
||||||
class CollectionSpeciesSerializer(serializers.ModelSerializer):
|
class CollectionSpeciesSerializer(serializers.ModelSerializer):
|
||||||
included_serializers = {
|
included_serializers = {
|
||||||
'collection': 'ccdb.collections_ccdb.serializers.CollectionSerializer',
|
'collection': 'ccdb.collections_ccdb.serializers.CollectionSerializer',
|
||||||
'species': 'ccdb.species.serializers.SpeciesSerializer',
|
'species': 'ccdb.species.serializers.SpeciesSerializer',
|
||||||
|
'sex': 'ccdb.species.serializers.SexSerializer',
|
||||||
}
|
}
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
from factory import DjangoModelFactory, Sequence, SubFactory
|
from factory import DjangoModelFactory, Sequence, SubFactory
|
||||||
from factory.fuzzy import FuzzyText, FuzzyChoice, FuzzyInteger
|
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,
|
from ccdb.collections_ccdb.tests.factories import (CollectionFactory,
|
||||||
CollectionTrapFactory)
|
CollectionTrapFactory)
|
||||||
|
|
||||||
|
@ -17,13 +17,21 @@ class SpeciesFactory(DjangoModelFactory):
|
||||||
sort_order = Sequence(lambda n: n)
|
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 TrapSpeciesFactory(DjangoModelFactory):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = TrapSpecies
|
model = TrapSpecies
|
||||||
|
|
||||||
collection_trap = SubFactory(CollectionTrapFactory)
|
collection_trap = SubFactory(CollectionTrapFactory)
|
||||||
species = SubFactory(SpeciesFactory)
|
species = SubFactory(SpeciesFactory)
|
||||||
sex = FuzzyText(length=25)
|
sex = SubFactory(SexFactory)
|
||||||
count = FuzzyInteger(0)
|
count = FuzzyInteger(0)
|
||||||
count_estimated = FuzzyChoice(choices=[True, False])
|
count_estimated = FuzzyChoice(choices=[True, False])
|
||||||
|
|
||||||
|
@ -34,6 +42,6 @@ class CollectionSpeciesFactory(DjangoModelFactory):
|
||||||
|
|
||||||
collection = SubFactory(CollectionFactory)
|
collection = SubFactory(CollectionFactory)
|
||||||
species = SubFactory(SpeciesFactory)
|
species = SubFactory(SpeciesFactory)
|
||||||
sex = FuzzyText(length=25)
|
sex = SubFactory(SexFactory)
|
||||||
count = FuzzyInteger(0)
|
count = FuzzyInteger(0)
|
||||||
count_estimated = FuzzyChoice(choices=[True, False])
|
count_estimated = FuzzyChoice(choices=[True, False])
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
from rest_framework import viewsets
|
from rest_framework import viewsets
|
||||||
|
|
||||||
from .models import Species, CollectionSpecies
|
from .models import Species, Sex, CollectionSpecies
|
||||||
from .serializers import SpeciesSerializer, CollectionSpeciesSerializer
|
from .serializers import (SpeciesSerializer, SexSerializer,
|
||||||
|
CollectionSpeciesSerializer)
|
||||||
|
|
||||||
|
|
||||||
class SpeciesViewSet(viewsets.ModelViewSet):
|
class SpeciesViewSet(viewsets.ModelViewSet):
|
||||||
|
@ -9,6 +10,11 @@ class SpeciesViewSet(viewsets.ModelViewSet):
|
||||||
serializer_class = SpeciesSerializer
|
serializer_class = SpeciesSerializer
|
||||||
|
|
||||||
|
|
||||||
|
class SexViewSet(viewsets.ModelViewSet):
|
||||||
|
queryset = Sex.objects.all()
|
||||||
|
serializer_class = SexSerializer
|
||||||
|
|
||||||
|
|
||||||
class CollectionSpeciesViewSet(viewsets.ModelViewSet):
|
class CollectionSpeciesViewSet(viewsets.ModelViewSet):
|
||||||
queryset = CollectionSpecies.objects.all()
|
queryset = CollectionSpecies.objects.all()
|
||||||
serializer_class = CollectionSpeciesSerializer
|
serializer_class = CollectionSpeciesSerializer
|
||||||
|
|
21
ccdb/users/migrations/0004_auto_20180228_1246.py
Normal file
21
ccdb/users/migrations/0004_auto_20180228_1246.py
Normal 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'),
|
||||||
|
),
|
||||||
|
]
|
Loading…
Add table
Reference in a new issue