Question

When I add a new Banner from admin panel the keyword I want to associate with the banner at its creation does not get added in db.

class Banners(models.Model):
    objects = BannerManager()
    banner_location = models.ManyToManyField(BannerLocation, verbose_name=_("Banner's Location"), default=None, null=True, blank=True)
    keywords = models.ManyToManyField(Keywords, verbose_name=_("Banner's Related Keywords"), null=True, blank=True)
    width = models.IntegerField(verbose_name=_("Banner Width"), null=False, blank=False)
    height = models.IntegerField(verbose_name=_("Banner Height"), null=False, blank=False)
    invocation_code = models.TextField(verbose_name=_("Banner Height"), null=False, blank=False)
    is_enable = models.BooleanField(verbose_name=_("Is Enable"), default=False)
    banner_updated = models.DateTimeField(auto_now=True)
    banner_created = models.DateTimeField(auto_now_add=True)

    class Meta:
        verbose_name = "Banner"
        verbose_name_plural = "Banners"
        ordering = ['-banner_updated', 'is_enable']

    def __unicode__(self):
        return "width: %s, height: %s" % (self.width, self.height)

    def save(self):
        is_new = False
        if self.pk is None:
            is_new = True
        super(Banners, self).save()
        if is_new == True:
            keyword = Keywords.objects.get(pk=1)
            self.keywords.add(keyword)
Was it helpful?

Solution

If you have the keywords field in your admin form what happens is this:

  1. you press save on your new Banners instance in the admin (with no keywords selected)
  2. Django admin model-form saves the Banners instance
  3. your overridden save method adds your keywords
  4. Django admin sets the keywords m2m field to whatever keywords were submitted in the form (replacing what you set in the save method)

The reason Django does this is because, as you know, the Banners instance has to be saved before m2m relations can be added.

I have been round in circles with this myself in the past messing with m2m_changed signal etc... but you're likely to end up with something that only works in narrow set of circumstances in the Django admin site, but doesn't make sense in other code.

Your save method is working I think (try it in a console, outside Django admin), what you really need is to customise behaviour of the admin form:

class BannersForm(forms.ModelForm):
    class Meta:
        model = Banners

    def __init__(self, *args, **kwargs):
        if kwargs.get('instance') is None:
            # create new Banners
            initial = kwargs.get('initial', {})
            initial.update({'keywords': Keywords.objects.filter(pk=1)})
            kwargs['initial'] = initial
        super(BannersForm, self).__init__(*args, **kwargs)


class BannersAdmin(admin.ModelAdmin):
    form = BannersForm


admin.site.register(Banners, BannersAdmin)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top