Commit 7f90bf00 authored by Kenzo-Hugo Hillion's avatar Kenzo-Hugo Hillion
Browse files

Merge branch '55-update-scripts-api' into 'dev'

Resolve "Update scripts to use new `PUT` and `POST` to populate database"

Closes #55

See merge request !14
parents 3c047acd e8a384d4
Pipeline #17093 passed with stages
in 2 minutes and 52 seconds
.DS_Store
__pycache__/
*.egg-info/
.env
*.env
.env_dev
.idea/
.vscode
......@@ -18,3 +19,4 @@ notebooks/
# Tests files
.coverage
.pytest_cache
# Metagenedb
[![pipeline status](https://gitlab.pasteur.fr/metagenomics/metagenedb/badges/master/pipeline.svg)](https://gitlab.pasteur.fr/metagenomics/metagenedb/commits/master)
[![coverage report](https://gitlab.pasteur.fr/metagenomics/metagenedb/badges/master/coverage.svg)](https://gitlab.pasteur.fr/metagenomics/metagenedb/commits/master)
[![pipeline status](https://gitlab.pasteur.fr/metagenomics/metagenedb/badges/dev/pipeline.svg)](https://gitlab.pasteur.fr/metagenomics/metagenedb/commits/dev)
[![coverage report](https://gitlab.pasteur.fr/metagenomics/metagenedb/badges/dev/coverage.svg)](https://gitlab.pasteur.fr/metagenomics/metagenedb/commits/dev)
Django based project to build genes catalog and tools
to play with it and contact external services.
......
......@@ -27,6 +27,7 @@ Cycler = "*"
jupyter = "*"
factory-boy = "*"
pytest-factoryboy = "*"
pylint = "*"
[packages]
certifi = "*"
......
{
"_meta": {
"hash": {
"sha256": "ccf8681e4b40107fa82f5be41d08cd73348d3b3ebc0fdbad1a18dbf549297337"
"sha256": "a9a2ecd17c88a47e5a54273aab5c3fae726014e859e07586f49446d8fa886911"
},
"pipfile-spec": 6,
"requires": {
......@@ -25,11 +25,11 @@
},
"certifi": {
"hashes": [
"sha256:046832c04d4e752f37383b628bc601a7ea7211496b4638f6514d0e5b9acc4939",
"sha256:945e3ba63a0b9f577b1395204e13c3a231f9bc0223888be653286534e5873695"
"sha256:e4f3620cfea4f83eedc95b24abd9cd56f3c4b146dd0177e83a21b4eb49e21e50",
"sha256:fd7c7c74727ddcf00e9acd26bba8da604ffec95bf1c2144e67aff7a8b50e6cef"
],
"index": "pypi",
"version": "==2019.6.16"
"version": "==2019.9.11"
},
"chardet": {
"hashes": [
......@@ -179,7 +179,7 @@
},
"master": {
"git": "https://github.com/khillion/bioapi.git",
"ref": "201003535ff7b788492f056884b1ad166ee02b59"
"ref": "1b0f58f458ed5c3b8d0a5f6cdc9a7838d52e52fe"
},
"metagenedb": {
"editable": true,
......@@ -187,25 +187,25 @@
},
"numpy": {
"hashes": [
"sha256:03f2ebcbffcce2dec8860633b89a93e80c6a239d21a77ae8b241450dc21e8c35",
"sha256:078c8025da5ab9e8657edc9c2a1e9642e06e953bc7baa2e65c1aa9d9dfb7e98b",
"sha256:0fbfa98c5d5c3c6489cc1e852ec94395d51f35d9ebe70c6850e47f465038cdf4",
"sha256:1c841033f4fe6801648180c3033c45b3235a8bbd09bc7249010f99ea27bb6790",
"sha256:2c0984a01ddd0aeec89f0ce46ef21d64761048cd76c0074d0658c91f9131f154",
"sha256:4c166dcb0fff7cb3c0bbc682dfb5061852a2547efb6222e043a7932828c08fb5",
"sha256:8c2d98d0623bd63fb883b65256c00454d5f53127a5a7bcdaa8bdc582814e8cb4",
"sha256:8cb4b6ae45aad6d26712a1ce0a3f2556c5e1484867f9649e03496e45d6a5eba4",
"sha256:93050e73c446c82065b7410221b07682e475ac51887cd9368227a5d944afae80",
"sha256:a3f6b3024f8826d8b1490e6e2a9b99e841cd2c375791b1df62991bd8f4c00b89",
"sha256:bede70fd8699695363f39e86c1e869b2c8b74fb5ef135a67b9e1eeebff50322a",
"sha256:c304b2221f33489cd15a915237a84cdfe9420d7e4d4828c78a0820f9d990395c",
"sha256:f11331530f0eff69a758d62c2461cd98cdc2eae0147279d8fc86e0464eb7e8ca",
"sha256:fa5f2a8ef1e07ba258dc07d4dd246de23ef4ab920ae0f3fa2a1cc5e90f0f1888",
"sha256:fb6178b0488b0ce6a54bc4accbdf5225e937383586555604155d64773f6beb2b",
"sha256:fd5e830d4dc31658d61a6452cd3e842213594d8c15578cdae6829e36ad9c0930"
],
"index": "pypi",
"version": "==1.17.1"
"sha256:05dbfe72684cc14b92568de1bc1f41e5f62b00f714afc9adee42f6311738091f",
"sha256:0d82cb7271a577529d07bbb05cb58675f2deb09772175fab96dc8de025d8ac05",
"sha256:10132aa1fef99adc85a905d82e8497a580f83739837d7cbd234649f2e9b9dc58",
"sha256:12322df2e21f033a60c80319c25011194cd2a21294cc66fee0908aeae2c27832",
"sha256:16f19b3aa775dddc9814e02a46b8e6ae6a54ed8cf143962b4e53f0471dbd7b16",
"sha256:3d0b0989dd2d066db006158de7220802899a1e5c8cf622abe2d0bd158fd01c2c",
"sha256:438a3f0e7b681642898fd7993d38e2bf140a2d1eafaf3e89bb626db7f50db355",
"sha256:5fd214f482ab53f2cea57414c5fb3e58895b17df6e6f5bca5be6a0bb6aea23bb",
"sha256:73615d3edc84dd7c4aeb212fa3748fb83217e00d201875a47327f55363cef2df",
"sha256:7bd355ad7496f4ce1d235e9814ec81ee3d28308d591c067ce92e49f745ba2c2f",
"sha256:7d077f2976b8f3de08a0dcf5d72083f4af5411e8fddacd662aae27baa2601196",
"sha256:a4092682778dc48093e8bda8d26ee8360153e2047826f95a3f5eae09f0ae3abf",
"sha256:b458de8624c9f6034af492372eb2fee41a8e605f03f4732f43fc099e227858b2",
"sha256:e70fc8ff03a961f13363c2c95ef8285e0cf6a720f8271836f852cc0fa64e97c8",
"sha256:ee8e9d7cad5fe6dde50ede0d2e978d81eafeaa6233fb0b8719f60214cf226578",
"sha256:f4a4f6aba148858a5a5d546a99280f71f5ee6ec8182a7d195af1a914195b21a2"
],
"index": "pypi",
"version": "==1.17.2"
},
"packaging": {
"hashes": [
......@@ -379,6 +379,13 @@
"markers": "sys_platform == 'darwin'",
"version": "==0.1.0"
},
"astroid": {
"hashes": [
"sha256:6560e1e1749f68c64a4b5dee4e091fce798d2f0d84ebe638cf0e0585a343acf4",
"sha256:b65db1bbaac9f9f4d190199bb8680af6f6f84fd3769a5ea883df8a91fe68b4c4"
],
"version": "==2.2.5"
},
"atomicwrites": {
"hashes": [
"sha256:03472c30eb2c5d1ba9227e4c2ca66ab8287fbfbbda3888aa93dc2e28fc6811b4",
......@@ -486,10 +493,10 @@
},
"faker": {
"hashes": [
"sha256:1d3f700e8dfcefd6e657118d71405d53e86974448aba78884f119bbd84c0cddf",
"sha256:d5366e120191c5610fceeebfe1c298dc46da0277096f639c6dd7e2eaee0fa547"
"sha256:45cc9cca3de8beba5a2da3bd82a6e5544f53da1a702645c8485f682366c15026",
"sha256:a6459ff518d1fc6ee2238a7209e6c899517872c7e1115510279033ffe6fe8ef3"
],
"version": "==2.0.1"
"version": "==2.0.2"
},
"flake8": {
"hashes": [
......@@ -501,11 +508,11 @@
},
"importlib-metadata": {
"hashes": [
"sha256:9ff1b1c5a354142de080b8a4e9803e5d0d59283c93aed808617c787d16768375",
"sha256:b7143592e374e50584564794fcb8aaf00a23025f9db866627f89a21491847a8d"
"sha256:aa18d7378b00b40847790e7c27e11673d7fed219354109d0e7b9e5b25dc3ad26",
"sha256:d5f18a79777f3aa179c145737780282e27b508fc8fd688cb17c7a813e8bd39af"
],
"index": "pypi",
"version": "==0.20"
"version": "==0.23"
},
"inflection": {
"hashes": [
......@@ -542,6 +549,13 @@
],
"version": "==7.5.1"
},
"isort": {
"hashes": [
"sha256:54da7e92468955c4fceacd0c86bd0ec997b0e1ee80d97f67c35a78b719dccab1",
"sha256:6e811fcb295968434526407adb8796944f1988c5b65e8139058f2014cbe100fd"
],
"version": "==4.3.21"
},
"jedi": {
"hashes": [
"sha256:786b6c3d80e2f06fd77162a07fed81b8baa22dde5d62896a790a331d6ac21a27",
......@@ -574,10 +588,10 @@
},
"jupyter-client": {
"hashes": [
"sha256:73a809a2964afa07adcc1521537fddb58c2ffbb7e84d53dc5901cf80480465b3",
"sha256:98e8af5edff5d24e4d31e73bc21043130ae9d955a91aa93fc0bc3b1d0f7b5880"
"sha256:6a6d415c62179728f6d9295b37356d8f6833e9e01c2b6e1901dc555571f57b21",
"sha256:f406f214f9daa92be110d5b83d62f3451ffc73d3522db7350f0554683533ab18"
],
"version": "==5.3.1"
"version": "==5.3.3"
},
"jupyter-console": {
"hashes": [
......@@ -627,6 +641,29 @@
"index": "pypi",
"version": "==1.1.0"
},
"lazy-object-proxy": {
"hashes": [
"sha256:02b260c8deb80db09325b99edf62ae344ce9bc64d68b7a634410b8e9a568edbf",
"sha256:18f9c401083a4ba6e162355873f906315332ea7035803d0fd8166051e3d402e3",
"sha256:1f2c6209a8917c525c1e2b55a716135ca4658a3042b5122d4e3413a4030c26ce",
"sha256:2f06d97f0ca0f414f6b707c974aaf8829c2292c1c497642f63824119d770226f",
"sha256:616c94f8176808f4018b39f9638080ed86f96b55370b5a9463b2ee5c926f6c5f",
"sha256:63b91e30ef47ef68a30f0c3c278fbfe9822319c15f34b7538a829515b84ca2a0",
"sha256:77b454f03860b844f758c5d5c6e5f18d27de899a3db367f4af06bec2e6013a8e",
"sha256:83fe27ba321e4cfac466178606147d3c0aa18e8087507caec78ed5a966a64905",
"sha256:84742532d39f72df959d237912344d8a1764c2d03fe58beba96a87bfa11a76d8",
"sha256:874ebf3caaf55a020aeb08acead813baf5a305927a71ce88c9377970fe7ad3c2",
"sha256:9f5caf2c7436d44f3cec97c2fa7791f8a675170badbfa86e1992ca1b84c37009",
"sha256:a0c8758d01fcdfe7ae8e4b4017b13552efa7f1197dd7358dc9da0576f9d0328a",
"sha256:a4def978d9d28cda2d960c279318d46b327632686d82b4917516c36d4c274512",
"sha256:ad4f4be843dace866af5fc142509e9b9817ca0c59342fdb176ab6ad552c927f5",
"sha256:ae33dd198f772f714420c5ab698ff05ff900150486c648d29951e9c70694338e",
"sha256:b4a2b782b8a8c5522ad35c93e04d60e2ba7f7dcb9271ec8e8c3e08239be6c7b4",
"sha256:c462eb33f6abca3b34cdedbe84d761f31a60b814e173b98ede3c81bb48967c4f",
"sha256:fd135b8d35dfdcdb984828c84d695937e58cc5f49e1c854eb311c4d6aa03f4f1"
],
"version": "==1.4.2"
},
"markupsafe": {
"hashes": [
"sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473",
......@@ -742,11 +779,11 @@
},
"pluggy": {
"hashes": [
"sha256:0825a152ac059776623854c1543d65a4ad408eb3d33ee114dff91e57ec6ae6fc",
"sha256:b9817417e95936bf75d85d3f8767f7df6cdde751fc40aed3bb3074cbcb77757c"
"sha256:0db4b7601aae1d35b4a033282da476845aa19185c1e6964b25cf324b5e4ec3e6",
"sha256:fa5fa1622fa6dd5c030e9cad086fa19ef6a0cf6d7a2d12318e10cb49d6d68f34"
],
"index": "pypi",
"version": "==0.12.0"
"version": "==0.13.0"
},
"prometheus-client": {
"hashes": [
......@@ -801,6 +838,14 @@
],
"version": "==2.4.2"
},
"pylint": {
"hashes": [
"sha256:5d77031694a5fb97ea95e828c8d10fc770a1df6eb3906067aaed42201a8a6a09",
"sha256:723e3db49555abaf9bf79dc474c6b9e2935ad82230b10c1138a71ea41ac0fff1"
],
"index": "pypi",
"version": "==2.3.1"
},
"pyparsing": {
"hashes": [
"sha256:6f98a7b9397e206d78cc01df10131398f1c8b8510a2f4d97d9abd82e1aacdd80",
......@@ -945,6 +990,27 @@
],
"version": "==4.3.2"
},
"typed-ast": {
"hashes": [
"sha256:18511a0b3e7922276346bcb47e2ef9f38fb90fd31cb9223eed42c85d1312344e",
"sha256:262c247a82d005e43b5b7f69aff746370538e176131c32dda9cb0f324d27141e",
"sha256:2b907eb046d049bcd9892e3076c7a6456c93a25bebfe554e931620c90e6a25b0",
"sha256:354c16e5babd09f5cb0ee000d54cfa38401d8b8891eefa878ac772f827181a3c",
"sha256:4e0b70c6fc4d010f8107726af5fd37921b666f5b31d9331f0bd24ad9a088e631",
"sha256:630968c5cdee51a11c05a30453f8cd65e0cc1d2ad0d9192819df9978984529f4",
"sha256:66480f95b8167c9c5c5c87f32cf437d585937970f3fc24386f313a4c97b44e34",
"sha256:71211d26ffd12d63a83e079ff258ac9d56a1376a25bc80b1cdcdf601b855b90b",
"sha256:95bd11af7eafc16e829af2d3df510cecfd4387f6453355188342c3e79a2ec87a",
"sha256:bc6c7d3fa1325a0c6613512a093bc2a2a15aeec350451cbdf9e1d4bffe3e3233",
"sha256:cc34a6f5b426748a507dd5d1de4c1978f2eb5626d51326e43280941206c209e1",
"sha256:d755f03c1e4a51e9b24d899561fec4ccaf51f210d52abdf8c07ee2849b212a36",
"sha256:d7c45933b1bdfaf9f36c579671fec15d25b06c8398f113dab64c18ed1adda01d",
"sha256:d896919306dd0aa22d0132f62a1b78d11aaf4c9fc5b3410d3c666b818191630a",
"sha256:ffde2fbfad571af120fcbfbbc61c72469e72f550d676c3342492a9dfdefb8f12"
],
"markers": "implementation_name == 'cpython'",
"version": "==1.4.0"
},
"wcwidth": {
"hashes": [
"sha256:3df37372226d6e63e1b1e1eda15c594bca98a22d33a23832a90998faa96bc65e",
......@@ -967,6 +1033,12 @@
],
"version": "==3.5.1"
},
"wrapt": {
"hashes": [
"sha256:565a021fd19419476b9362b05eeaa094178de64f8361e44468f9e9d7843901e1"
],
"version": "==1.11.2"
},
"zipp": {
"hashes": [
"sha256:3718b1cbcd963c7d4c5511a8240812904164b7f381b647143a89d3b98f9bcd8e",
......
from .function import FunctionFactory # noqa
from .gene import GeneFactory # noqa
from .taxonomy import TaxonomyFactory # noqa
from factory import DjangoModelFactory, lazy_attribute
from faker import Factory
from metagenedb.apps.catalog import models
faker = Factory.create()
SELECTED_SOURCE = [i[0] for i in models.Function.SOURCE_CHOICES]
class GeneFactory(DjangoModelFactory):
class Meta:
model = models.Gene
@lazy_attribute
def gene_id(self):
return str(faker.pyint())
@lazy_attribute
def length(self):
return str(faker.pyint())
# Generated by Django 2.2.5 on 2019-09-12 13:08
from django.db import migrations, models
import django.db.models.deletion
from metagenedb.common.utils.chunks import generate_chunks
def copy_gene_functions(apps, schema_editor):
Gene = apps.get_model('catalog', 'Gene')
GeneFunction = apps.get_model('catalog', 'GeneFunction')
OldGeneFunctions = Gene.functions.through
for chunk in generate_chunks(OldGeneFunctions.objects.all(), 500):
new_objs = [GeneFunction(gene=item.gene, function=item.function) for item in chunk]
GeneFunction.objects.bulk_create(new_objs)
class Migration(migrations.Migration):
dependencies = [
('catalog', '0009_meta_unique'),
]
operations = [
migrations.CreateModel(
name='GeneFunction',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('function', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='catalog.Function')),
('gene', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='catalog.Gene')),
],
options={
'unique_together': {('gene', 'function')},
},
),
migrations.RunPython(copy_gene_functions)
]
# Generated by Django 2.2.5 on 2019-09-12 13:43
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('catalog', '0010_genefunction'),
]
operations = [
migrations.RemoveField(
model_name='gene',
name='functions',
field=models.ManyToManyField(to='catalog.Function'),
),
migrations.AddField(
model_name='gene',
name='functions',
field=models.ManyToManyField(through='catalog.GeneFunction', to='catalog.Function'),
),
]
from .function import Function, KeggOrthology # noqa
from .gene import Gene # noqa
from .gene import Gene, GeneFunction # noqa
from .taxonomy import Taxonomy # noqa
......@@ -7,7 +7,7 @@ class Gene(models.Model):
gene_name = models.CharField(max_length=100, unique=True)
gene_id = models.SlugField(max_length=100, db_index=True, unique=True)
length = models.PositiveIntegerField()
functions = models.ManyToManyField(Function)
functions = models.ManyToManyField(Function, through='GeneFunction')
taxonomy = models.ForeignKey(
'Taxonomy', related_name='genes',
on_delete=models.SET_NULL,
......@@ -19,3 +19,16 @@ class Gene(models.Model):
class Meta:
ordering = ['-gene_id']
class GeneFunction(models.Model):
gene = models.ForeignKey(Gene, on_delete=models.CASCADE)
function = models.ForeignKey(Function, on_delete=models.CASCADE)
def __str__(self):
return f"{self.gene.gene_id} <-> {self.function.function_id}"
class Meta:
unique_together = [
'gene', 'function'
]
from collections import defaultdict
from rest_framework import serializers
from rest_framework.exceptions import ValidationError
from rest_framework.exceptions import ValidationError, ErrorDetail
from rest_framework.fields import SkipField
from rest_framework.settings import api_settings
from rest_framework.utils import html, model_meta
......@@ -7,13 +9,20 @@ from rest_framework.utils import html, model_meta
class BulkListSerializer(serializers.ListSerializer):
def _extract_many_to_many(self, validated_data, info):
many_to_many = [{} for v in validated_data]
def _extract_many_to_many(self, validated_data, info, lookup_field):
many_to_many = {
'keys': set(),
'values': defaultdict(list)
}
for field_name, relation_info in info.relations.items():
if relation_info.to_many:
for data_item, many_to_many_item in zip(validated_data, many_to_many):
for data_item in validated_data:
if field_name in data_item:
many_to_many_item[field_name] = data_item.pop(field_name)
many_to_many['keys'].add(field_name)
many_to_many['values'][field_name].append({
field_name: data_item.pop(field_name),
lookup_field: data_item[lookup_field]
})
return many_to_many
def _get_db_index_fields(self, info):
......@@ -68,6 +77,7 @@ class BulkListSerializer(serializers.ListSerializer):
ret = []
errors = []
primary_keys = set()
for item in data:
try:
if isinstance(self.instance, dict):
......@@ -75,6 +85,10 @@ class BulkListSerializer(serializers.ListSerializer):
validated = self.child.run_validation(item)
else:
validated = self.child.run_validation(item)
if item[lookup_field] not in primary_keys:
primary_keys.add(item[lookup_field])
else:
errors.append(ErrorDetail(item[lookup_field], code='duplicate'))
except ValidationError as exc:
errors.append(exc.detail)
else:
......@@ -88,9 +102,15 @@ class BulkListSerializer(serializers.ListSerializer):
def create(self, validated_data):
ModelClass = self.Meta.model
info = model_meta.get_field_info(ModelClass)
lookup_field = self._get_db_index_fields(info)[0]
many_to_many = self._extract_many_to_many(validated_data, info, lookup_field)
instances = ModelClass.objects.bulk_create(
[ModelClass(**item) for item in validated_data]
)
if many_to_many:
for field in many_to_many['keys']:
getattr(self, f'_handle_{field}', None)(many_to_many['values'][field])
return instances
def update(self, instances, validated_data):
......@@ -100,8 +120,8 @@ class BulkListSerializer(serializers.ListSerializer):
"""
ModelClass = self.Meta.model
info = model_meta.get_field_info(ModelClass)
db_index_fields = self._get_db_index_fields(info)
lookup_field = db_index_fields[0]
lookup_field = self._get_db_index_fields(info)[0]
many_to_many = self._extract_many_to_many(validated_data, info, lookup_field)
updated_keys = self._get_all_key_fields(validated_data)
validated_data = {item.pop(lookup_field): item for item in validated_data}
for item_id, validated_data_element in validated_data.items():
......@@ -111,6 +131,10 @@ class BulkListSerializer(serializers.ListSerializer):
list(instances.values()),
updated_keys
)
# Link existing many-to-many relationships.
if many_to_many:
for field in many_to_many['keys']:
getattr(self, f'_handle_{field}', None)(many_to_many['values'][field])
return list(instances.values())
class Meta:
......
......@@ -3,8 +3,7 @@ import traceback
from rest_framework import serializers
from rest_framework.utils import model_meta
from metagenedb.apps.catalog.models import Function, Gene, Taxonomy
from metagenedb.apps.catalog.serializers import FunctionSerializer
from metagenedb.apps.catalog.models import Function, Gene, GeneFunction, Taxonomy
from .bulk_list import BulkListSerializer
......@@ -16,11 +15,45 @@ class GeneListSerializer(BulkListSerializer):
class Meta:
model = Gene
def _generate_gene_function_mapping(self, values, genes):
"""
Generate a list of GeneFunction pair to create relation between them
"""
genes_dict = {gene.gene_id: gene for gene in genes}
mapping = []
for value in values:
for function in value['functions']:
mapping.append(GeneFunction(gene=genes_dict[value['gene_id']],
function=function))
return mapping
def _handle_functions(self, values):
"""
:param values: each dictionnary has the 'functions' and 'gene_id' keys
:type values: LIST of DICT
"""
# Get all Gene objects
gene_ids = [item['gene_id'] for item in values]
# Get all link with corresponding genes & Delete them
genes = Gene.objects.filter(gene_id__in=gene_ids)
GeneFunction.objects.filter(gene__in=genes).delete()
# Generate table for bulk_create of function <-> gene and create it
GeneFunction.objects.bulk_create(
self._generate_gene_function_mapping(values, genes)
)
print("hi")
def create(self, validated_data):
instances = super().create(validated_data)
return instances
class GeneSerializer(serializers.ModelSerializer):
functions = FunctionSerializer(
functions = serializers.SlugRelatedField(
queryset=Function.objects.all(),
slug_field='function_id',
many=True,
required=False
required=False,
)
taxonomy = serializers.SlugRelatedField(
queryset=Taxonomy.objects.all(),
......@@ -43,12 +76,12 @@ class GeneSerializer(serializers.ModelSerializer):
def _handle_functions(self, functions, instance):
for function in functions:
try:
function = Function.objects.get(function_id=function.get('function_id'))
function = Function.objects.get(function_id=function)
instance.functions.add(function)
instance.full_clean()
instance.save()
except Function.DoesNotExist:
_LOGGER.warning(f"{function.get('function_id')} not found for {instance.gene_id}. Function ignored")
_LOGGER.warning("%s not found for %s. Function ignored", function, instance.gene_id)
def create(self, validated_data):
ModelClass = self.Meta.model
......
......@@ -3,6 +3,7 @@ from unittest import TestCase
from unittest.mock import Mock
from rest_framework.test import APITestCase
from rest_framework.exceptions import ValidationError
from metagenedb.apps.catalog.serializers import FunctionSerializer
from metagenedb.apps.catalog.serializers.bulk_list import BulkListSerializer
......@@ -23,8 +24,8 @@ class BaseTestBulkListSerializerMethods(TestCase):
def setUp(self):
self.data = [
{'field1': 'value1', 'field2': 'value2'},
{'field1': 'value3', 'field2': 'value4'}
{'id': 'entry_1', 'field1': 'value1', 'field2': 'value2'},
{'id': 'entry_2', 'field1': 'value3', 'field2': 'value4'}
]
self.bulk_list_serializer = BulkListSerializerTestExtractManyToMany()
self.info = Mock()
......@@ -38,12 +39,40 @@ class TestExtractManyToMany(BaseTestBulkListSerializerMethods):
'field2': Mock(to_many=False)
}
ori_list = deepcopy(self.data)
expected_list = [
{'field1': 'value1'},
{'field1': 'value3'}
]
tested_list = self.bulk_list_serializer._extract_many_to_many(self.data, self.info)
self.assertListEqual(tested_list, expected_list)
expected_dict = {
'keys': {'field1'},
'values': {
'field1': [
{'field1': 'value1', 'id': 'entry_1'},
{'field1': 'value3', 'id': 'entry_2'}
]
}
}