Ejemplo n.º 1
0
def get_property_customization_by_fn(fn, current_model_customization):
    """
    returns the 1st matching QPropertyCustomization in the customization hierarchy...
    if the top-level property_customization matches, this is simple
    if the cusotmizations are existing (ie: already saved), this is straightforward
    if the customizations are new (ie: not saved), this is icky
    :param fn: fn to use to find customization
    :param current_model_customization: customizations to check
    :return: QPropertyCustomization
    """
    # RECALL THAT AS OF v0.16.0.0 INSTEAD OF PASSING A COMPLEX NESTED DICTIONARY
    # I AM JUST PASSING A SINGLE model_customization INSTANCE W/ ALL ITS M2M FIELDS ALREADY COMPLETE

    property_customization = find_in_sequence(
        fn,
        current_model_customization.property_customizations(manager="allow_unsaved_property_customizations_manager").all()
    )
    if property_customization:
        return property_customization

    if current_model_customization.is_new():
        return get_customization_by_fn_recusively(
            fn,
            current_model_customization.property_customizations(manager="allow_unsaved_property_customizations_manager").all(),
            CustomizationTypes.PROPERTY,
        )
    else:  # current_model_customization.is_existing()
        return find_in_sequence(
            fn,
            QPropertyCustomization.objects.filter(
                model_customization__project=current_model_customization.project,
                name=current_model_customization.name,
            )
        )
