将对象添加到ManyToMany字段时,Django TypeError'NoneType'

时间:2017-10-19 19:59:37

标签: django django-models

我正在尝试在我的Django项目中添加一个名为“clinicaltrials”(CT)的应用程序,该应用程序存储来自clinicaltrial.gov API的数据。每个试验可能有多个合作者和多种疾病,因此我使用ManyToManyField为它们设置了其他模型。 (注意:我最初尝试将CT直接连接到我的公司模型,但并非所有可能的公司都在我的数据库中,因此我在CT模型中也捕获了名称)

我遇到的问题是当我尝试将CT记录添加到其他任何一个模型时,我收到错误TypeError: 'NoneType' object is not iterable。我认为通过pk查找它可以正常工作。这是我第一次使用ManyToManyField,过去两天我一直在努力。我在哪里错了?

这是我用来写模型的功能:

def write_database(data):

    for trial in range(len(data)):

        # if the trial exists in the database continue to the next one
        if ClinicalTrial.objects.filter(nct_id=data[trial].get('nct_id')).exists():
            continue

        # create list of collaborators for later
        if data[trial].get('collaborators') is not None:
            collaborators = []
            collaborator_len = len(data[trial].get('collaborators'))
            for x in range(collaborator_len):
                collaborators.append(data[trial].get('collaborators')[x].get('name'))
        else:
            collaborators = None

        print(collaborators)

        # write trial info to database
        ct = ClinicalTrial()
        ct.nct_id = data[trial].get('nct_id')
        ct.status = data[trial].get('current_trial_status')
        ct.status_date = data[trial].get('current_trial_status_date')
        ct.start_date = data[trial].get('start_date')
        ct.start_date_type_code = data[trial].get('start_date_type_code')
        ct.completion_date = data[trial].get('completion_date')
        ct.record_verification_date = data[trial].get('record_verification_date')
        ct.completion_date_type_code = data[trial].get('completion_date_type_code')
        ct.brief_title = data[trial].get('brief_title')
        ct.official_title = data[trial].get('official_title')
        ct.brief_title = data[trial].get('brief_title')
        ct.brief_summary = data[trial].get('brief_summary')
        ct.primary_purpose_code = data[trial].get('primary_purpose').get('primary_purpose_code')
        ct.phase = data[trial].get('phase').get('phase')
        ct.minimum_target_accrual_number = data[trial].get('minimum_target_accrual_number')
        ct.number_of_arms = data[trial].get('number_of_arms')
        ct.lead_org_name = data[trial].get('lead_org')
        try:
            ct.lead_org_fk = Company.objects.get(company_name__startswith=data[trial].get('lead_org'))
        except:
            pass

        ct.save()
        pk = ct.pk  # added this to try and get the below to work

        # add collaborators
        if collaborators is not None:
            for x in range(len(collaborators)):
                try:
                    # add m2m key to ClinicalTrial model
                    key = Company.objects.get(company_name__startswith=collaborators[x])
                    ct.collaborators = ct.collaborators.add(key)
                    print('ct.collab added')
                    ct.save()

                    # not all companies will be linked above due to syntax, this adds the text name to a separate table
                    c, _ = Collaborator.objects.get_or_create(company=collaborators[x])
                    c.save()
                    ct = ClinicalTrial.objects.get(pk=pk)
                    c.clinical_trials = c.clinical_trials.add(ct)
                    c.save()
                except:
                    pass

        # add diseases
        if data[trial].get('diseases') is not None:
            len_diseases = len(data[trial].get('diseases'))
            for x in range(len_diseases):
                d, _ = Disease.objects.get_or_create(
                    disease_code=data[trial].get('diseases')[x].get('disease_code'),
                    preferred_name=data[trial].get('diseases')[x].get('preferred_name'),
                    display_name=data[trial].get('diseases')[x].get('display_name'))
                d.save()
                ct = ClinicalTrial.objects.get(pk=pk)
                d.clinical_trials = d.clinical_trials.add(ct)
                d.save()

    return

以下是我的models.py的样子:

from django.db import models
from dashboard.models import Company


class ClinicalTrial(models.Model):
    # companies involved
    lead_org_name = models.CharField(max_length=200)
    lead_org_fk = models.ForeignKey(Company, related_name='ct_lead_org', null=True)
    collaborators_m2m = models.ManyToManyField(Company)
    # model details
    nct_id = models.CharField(max_length=50, unique=True, default=0)
    status = models.CharField(max_length=200, blank=True)
    status_date = models.DateField(null=True)
    start_date = models.DateField(null=True)
    start_date_type_code = models.CharField(max_length=200, blank=True, default='')
    completion_date = models.DateField(null=True)
    completion_date_type_code = models.CharField(max_length=200, blank=True, default='', null=True)
    record_verification_date = models.CharField(max_length=200, blank=True)
    brief_title = models.CharField(max_length=200, blank=True)
    official_title = models.CharField(max_length=200, blank=True)
    brief_summary = models.CharField(max_length=200, blank=True)
    study_protocol_type = models.CharField(max_length=200, blank=True)
    primary_purpose_code = models.CharField(max_length=200, blank=True)
    phase = models.CharField(max_length=200, blank=True)
    minimum_target_accrual_number = models.CharField(max_length=200, blank=True)
    number_of_arms = models.CharField(max_length=200, blank=True)

    def __str__(self):
        return self.official_title


class Disease(models.Model):
    clinical_trials = models.ManyToManyField(ClinicalTrial, related_name='disease')
    disease_code = models.CharField(max_length=200, blank=True, null=True)
    preferred_name = models.CharField(max_length=200, blank=True)
    display_name = models.CharField(max_length=200, blank=True)


class Collaborator(models.Model):
    clinical_trials = models.ManyToManyField(ClinicalTrial, related_name='collaborator')
    company = models.CharField(max_length=200)

1 个答案:

答案 0 :(得分:0)

我不知道为什么,但我似乎无法在网上找到有关如何将值实际发布到ManyToManyField的任何代码示例。无论如何,这就是我能够让其他人面对类似问题的方法。

从根本上说,我学到了两件事。首先,这是如何将项添加到ManyToManyField d.clinical_trials.add(ct.pk)。其次,如果使用get_or_create()命令,则在添加ManyToManyField值之前不需要保存模型。

这是OP中函数的代码片段与我更改的内容。

#----------------------------------------------------------------    
# ORIGINAL CODE FROM OP
#----------------------------------------------------------------
# add m2m key to ClinicalTrial model
key = Company.objects.get(company_name__startswith=collaborators[x])
ct.collaborators = ct.collaborators.add(key)
print('ct.collab added')
ct.save()

# not all companies will be linked above due to syntax, this adds the text name to a separate table
c, _ = Collaborator.objects.get_or_create(company=collaborators[x])
c.save()
ct = ClinicalTrial.objects.get(pk=pk)
c.clinical_trials = c.clinical_trials.add(ct)
c.save()

# add diseases
if data[trial].get('diseases') is not None:
    len_diseases = len(data[trial].get('diseases'))
    for x in range(len_diseases):
        d, _ = Disease.objects.get_or_create(
            disease_code=data[trial].get('diseases')[x].get('disease_code'),
            preferred_name=data[trial].get('diseases')[x].get('preferred_name'),
            display_name=data[trial].get('diseases')[x].get('display_name'))
        d.save()
        ct = ClinicalTrial.objects.get(pk=pk)
        d.clinical_trials = d.clinical_trials.add(ct)
        d.save()

#----------------------------------------------------------------
# NEW CODE
#----------------------------------------------------------------
# add m2m key to ClinicalTrial model
key = Company.objects.get(company_name__startswith=collaborators[x])
ct.collaborators = ct.collaborators.add(key.PK)

# not all companies will be linked above due to syntax, this adds the text name to a separate table
c, _ = Collaborator.objects.get_or_create(company=collaborators[x])
c.clinical_trials.add(ct.pk)
c.save()

# add diseases
if data[trial].get('diseases') is not None:
    len_diseases = len(data[trial].get('diseases'))
    for x in range(len_diseases):
        d, _ = Disease.objects.get_or_create(
            disease_code=data[trial].get('diseases')[x].get('disease_code'),
            preferred_name=data[trial].get('diseases')[x].get('preferred_name'),
            display_name=data[trial].get('diseases')[x].get('display_name'))
        d.clinical_trials.add(ct.pk)
        d.save()