def _create_or_update_reverse_related_object(self, data, key, data_item):
        model_descriptor = getattr(self.model, key)
        model = get_model_from_relation(self.model, key)
        field_name = get_reverse_field_name(self.model, key)
        resource = self._get_resource(model)
        if resource:
            related_obj = get_object_or_none(model,
                                             **{field_name: self.inst.pk})
            try:
                if data_item is None:
                    if related_obj:
                        self._delete_reverse_object(
                            {resource.pk_field_name: related_obj.pk}, model)
                    setattr(self.inst, model_descriptor.cache_name, None)
                else:
                    if not isinstance(data_item, dict):
                        obj_data = {
                            resource.pk_field_name: force_text(data_item)
                        }
                    else:
                        obj_data = data_item.copy()

                    if resource.pk_field_name not in obj_data and related_obj:
                        obj_data[resource.pk_field_name] = related_obj.pk
                    obj_data[field_name] = self.inst.pk
                    setattr(
                        self.inst, key,
                        self._create_or_update_related_object(obj_data, model))

            except DataInvalidException as ex:
                self.errors[key] = ex.errors
Beispiel #2
0
def reverse_related_fields_for_model(model, fields=None, exclude=None, resource_typemapper=None):
    """
    Generate reverse related fields for concrete model.
    """

    field_list = []
    opts = model._meta
    reverse_fields = [
        f for f in opts.get_fields()
        if (f.one_to_many or f.one_to_one or f.many_to_many)
        and f.auto_created and not f.concrete
    ]
    for f in reverse_fields:
        if fields is not None and f.name not in fields:
            continue
        if exclude and f.name in exclude:
            continue
        if not f.related_name:
            continue

        resource_class = get_resource_class(get_model_from_relation(model, f.name), resource_typemapper)

        if resource_class and (is_reverse_many_to_many(model, f.name) or is_reverse_many_to_one(model, f.name)):
            field_list.append((f.name, ReverseStructuredManyField(f.name, resource_class=resource_class)))
        elif resource_class and is_reverse_one_to_one(model, f.name):
            field_list.append((f.name, ReverseOneToOneField(f.name, resource_class=resource_class)))

    return OrderedDict(field_list)
Beispiel #3
0
 def _get_field_label_from_model_related_objects(self, model, field_name):
     for rel in get_all_related_objects_from_model(model):
         reverse_name = rel.get_accessor_name()
         if field_name == reverse_name:
             model = get_model_from_relation(model, field_name)
             if isinstance(rel.field, models.OneToOneField):
                 return model._meta.verbose_name
             else:
                 return model._meta.verbose_name_plural
     return None
Beispiel #4
0
 def _create_update_or_remove(self, parent_inst, data, via, request,
                              partial_update, form):
     model = get_model_from_relation(parent_inst.__class__,
                                     self.reverse_field_name)
     field_name = get_reverse_field_name(parent_inst.__class__,
                                         self.reverse_field_name)
     resource = self._get_resource(model, request)
     return self._update_reverse_related_objects(resource, model,
                                                 parent_inst, field_name,
                                                 via, data, partial_update)
Beispiel #5
0
 def _get_field_label_from_model_related_objects(self, model, field_name):
     for rel in get_all_related_objects_from_model(model):
         reverse_name = rel.get_accessor_name()
         if field_name == reverse_name:
             model = get_model_from_relation(model, field_name)
             if isinstance(rel.field, models.OneToOneField):
                 return model._meta.verbose_name
             else:
                 return model._meta.verbose_name_plural
     return None
Beispiel #6
0
 def create_update_or_remove(self, parent_inst, data, via, request, partial_update, form):
     model = get_model_from_relation(parent_inst.__class__, self.reverse_field_name)
     field_name = get_reverse_field_name(parent_inst.__class__, self.reverse_field_name)
     resource = self._get_resource(model, request)
     related_obj = self._get_obj_or_none(model, parent_inst, field_name)
     if data is None and related_obj:
         self._remove(resource, parent_inst, related_obj, field_name, via)
         return None
     elif data is not None:
         return self._create_or_update(resource, parent_inst, related_obj, field_name, via, data, partial_update)
Beispiel #7
0
    def test_get_model_from_relation(self):
        assert_equal(get_model_from_relation(Issue, 'watched_by'), User)
        assert_equal(get_model_from_relation(Issue, 'created_by'), User)
        assert_equal(get_model_from_relation(Issue, 'solver'), User)
        assert_equal(get_model_from_relation(Issue, 'leader'), User)
        assert_raises(FieldError, get_model_from_relation, Issue, 'name')
        assert_raises(FieldError, get_model_from_relation, Issue, 'created_at')
        assert_raises(FieldError, get_model_from_relation, Issue, 'invalid')

        assert_equal(get_model_from_relation(User, 'watched_issues'), Issue)
        assert_equal(get_model_from_relation(User, 'created_issues'), Issue)
        assert_equal(get_model_from_relation(User, 'solving_issue'), Issue)
        assert_equal(get_model_from_relation(User, 'leading_issue'), Issue)
 def _create_or_update_reverse_related_objects_remove(
         self, data, key, data_item):
     if isinstance(data, (tuple, list)):
         try:
             self._delete_reverse_objects(
                 data, get_model_from_relation(self.model, key))
         except DataInvalidException as ex:
             self._append_errors(key, 'remove', ex.errors)
     else:
         self._append_errors(key, 'remove',
                             self.INVALID_COLLECTION_EXCEPTION)
 def _create_or_update_reverse_related_objects_add(self, data, key,
                                                   data_item):
     model = get_model_from_relation(self.model, key)
     field_name = get_reverse_field_name(self.model, key)
     if isinstance(data, (tuple, list)):
         try:
             self._create_and_return_new_object_pk_list(
                 data, model, self.inst, field_name)
         except DataInvalidException as ex:
             self._append_errors(key, 'add', ex.errors)
     else:
         self._append_errors(key, 'add', self.INVALID_COLLECTION_EXCEPTION)
Beispiel #10
0
 def _process_field(self, data, files, key, data_item):
     rest_field = getattr(self.form, key, None)
     if (not rest_field and isinstance(self.form, RESTFormMixin) and self.form._rest_meta.auto_reverse and (
             is_reverse_many_to_many(self.model, key) or is_reverse_many_to_one(self.model, key))):
         resource_class = self._get_resource_class(get_model_from_relation(self.model, key))
         rest_field = ReverseStructuredManyField(key, resource_class=resource_class) if resource_class else None
     if isinstance(rest_field, ReverseManyField):
         try:
             data[key] = self.form.data[key] = rest_field.create_update_or_remove(
                 self.inst, data_item, self.via, self.request, self.partial_update, self.form
             )
         except DataInvalidException as ex:
             self.errors[key] = ex.errors
Beispiel #11
0
 def create_update_or_remove(self, parent_inst, data, via, request,
                             partial_update, form):
     model = get_model_from_relation(parent_inst.__class__,
                                     self.reverse_field_name)
     field_name = get_reverse_field_name(parent_inst.__class__,
                                         self.reverse_field_name)
     resource = self._get_resource(model, request)
     related_obj = self._get_obj_or_none(model, parent_inst, field_name)
     if data is None and related_obj:
         self._remove(resource, parent_inst, related_obj, field_name, via)
         return None
     elif data is not None:
         return self._create_or_update(resource, parent_inst, related_obj,
                                       field_name, via, data,
                                       partial_update)
 def _create_or_update_reverse_related_objects_set(self, data, key,
                                                   data_item):
     model = get_model_from_relation(self.model, key)
     field_name = get_reverse_field_name(self.model, key)
     resource = self._get_resource(model)
     if isinstance(data, (tuple, list)):
         try:
             new_object_pks = self._create_and_return_new_object_pk_list(
                 data, model, self.inst, field_name)
             # This is not optimal solution but is the most universal
             self._delete_reverse_objects(
                 resource._get_queryset().filter(**{
                     field_name: self.inst
                 }).exclude(pk__in=new_object_pks).values_list('pk',
                                                               flat=True),
                 model)
         except DataInvalidException as ex:
             self._append_errors(key, 'set', ex.errors)
     else:
         self._append_errors(key, 'set', self.INVALID_COLLECTION_EXCEPTION)
    def _create_or_update_reverse_related_objects(self, data, key, data_item):
        model = get_model_from_relation(self.model, key)
        field_name = get_reverse_field_name(self.model, key)
        resource = self._get_resource(model)
        if resource:
            if isinstance(data_item, list) or 'set' in data_item:
                set_data_item = data_item if isinstance(
                    data_item, list) else data_item.get('set')
                self._create_or_update_reverse_related_objects_set(
                    set_data_item, key, data_item)
            else:
                if 'remove' in data_item:
                    self._create_or_update_reverse_related_objects_remove(
                        data_item.get('remove'), key, data_item)
                if 'add' in data_item:
                    self._create_or_update_reverse_related_objects_add(
                        data_item.get('add'), key, data_item)

            try:
                del self.inst._prefetched_objects_cache[field_name]
            except (AttributeError, KeyError):
                pass
Beispiel #14
0
def reverse_related_fields_for_model(model,
                                     fields=None,
                                     exclude=None,
                                     resource_typemapper=None):
    """
    Generate reverse related fields for concrete model.
    """

    field_list = []
    opts = model._meta
    reverse_fields = [
        f for f in opts.get_fields()
        if (f.one_to_many or f.one_to_one or f.many_to_many) and f.auto_created
        and not f.concrete
    ]
    for f in reverse_fields:
        if fields is not None and f.name not in fields:
            continue
        if exclude and f.name in exclude:
            continue
        if not f.related_name:
            continue

        resource_class = get_resource_class(
            get_model_from_relation(model, f.name), resource_typemapper)

        if resource_class and (is_reverse_many_to_many(model, f.name)
                               or is_reverse_many_to_one(model, f.name)):
            field_list.append(
                (f.name,
                 ReverseStructuredManyField(f.name,
                                            resource_class=resource_class)))
        elif resource_class and is_reverse_one_to_one(model, f.name):
            field_list.append(
                (f.name,
                 ReverseOneToOneField(f.name, resource_class=resource_class)))

    return OrderedDict(field_list)
Beispiel #15
0
 def _get_model(self, parent_inst):
     return get_model_from_relation(parent_inst.__class__,
                                    self.reverse_field_name)
Beispiel #16
0
 def create_update_or_remove(self, parent_inst, data, via, request, partial_update, form):
     model = get_model_from_relation(parent_inst.__class__, self.reverse_field_name)
     field_name = get_reverse_field_name(parent_inst.__class__, self.reverse_field_name)
     resource = self._get_resource(model, request)
     return self._update_reverse_related_objects(resource, model, parent_inst, field_name, via, data, partial_update)