Ejemplo n.º 2
0
def get_customization_by_fn_recusively(fn, current_property_customizations, customization_type, **kwargs):
    """
    used in conjunction w/ the "get_<x>_customization_by_fn" fns above
    recursively goes through the customization hierarchy (of unsaved customizations)
    returns the first customization that returns True for fn
    :param fn: fn to call
    :param property_customizations: the property customizations from which to begin checking
    :param customization_type: the type of customization to check
    :return: either QModelCustomization or QCategoryCustomization or QPropertyCustomization or None
    """

    previously_recursed_customizations = kwargs.pop("previously_recursed_customizations", set())

    for property_customization in current_property_customizations:
        property_customization_key = property_customization.get_key()
        if property_customization_key not in previously_recursed_customizations:
            if customization_type == CustomizationTypes.PROPERTY and fn(property_customization):
                return property_customization

            if property_customization.use_subforms():
                target_model_customizations = property_customization.relationship_target_model_customizations(manager="allow_unsaved_relationship_target_model_customizations_manager").all()
                for target_model_customization in target_model_customizations:

                    if customization_type == CustomizationTypes.MODEL:
                        if fn(target_model_customization):
                            return target_model_customization

                    elif customization_type == CustomizationTypes.CATEGORY:
                        target_category_customization = find_in_sequence(
                            fn,
                            target_model_customization.category_customizations(manager="allow_unsaved_category_customizations_manager").all()

                        )
                        if target_category_customization:
                            return target_category_customization

                    else:  # customization_type == CustomizationTypes.PROPERTY
                        pass  # (this will already have been checked above)

                    previously_recursed_customizations.add(property_customization_key)  # only tracking property_customizations b/c those are the only recursive things
                    matching_customization = get_customization_by_fn_recusively(
                        fn,
                        target_model_customization.property_customizations(manager="allow_unsaved_property_customizations_manager").all(),
                        customization_type,
                        previously_recursed_customizations=previously_recursed_customizations,
                    )
                    if matching_customization:
                        return matching_customization
    def parse_ontology_content_property(self, ontology_content, new_property_proxy_order, model_proxy):

        new_property_proxy_name = ontology_content["name"]
        new_property_proxy_id = ontology_content.get("id")
        new_property_proxy_field_type = QPropertyTypes.get(ontology_content["property_type"])
        assert new_property_proxy_field_type is not None, "invalid property_type specified"

        (new_property_proxy, created_property_proxy) = QPropertyProxy.objects.get_or_create(
            # these fields are the "defining" ones (other fields can change below w/out creating new proxies)
            ontology=self,
            model_proxy=model_proxy,
            name=new_property_proxy_name,
            cim_id=new_property_proxy_id,
            field_type=new_property_proxy_field_type,
        )

        category_id = ontology_content.get("category_id")
        new_property_proxy.category_id = category_id
        new_property_proxy.category_proxy = find_in_sequence(lambda c: c.cim_id == category_id, model_proxy.category_proxies.all())

        new_property_proxy.order = new_property_proxy_order
        new_property_proxy.is_meta = ontology_content.get("is_meta", False)
        new_property_proxy.is_nillable = ontology_content.get("is_nillable", False)
        new_property_proxy.is_hierarchical = ontology_content.get("is_hierarchical", False)
        new_property_proxy_documentation = ontology_content.get("documentation")
        if new_property_proxy_documentation:
            new_property_proxy.documentation = remove_spaces_and_linebreaks(new_property_proxy_documentation)
        new_property_proxy_cardinality = re.split("\.|,", ontology_content.get("cardinality"))  # TODO: DECIDE ONCE-AND-FOR-ALL IF "cardinality" IS SPLIT ON '.' OR ','
        new_property_proxy.cardinality_min = new_property_proxy_cardinality[0]
        new_property_proxy.cardinality_max = new_property_proxy_cardinality[1]
        new_property_proxy.values = ontology_content.get("values")
        if new_property_proxy_field_type == QPropertyTypes.ATOMIC:
            new_property_proxy_atomic_type_type = ontology_content.get("atomic_type")
            if new_property_proxy_atomic_type_type == "STRING":
                new_property_proxy_atomic_type_type = "DEFAULT"
            new_property_proxy_atomic_type = QAtomicTypes.get(new_property_proxy_atomic_type_type)
            assert new_property_proxy_atomic_type is not None, "invalid atomic_type specified"
            new_property_proxy.atomic_type = new_property_proxy_atomic_type
        elif new_property_proxy_field_type == QPropertyTypes.ENUMERATION:
            new_property_proxy.enumeration_is_open = ontology_content.get("enumeration_is_open")
            new_property_proxy.enumeration_choices = ontology_content.get("enumeration_members")
        else:  # new_property_proxy_field_type == QPropertyTypes.RELATIONSHIP
            new_property_proxy.relationship_target_names = ontology_content.get("relationship_targets")  # target_names are set now; target_models are set later in  "QPropertyProxy.reset"

        new_property_proxy.save()

        return new_property_proxy
    def __init__(self, *args, **kwargs):

        # customizers was passed in via curry() in the factory function below
        customizers = kwargs.pop("customizers", None)

        # RIGHT, THIS CAUSED AN AWFUL LOT OF CONFUSION
        # THE CALL TO super() CAN TAKE A "customizer" ARGUMENT
        # BUT I CAN ONLY FIND THAT CUSTOMIZER BY MATCHING IT AGAINST THE VALUE OF "proxy"
        # THAT REQUIRES CALLING get_current_field_value() WHICH CHECKS THE PREFIX OF A FORM
        # BUT THAT PREFIX - AND SOME OTHER THINGS TOO - IS ONLY SET FROM DEEP W/IN THE __init__ FN
        # OF A BASE CLASS; SO I CALL super FIRST W/OUT A "customizer" ARGUMENT AND THEN CUSTOMIZE
        # AT THE END OF THIS __init__ FN

        super(MetadataScientificPropertyForm, self).__init__(*args, **kwargs)

        if customizers:
            proxy_pk = int(self.get_current_field_value("proxy"))
            customizer = find_in_sequence(lambda c: c.proxy.pk == proxy_pk, customizers)
            assert(customizer.name == self.get_current_field_value("name"))  # this is new code; just make sure it works
        else:
            customizer = None

        is_enumeration = self.get_current_field_value("is_enumeration", False)

        if self.instance.pk and is_enumeration:
            # ordinarily, this is done in create_scientific_property_form_data above
            # but if this is an existing model, I still need to do this jiggery-pokery someplace
            current_enumeration_value = self.get_current_field_value("enumeration_value")
            if isinstance(current_enumeration_value, basestring) and customizer.enumeration_multi:
                self.initial["enumeration_value"] = current_enumeration_value.split("|")

        if not is_enumeration:
            update_field_widget_attributes(self.fields["atomic_value"], {"onchange": "copy_value(this,'%s-scientific_property_value');" % self.prefix})
            update_field_widget_attributes(self.fields["atomic_value"], {"class": "atomic_value changer"})
        else:
            # this is handled via the "multiselect" widget in JS rather than here (b/c the widget is created dynamically via JS and has no _standard_ onchange event)
            # update_field_widget_attributes(self.fields["enumeration_value"], {"onchange": "copy_value(this,'%s-scientific_property_value');" % self.prefix})
            update_field_widget_attributes(self.fields["enumeration_value"], {"class": "multiselect"})

        if customizer:
            # HUH, WHY AM I CALLING THIS EXPLICITLY HERE, WHEN IT OUGHT TO BE CALLED AUTOMATICALLY IN super() ABOVE?
            # B/C customizer IS NOT PASSED TO super() B/C IT NEEDS TO BE FOUND BASED ON THE CURRENT PROXY
            # WHICH GETS RETURNED BY get_current_field_value()
            # WHICH HAS TO HAVE THIS FORM MOSTLY SET UP BEFORE IT WILL WORK
            # WHICH HAPPENS IN THE CALL TO super()
            # (SEE ABOVE)
            self.customize(customizer)
def get_realization_by_fn(fn, current_model_realization, realization_types, **kwargs):
    """
    just like the above fn, except it returns the first realization for which fn returns true
    :param fn: fn to call
    :param current_model_realization: the model customization from which to begin checking
    :param realization_types: the types of customizations to check
    :return: either QModelRealization or QCategoryRealization or QPropertyRealization or None
    """

    previously_recursed_realizations = kwargs.pop("previously_recursed_realizations", set())

    if RealizationTypes.MODEL in realization_types:
        if fn(current_model_realization):
            return current_model_realization

    if RealizationTypes.CATEGORY in realization_types:
        category_realization = find_in_sequence(
            fn,
            current_model_realization.categories(manager="allow_unsaved_categories_manager").all()
        )
        if category_realization:
            return category_realization

    for property_realization in current_model_realization.properties(manager="allow_unsaved_properties_manager").all():
        property_realization_key = property_realization.key
        if property_realization_key not in previously_recursed_realizations:

            if RealizationTypes.PROPERTY in realization_types and fn(property_realization):
                return property_realization

            if property_realization.field_type == QPropertyTypes.RELATIONSHIP:
                previously_recursed_realizations.add(property_realization_key)
                target_model_realizations = property_realization.relationship_values(manager="allow_unsaved_relationship_values_manager").all()
                for target_model_realization in target_model_realizations:
                    matching_realization = get_realization_by_fn(
                        fn,
                        target_model_realization,
                        realization_types,
                        previously_recursed_realizations=previously_recursed_realizations,
                    )
                    if matching_realization:  # break out of the loop as soon as I find a match
                        return matching_realization
def save_valid_model_formset(model_formset, model_parent_dictionary={}):

    # just save everything, regardless of whether it was loaded or not
    # (all of the logic of dealing w/ non-loaded forms is dealt with in the creation & validation fns)
    # loaded_model_forms = model_formset.get_loaded_forms()
    model_forms = model_formset.forms

    # force model_formset to save instances even if they haven't changed
    # TODO: MAKE THE commit KWARG CONDITIONAL ON WHETHER THE FORM CHANGED (OR IS NEW) TO CUT DOWN ON DB HITS
    # TODO: (NOTE, I'LL HAVE TO CHANGE THE LOOP BELOW ONCE I'VE DONE THIS)
    model_instances = [model_form.save(commit=True) for model_form in model_forms]

    for model_instance in model_instances:
        try:
            model_parent_key = model_parent_dictionary[model_instance.get_model_key()]
            model_instance.parent = find_in_sequence(lambda m: m.get_model_key() == model_parent_key, model_instances)
        except KeyError:
            pass  # maybe this model didn't have a parent (or the dict was never passed to this fn)
        model_instance.save(increment_version=False)

    return model_instances
