JawsIk
@JawsIk
Python Django, Lua, ЧПУ-станки(ArtCam, Aspire)

Как в Django сохранить поля только дочерней модели, и не затрагивать поля родительской модели?

У меня есть приложение «profile» и две модели: «Human» и «Client».
Модель «Human» расширяет встроенную модель «User».
А модель «Client» расширяет модель «Human».

from django.contrib.auth.models import User

class Human(User):
    city = models.CharField(max_length=100, blank=True)
    address = models.CharField(max_length=150, blank=True)
    phone = models.CharField(max_length=30, blank=True)

    def __str__(self):
        return "{0} ({1})".format(self.username, self.get_full_name())

class Client(Human):
    company = models.CharField(max_length=100, blank=True)
    discount = models.DecimalField(max_digits=4, decimal_places=2, default=15)
    
    def __str__(self):
        return "#{} : {} | {} ({})".format(self.id, self.username, self.get_full_name(), self.company)


Через Django shell, я добавляю новую запись в базу данных. Использую для этого дела дочерний класс Human:

from profile.models import Human
hu = Human(username='first', email='first@test.test', first_name='Mr.First', city='First City', phone="+9876543210")
hu.set_password('12345678')
hu.save()


В базе данных я вижу, что появились записи в таблицах auth_user и profile_human. Допустим им присвоился id = 3. (в auth_user он отображается как id, а в profile_human, как user_ptr_id)

Предположим, мой пользователь стал моим клиентом. И теперь мне нужно добавить дополнительные данные в модель Client (в таблицу profile_client).

Это не новый пользователь! Этот пользователь у меня уже есть. Информация о нём находится в двух таблицах (auth_user и profile_human). Но в таблице profile_client никаких записей про этого пользователя ещё нет.

Через Django shell, я создаю новый экземпляр модели Client:

from profile.models import Client
cli = Client(id=3, company='FST', discount=10.00)


Т.к. это существующий пользователь, то я указываю id=3

Если я пытаюсь сделать
cli.update()
я получаю ошибку, ибо в таблице profile_client нет ещё такой записи и поэтому вижу ошибку, что объект Client не имеет атрибута update.

Если я пытаюсь сохранить только указанные поля:
cli.save(update_fields=['company', 'discount'])
То я снова получаю ошибку, т.к. в таблице profile_client пока ведь нет ещё такой записи и поэтому приходит подсказка, мол попробуйте сохраниться без атрибута update_fields

Но если я сохраняюсь просто через:
cli.save()

Я конечно же получаю новую запись в таблице profile_client, и в ней нужные поля и даже нужный id (но в этой таблице он называется human_ptr_id), но при этом в других таблицах информация со всех полей обнуляется (становится пустой).

Т.е. теперь в таблицах auth_user и profile_human вся информация у пользователя с id = 3 стёрта. Напрочь.

Вопрос: Как при добавлении новой записи дочерней модели, сохранить поля только этой дочерней модели, не затрагивая при этом поля родительских моделей?

p.s. там конечно же полей на много больше, но для понимания код моделей упрощён.
  • Вопрос задан
  • 769 просмотров
Решения вопроса 1
JawsIk
@JawsIk Автор вопроса
Python Django, Lua, ЧПУ-станки(ArtCam, Aspire)
Вот за что я люблю Django, так это за то, что здесь очень всё удобно. Оказывается решением была очень простая штука. Жаль, что я так и не смог найти это в официальной документации (на мой взгляд документация сделана плохо).

Упрощённо ответив, решение будет таким:

from profile.models import Client
cli = Client(company = 'FST', discount=10.00, human_ptr_id=3)
cli.save_base(raw = True)


т.е. последняя строка как раз и делает то, что описано в вопросе. А вместо id пишем родитель_ptr_id. Все спасибо. Вопрос закрыт.
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 1
@FulTupFul
1. Наследование от from django.contrib.auth.models import User Это ОЧЕНЬ плохая практика. Не делайте так. Модель User это не абстрактная модель.
2. У вас три разных моделей, следовательно три разных таблицы. Никакой связности между ними нет.
3. Правильным решением будет переопределить модель User. Вот туториал для этого https://simpleisbetterthancomplex.com/tutorial/201...
Вам подойдет четвертый вариант. Тогда вы сможете избавиться от Human.
А модель Client связать с User через ForeignKey
class CustomUser(AbstractBaseUser, PermissionsMixin):
    # some fields
    # some methods

class Client(models.Model):
    user = models.ForeignKey("CustomUser", on_delete=models.CASCADE)
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы