Nano Hash - криптовалюты, майнинг, программирование

Django: доступ к объектам ManyToManyField после сохранения

Это меня сбивает с толку... Когда я сохраняю свою модель, объекты книги не изменяются. Но если я открою счет-фактуру и снова его сохраню, изменения будут внесены. Что я делаю не так?

class Invoice(models.Model):
    ...
    books = models.ManyToManyField(Book,blank=True,null=True)
    ...

    def save(self, *args, **kwargs):
        super(Invoice, self).save(*args, **kwargs)
        for book in self.books.all():
            book.quantity -= 1
            if book.quantity == 0:
                book.sold = True;
            book.save()

Редактировать: я пытался использовать сигнал post_save, но он работает точно так же. Никаких изменений при первом сохранении, изменения сохраняются во второй раз.

Обновление: похоже, проблема решена с помощью этого кода:

class InvoiceAdmin(admin.ModelAdmin):
    ...

    def save_model(self, request, obj, form, change):
        obj.save()
        for bk in form.cleaned_data['books']:
            book = Book.objects.get(pk=bk.id)
            book.quantity -= 1
            if book.quantity == 0:
                book.sold = True;
            book.save()

  • я бы подумал о переделке. даже если это сработает так, как вы предполагали, что произойдет, если в счет-фактуру нужно будет внести изменения? когда вы сохраните его, это будет выглядеть так, как будто книги были проданы дважды. 05.02.2010
  • Да, это правда: вторая часть моего исследования отслеживает instance_id, чтобы увидеть, был ли он уже сохранен... Я думаю, что m2m_changed из Django 1.2 может быть именно тем, что мне нужно... 05.02.2010

Ответы:


1

Вот как я работал над этим, действительно сбивающим с толку, поведением. Подключите приемник сигнала к событию models.signals.m2m_changed, это запускается каждый раз, когда изменяется поле m2m. Встроенные комментарии объясняют, почему.

class Gig(models.Model):
    def slugify(self):
        # Add venue name, date and artists to slug
        self.slug = slugify(self.venue.name) + "-"
        self.slug += self.date.strftime("%d-%m-%Y") + "-"
        self.slug += "-".join([slugify(artist.name) for artist in self.artists.all()]) 
        self.save()


@receiver(models.signals.m2m_changed, sender=Gig.artist.through)
def gig_artists_changed(sender, instance, **kwargs):
    # This callback function get's called twice. 
    # 1 first change appears to be adding an empty list
    # 2nd change is adding the actual artists
    if instance.artist.all() and not instance.slug:                                                                                                                                                               
        instance.slugify()
17.08.2012

2

Это связано с тем, что отношение m2m сохраняется после сохранения вашей модели, чтобы получить PK родительского объекта. В вашем случае второе сохранение работает так, как ожидалось, потому что у модели уже есть PK и связанные книги из первого сохранения (это делается в сигнале).

Я еще не нашел решения, лучше всего внести свои изменения в панели администратора, наверное.

04.02.2010
  • Я знаю, что они сохраняются после сохранения модели, поэтому я поставил предложение for после super().save() Сохраняются ли они после сигнала post_save? Есть ли сигнал, когда они будут сохранены? 04.02.2010
  • они сохраняются после вызова Invoice.save(), поэтому, даже если вы поместите после родительского сохранения, он не сохранит m2m. Что касается сигналов, посмотрите на m2m_saved 04.02.2010
  • Но мне интересно, какая функция вызывается после сохранения для сохранения полей m2m? Не мог бы я вместо этого переопределить это поле? 05.02.2010
  • Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..