def get_new_customization_set(project=None, ontology=None, proxy=None, vocabularies=[]):
    """

    """

    model_customization = QModelCustomization(ontology=ontology, proxy=proxy, project=project)
    model_customization.reset(proxy)

    vocabulary_customizations = []
    for i, vocabulary in enumerate(vocabularies):
        with allow_unsaved_fk(QModelCustomizationVocabulary, ["model_customization"]):
            vocabulary_customization = QModelCustomizationVocabulary(
                model_customization=model_customization, vocabulary=vocabulary, order=i + 1, active=True
            )
        vocabulary_customizations.append(vocabulary_customization)

    standard_category_customizations = []
    for standard_category_proxy in ontology.categorization.category_proxies.all():
        with allow_unsaved_fk(QStandardCategoryCustomization, ["model_customization"]):
            standard_category_customization = QStandardCategoryCustomization(
                model_customization=model_customization, proxy=standard_category_proxy
            )
            standard_category_customization.reset(standard_category_proxy)
        standard_category_customizations.append(standard_category_customization)

    standard_property_customizations = []
    for standard_property_proxy in proxy.standard_properties.all():
        with allow_unsaved_fk(
            QStandardPropertyCustomization, ["model_customization", "category", "relationship_subform_customization"]
        ):
            standard_property_customization = QStandardPropertyCustomization(
                model_customization=model_customization,
                proxy=standard_property_proxy,
                category=find_in_sequence(
                    lambda category: category.proxy.has_property(standard_property_proxy),
                    standard_category_customizations,
                ),
            )
            standard_property_customization.reset(standard_property_proxy)
            # HERE BEGINS THE SUBFORM BIT
            if standard_property_customization.use_subform():
                subform_customization_set = get_new_customization_set(
                    project=project,
                    ontology=ontology,
                    proxy=standard_property_proxy.relationship_target_model,
                    vocabularies=[],  # NO VOCABULARIES USED IN SUBFORMS ?
                )
                standard_property_customization.relationship_subform_customization = subform_customization_set[
                    "model_customization"
                ]
                # this is important; I do not have access to unsaved m2m fields, but I can set an attribute on the instance
                standard_property_customization.relationship_subform_customization_set = subform_customization_set
            # HERE ENDS THE SUBFORM BIT
        standard_property_customizations.append(standard_property_customization)

    scientific_category_customizations = []
    scientific_property_customizations = []
    for vocabulary in vocabularies:
        vocabulary_key = vocabulary.get_key()
        for component in vocabulary.component_proxies.all():
            component_key = component.get_key()
            n_categories = len(scientific_category_customizations)
            for scientific_category_proxy in component.category_proxies.all():
                with allow_unsaved_fk(QScientificCategoryCustomization, ["model_customization"]):
                    scientific_category_customization = QScientificCategoryCustomization(
                        model_customization=model_customization,
                        proxy=scientific_category_proxy,
                        vocabulary_key=vocabulary_key,
                        component_key=component_key,
                    )
                    scientific_category_customization.reset(scientific_category_proxy, reset_keys=False)
                scientific_category_customizations.append(scientific_category_customization)
            n_properties = len(scientific_property_customizations)
            for scientific_property_proxy in component.scientific_property_proxies.all():
                with allow_unsaved_fk(QScientificPropertyCustomization, ["category", "model_customization"]):
                    scientific_property_customization = QScientificPropertyCustomization(
                        model_customization=model_customization,
                        proxy=scientific_property_proxy,
                        vocabulary_key=vocabulary_key,
                        component_key=component_key,
                        category=find_in_sequence(
                            lambda category: category.proxy.has_property(scientific_property_proxy),
                            scientific_category_customizations[n_categories - 1 :],
                        ),  # ignore the previous categories
                    )
                    scientific_property_customization.reset(scientific_property_proxy, reset_keys=False)
                scientific_property_customizations.append(scientific_property_customization)

    customization_set = {
        "model_customization": model_customization,
        "vocabulary_customizations": vocabulary_customizations,
        "standard_category_customizations": standard_category_customizations,
        "standard_property_customizations": standard_property_customizations,
        "scientific_category_customizations": scientific_category_customizations,
        "scientific_property_customizations": scientific_property_customizations,
    }

    return customization_set
def get_new_realizations(project=None, ontology=None, model_proxy=None, **kwargs):
    # unlike w/ customizations, I do not create the entire possible set all at once
    # instead I just deal w/ the minimum number of properties (based on cardinality)
    # infinite recursion is therefore avoided; not by re-using previously created models
    # as with customizations, but by only creating a finite amount of models
    # hooray!

    parent_property = kwargs.pop("parent_property", None)
    if parent_property is not None:
        is_active = parent_property.is_required
    else:
        is_active = True
    model_realization = QModelRealization(
        project=project,
        proxy=model_proxy,
        version="0.0.0",
        is_active=is_active
    )
    model_realization.reset()

    category_realizations = []
    # TODO: IS THERE A MORE EFFICIENT WAY TO DO THIS?
    # gets _all_ of the categories that are relevant to this model...
    used_category_proxies = [p.category_proxy for p in model_proxy.property_proxies.all()]
    category_proxies = set(model_proxy.category_proxies.all())
    category_proxies.update(used_category_proxies)
    # for category_proxy in model_proxy.category_proxies.all():
    for category_proxy_order, category_proxy in enumerate(category_proxies):
        with allow_unsaved_fk(QCategoryRealization, ["model"]):
            category_realization = QCategoryRealization(
                proxy=category_proxy,
                model=model_realization,
                order=category_proxy_order,
            )
            category_realization.reset()
        category_realizations.append(category_realization)
    model_realization.categories(manager="allow_unsaved_categories_manager").add_potentially_unsaved(*category_realizations)

    property_realizations = []
    for property_proxy_order, property_proxy in enumerate(model_proxy.property_proxies.all()):
        property_category_realization = find_in_sequence(
            lambda c: c.proxy == property_proxy.category_proxy,
            category_realizations
        )
        with allow_unsaved_fk(QPropertyRealization, ["model", "category"]):
            property_realization = QPropertyRealization(
                proxy=property_proxy,
                field_type=property_proxy.field_type,    # TODO: I AM HAVING TO PASS "field_type" SO THAT IT'S SET IN "__init__" IN ORDER TO SETUP ANY ENUMERATIONS;
                model=model_realization,                 # TODO: AN ALTERNATIVE WOULD BE TO CALL "reset" FROM "__init__" WHENEVER "is_new" IS True.
                category=property_category_realization,
                order=property_proxy_order,
            )
            property_realization.reset()
            property_category_realization.properties(manager="allow_unsaved_category_properties_manager").add_potentially_unsaved(property_realization)
            # here begins the icky bit
            if property_realization.field_type == QPropertyTypes.RELATIONSHIP and property_realization.is_hierarchical:  # property_realization.is_required:
                target_relationship_values = []
                # TODO: IF I WERE TO PRE-CREATE ALL RELATIONSHIPS THEN HERE IS WHERE I WOULD DO IT
                # TODO: BUT THAT WOULD BE MIND-BOGGLINGLY COMPLEX...
                # TODO: ...B/C I WOULD NEED TO KNOW IN ADVANCE WHAT TYPES OF RELATIONSHIPS TO CREATE IN THE CASE OF MULTIPLE TYPES OF TARGETS;
                # TODO: AS IT IS, I GET AROUND THIS BY ONLY PRE-CREATING SPECIALIZATIONS WHICH ARE EXPLICIT IN THEIR TARGET PROXIES
                # TODO: BUT I STILL CANNOT HANDLE THIS FOR NON-SPECIALIZED PROXIES
                if property_realization.has_specialized_values:

                    # assert property_realization.cardinality_min == len(property_proxy.values)

                    for target_model_proxy_id in property_proxy.values:
                        target_model_proxy = property_proxy.relationship_target_models.get(cim_id=target_model_proxy_id)
                        kwargs.update({"parent_property": property_realization})
                        with allow_unsaved_fk(QModelRealization, ["relationship_property"]):  # this lets me access the parent property of a model
                            new_model_realization = get_new_realizations(
                                project=project,
                                ontology=target_model_proxy.ontology,
                                model_proxy=target_model_proxy,
                                **kwargs
                            )
                            new_model_realization.relationship_property = property_realization
                        target_relationship_values.append(new_model_realization)
                    property_realization.relationship_values(manager="allow_unsaved_relationship_values_manager").add_potentially_unsaved(*target_relationship_values)

                # here ends the icky bit
        property_realizations.append(property_realization)
    model_realization.properties(manager="allow_unsaved_properties_manager").add_potentially_unsaved(*property_realizations)

    return model_realization
