Django - обновлять поля внутри объекта модели django, используя kwargs - PullRequest
0 голосов
/ 01 июня 2018

Я искал простой ответ на этот вопрос, но не смог его найти.
Этот вопрос несколько похож на него, но не совсем так, вот он.

Допустим, у меня есть собственный метод обновления внутри моей модели Django.

class People(models.Model):
    identifier = models.CharField(max_length=255, primary_key = True)
    name = models.CharField(max_length=255)
    house = model.ForeignKey(House)
    salary = model.IntegerField()

    def my_fancy_update(self, **kwargs):
        # Here I want to do my update
        pass

Что я хочу сделать, это использовать kwargs для обновления моей модели.
Сейчас я использую следующее:

def my_fancy_update(self, **kwargs):
    self.name = kwargs.get('name')
    self.house = kwargs.get('house')
    self.salary = kwargs.get('salary')
    self.save()

Это то, что похоже на то, что я действительно хочу сделать:

def my_fancy_update(self, **kwargs):
    self.update(**kwargs)

self.update не работает, возникает ошибка:
AttributeError: 'People' object has no attribute 'update'

Также self.objects.update невозможно из-за того, что менеджер недоступен при использовании self.

Теперь у меня вопрос, возможно ли это и как это возможно?сделано в Django.
Это экономит мне много времени, перечисляя каждый атрибут в моих реальных моделях.

Ответы [ 2 ]

0 голосов
/ 01 июня 2018

Обратите внимание, что ваше текущее решение:

def my_fancy_update(self, **kwargs):
    self.name = kwargs.get('name')
    self.house = kwargs.get('house')
    self.salary = kwargs.get('salary')
    self.save()

очень хрупкое, поскольку оно может установить любое имя, дом и зарплату на None.

Первое чистое решение будетиспользовать цикл for иладка:

def my_fancy_update(self, **kwargs):
    for name, value in kwargs.items():
        setattr(self, name, value)
    self.save()

, но это все еще хрупко, поскольку он не проверяет, что переданные имена на самом деле являются именами полей модели.Более безопасная реализация будет использовать self._meta.get_fields() для проверки этого:

def my_fancy_update(self, **kwargs):
    fieldnames = set(f.name for f in self._meta.get_fields())
    for name, value in kwargs.items():
        if name not in fieldnames:
            raise ValueError("%s is not a field of %s" % (name, type(self).__name__))
        setattr(self, name, value)
    self.save()

и, наконец, вы можете избежать вызова save(), если ничего не было обновлено, и фиксировать только то, что было действительно обновлено:

def my_fancy_update(self, **kwargs):
    if not kwargs:
        return

    fieldnames = set(f.name for f in self._meta.get_fields())
    updated = []
    for name, value in kwargs.items():
        if name not in fieldnames:
            raise ValueError("%s is not a field of %s" % (name, type(self).__name__))
        setattr(self, name, value)
        updated.append(name)
    self.save(update_fields=updated)
0 голосов
/ 01 июня 2018

Мы можем перебирать атрибуты и обновлять значения, затем мы вызываем функцию .save():

def my_fancy_update(self, **kwargs):
    <b>for k, v in kwargs.items():
        setattr(self, k, v)</b>
    self.save()

Это, однако, установит атрибуты вручную, поэтому возможно, что есть некоторые сигналы, триггеры и т. д., которые будут обновлять и очищать значения.

setattr(..) - это функция Python, такая что setattr(x, 'y', z) эквивалентна x.y = z (обратите внимание, что мы передаем 'y' в виде строкив setattr(..).

Также невозможно обновить атрибуты, такие как related_field__attribute и т. д.

...