AttributeError: объект '_io.BufferedWriter' не имеет атрибута 'save'

Я пытаюсь сохранить следующий файл

Вот модель:

class someModel(models.Model):
    someFile = models.FileField(storage=someModule(), blank=True)

Вот как я создаю файл, который хочу сохранить:

flat_array = array.flatten(order="F")

with open(filename, "wb") as some_transformed_file:

    some_transformed_file.write(struct.pack(">i", 192837465))
    some_transformed_file.write(flat_array[i].real)

return some_transformed_file

Вот спасительная часть:

doc_io = BytesIO()
some_transformed_file.save(doc_io)
some_file_object = File(doc_io, filename=os.path.basename(name))

item = someModel.objects.create(someFile=some_file_object )

Я получаю ошибку

AttributeError: '_io.BufferedWriter' object has no attribute 'save'

>

На самом деле, ваши пользовательские методы create_usercreate_superuser, которые вы, вероятно, также переписали) не вызываются при создании нового пользователя из панели администратора. Я не совсем понимаю почему, но думаю, что функция create_user - это просто ярлык.

Почему бы не переопределить save() метод вашего CustomUser? Из документации Django:

Классический случай использования переопределения встроенных методов - если вы хотите, чтобы что-то происходило всякий раз, когда вы сохраняете объект.

Не совсем то, что вы ищете? Посмотрите документацию Django здесь (чтобы сделать это на уровне формы) и здесь (если вы предпочитаете изменять непосредственно саму модель, независимо от того, какая форма используется) для получения дополнительной информации.

Например, если вы предпочитаете второй вариант, вы можете добавить этот метод в CustomUser:

from django.apps.apps import get_model
from django.db import transaction

class CustomUser(AbstractUser):

    # your initial code goes here ...

    def save(self, *args, **kwargs):
        # make the distinction between the creation and the update of the instance
        if not self._state.adding:
               # doesn't change the initial method if the user has already been saved in DB
               return super(CustomUser, self).save(*args, **kwargs)
        # guarantee of atomicity
        with transaction.atomic():
                # dynamic resolution to avoid a circular import, might not be necessary
                customer = get_model("stripe", "Customer").create(
                    email=self.email,
                    name=self.name,
                )
                self.stripe_customer_id = customer.id
                super(CustomUser, self).save(*args, **kwargs)
                return self

Не забывайте делать различие между созданием и обновлением экземпляра.

UserAdmin полагается на реализацию в ModelAdmin для создания экземпляра, проверки формы, а затем сохранения экземпляра, а не вызова пользовательского метода в менеджере модели.

Цепочка вызовов: ModelAdmin.add_view() → ... → self._changeform_view(), которая вызывает:

  • (i) form.is_valid() (из ModelForm) → ... → self._post_clean()self.instance = construct_instance(...),
  • (ii) self.save_form(...)new_object = form.save(commit=False) (из BaseModelForm) возвращая self.instance, и
  • (iii) self.save_model(..., new_object, ...)obj.save().

Вы можете переопределить ModelAdmin.save_form для вызова метода create_user пользовательского менеджера пользователей и заменить form.instance:

class CustomUserAdmin(UserAdmin):
    model = CustomUser
    fieldsets = (
        (None, {'fields': (model.USERNAME_FIELD, 'name', 'password')}),
    ) + UserAdmin.fieldsets[2:]
    add_fieldsets = (
        (None, {'fields': (model.USERNAME_FIELD, 'name', 'password1', 'password2')}),
    )
    ordering = (model.USERNAME_FIELD,)

    def save_form(self, request, form, change):
        if not change:
            form.instance = self.model.objects.create_user(
                form.cleaned_data['email'],
                form.cleaned_data['password1'],
                form.cleaned_data['name'],
            )
        return super().save_form(request, form, change)

⚠️ Заметьте в обычной цепочке вызовов, что save_form() не вызывает obj.save(), так как ModelAdmin обрабатывает множественные наборы форм и m2m модели, в то время как CustomUserManager.create_user вызывает user.save(). Можно изменить это поведение в UserAdmin с известной областью применения, хотя вы можете рассмотреть возможность разделения CustomUserManager.create_user на CustomUserManager.construct_instance и CustomUserManager.save_new_model (перенести stripe.Customer.create(...) и user.save() сюда).

Вернуться на верх