Ejemplo n.º 9
0
def get_new_customizations(project=None, ontology=None, model_proxy=None, **kwargs):

    key = kwargs.pop("key")
    customizations = kwargs.pop("customizations", {})

    # TODO: CHANGE THIS TO USE GUIDS INSTEAD OF NAMES FOR KEYS
    # TODO: TRY TO REWRITE THIS TO USE "prefix" AGAIN (INSTEAD OF EXPLICIT "key")

    model_proxy_key = key
    if model_proxy_key not in customizations:
        model_customization = QModelCustomization(
            project=project,
            ontology=ontology,
            proxy=model_proxy,
        )
        model_customization.reset()
        customizations[model_proxy_key] = model_customization
    else:
        model_customization = customizations[model_proxy_key]

    category_customizations = []
    for catgegory_proxy in ontology.categorization.category_proxies.all():
        category_proxy_key = "{0}.{1}".format(model_proxy_key, catgegory_proxy.name)
        with allow_unsaved_fk(QCategoryCustomization, ["model_customization"]):
            if category_proxy_key not in customizations:
                category_customization = QCategoryCustomization(
                    proxy=catgegory_proxy,
                    model_customization=model_customization,
                )
                category_customization.reset()
                customizations[category_proxy_key] = category_customization
            else:
                category_customization = customizations[category_proxy_key]
        category_customizations.append(category_customization)
    # assert category_customizations[-1].proxy == ontology.categorization.get_uncategorized_category_proxy()
    model_customization.category_customizations(manager="allow_unsaved_category_customizations_manager").add_potentially_unsaved(*category_customizations)

    property_customizations = []
    for property_proxy in model_proxy.property_proxies.all():
        property_proxy_key = "{0}.{1}".format(model_proxy_key, property_proxy.name)
        with allow_unsaved_fk(QPropertyCustomization, ["model_customization", "category"]):
            # close this context manager before using the custom related manager
            # (too much hackery at once)
            if property_proxy_key not in customizations:
                category_customization = find_in_sequence(
                    lambda c: c.proxy.has_property(property_proxy),
                    category_customizations
                )
                property_customization = QPropertyCustomization(
                    proxy=property_proxy,
                    model_customization=model_customization,
                    category=category_customization,
                )
                property_customization.reset()
                category_customization.property_customizations(manager="allow_unsaved_categories_manager").add_potentially_unsaved(property_customization)
                customizations[property_proxy_key] = property_customization
            else:
                property_customization = customizations[property_proxy_key]
        property_customizations.append(property_customization)

        ############################
        # here begins the icky bit #
        ############################

        if property_customization.use_subforms():
            subform_key = "{0}.{1}".format(model_proxy.name, property_proxy.name)  # this property in this model (only 1 level deep)
            target_model_customizations = []
            for target_model_proxy in property_proxy.relationship_target_models.all():
                target_model_proxy_key = "{0}.{1}".format(subform_key, target_model_proxy.name)
                if target_model_proxy_key not in customizations:
                    target_model_customization = get_new_customizations(
                        project=project,
                        ontology=ontology,
                        model_proxy=target_model_proxy,
                        key=target_model_proxy_key,
                        customizations=customizations,
                    )
                else:
                    target_model_customization = customizations[target_model_proxy_key]

                target_model_customizations.append(target_model_customization)
            property_customization.relationship_target_model_customizations(manager="allow_unsaved_relationship_target_model_customizations_manager").add_potentially_unsaved(*target_model_customizations)

        ##########################
        # here ends the icky bit #
        ##########################

        model_customization.property_customizations(manager="allow_unsaved_property_customizations_manager").add_potentially_unsaved(*property_customizations)

    return customizations[model_proxy_key]
    def update(self, model_customization):
        """
        looks through the customization and checks if any standard or scientific properties
        which should be displayed are missing,
        or which shouldn't be displayed are still there (?)
        :param model_customization:
        :return:
        """
        standard_properties = self.standard_properties.all()
        standard_property_customizations = model_customization.standard_property_customizers.all()
        for standard_property_customization in standard_property_customizations:
            standard_property_proxy = standard_property_customization.proxy
            standard_property = find_in_sequence(lambda sp: standard_property_proxy == sp.proxy, standard_properties)

            if standard_property_customization.displayed:

                field_type = standard_property_customization.field_type

                # if there is no standard property, create it...
                if not standard_property:
                    new_standard_property = MetadataStandardProperty(
                        proxy=standard_property_proxy,
                        model=self,
                    )
                    new_standard_property.reset()
                    # and if there is a default value, then set it...
                    if field_type == MetadataFieldTypes.ATOMIC and standard_property_customization.default_value:
                        new_standard_property.atomic_value = standard_property_customization.default_value
                    elif field_type == MetadataFieldTypes.ENUMERATION and standard_property_customization.enumeration_default:
                        new_standard_property.enumeration_value = standard_property_customization.enumeration_default
                    new_standard_property.save()
                    standard_property = new_standard_property

                if field_type == "RELATIONSHIP":
                    # recurse through subforms...
                    for submodel in standard_property.relationship_value.all():
                        submodel_customizer = standard_property_customization.subform_customizer
                        if submodel_customizer:
                            submodel.update(submodel_customizer)

            else:  # not standard_property_customization.displayed

                # if there is a standard property, delete it...
                if standard_property:
                    # TODO: RE-VISIT THIS LOGIC; EVENTUALLY, I DON'T WANT TO DELETE PROPERTIES
                    standard_property.delete()

        # do the same basic thing, but w/ scientific properties
        # TODO: THIS SEEMS LIKE PRETTY INEFFICIENT CODE, ANY WAY TO SPEED THIS UP
        scientific_properties = self.scientific_properties.all()
        scientific_property_customizations = model_customization.scientific_property_customizers.filter(
            vocabulary_key=self.vocabulary_key,
            component_key=self.component_key,
        )
        for scientific_property_customization in scientific_property_customizations:
            scientific_property_proxy = scientific_property_customization.proxy
            scientific_property = find_in_sequence(lambda sp: sp.proxy == scientific_property_proxy, scientific_properties)

            if scientific_property_customization.displayed:

                # if there is no scientific property, create it...
                if not scientific_property:
                    new_scientific_property = MetadataScientificProperty(
                        proxy=scientific_property_proxy,
                        model=self,
                    )
                    new_scientific_property.reset()
                    new_scientific_property.save()

            else:  # not scientific_property_customization.displayed

                # if there is a scientific property, delete it...
                if scientific_property:
                    # TODO: RE-VISIT THIS LOGIC; EVENTUALLY, I DON'T WANT TO DELETE PROPERTIES
                    scientific_property.delete()
 def get_label(self):
     label_property = find_in_sequence(lambda property: property.is_label == True, self.standard_properties.all())
     if label_property:
         return u"%s" % label_property.get_value()
     else:
         return None