0
class MyModel(models.Model):
     field1 = models.ForeignKey('AnotherModel', null=False, blank=False)
     field2 = #its a choice field
     # some more fields

What I want is to fill the field1 with a default value if field2 is equal to some specific value (from choice tuple).

I gave it a try by overriding the save() method but I wasn't successful.

def save(self, *args, *kwargs):
   if self.field2 == 'some-specific-value':
      self.field1 = 'some-default-value or a dummy object id?'

For other values of choice field (field2) user has to provide a value but as mentioned above, for a specific value we will fill with default word/string.

I even tried to use signal pre_save, pre_init, post_init but no success

@receiver(post_init, sender=MyModel)
def populate_field1(sender, instance, *args, **kwargs):
    print 'in signal'
    if instance.field2 == 'some-specific-value':
          instance.field1 = 'some-default-value'

How can I do this?

bakar
  • 1,152
  • 2
  • 11
  • 20
  • 2
    `I gave it a try by overriding save() method but not successful` doesn't really help, what is your specific error case. – Hedde van der Heide Aug 10 '15 at 12:03
  • @HeddevanderHeide: when I tried to save this model using django admin, and left blank field1 but field2 has specific value, as soon as i click on save button it shows that this is compulsory field and doesnt save. `This field is required.` error shows up in RED background – bakar Aug 10 '15 at 12:05
  • 2
    Obviously because you have both null and blank set to False, you can remove those and clean them manually? – Hedde van der Heide Aug 10 '15 at 12:18
  • so do you have any solution to this problem? – bakar Aug 10 '15 at 12:20
  • if you pay attention to the error message you see your problem is the model validation... model validation is called automatically when saving from a ModelForm, such as in the django admin. Since the `field1` is defined as `null=False` you need to customise your model validation https://docs.djangoproject.com/en/1.8/ref/models/instances/#validating-objects – Anentropic Aug 10 '15 at 12:46
  • @Anentropic: ok but that is specific to django admin, I want this functionality everywhere, I mean whether a user save from admin panel or django program of shell. could you please provide a sample code for this – bakar Aug 10 '15 at 13:03
  • 1
    what I mean is if you just call `instance.save()` in a python shell it should work because the validation is not called. so to get it working in the django admin as well you need to customise the validation on the model. – Anentropic Aug 10 '15 at 13:12

1 Answers1

0

Cleaning is where I would do that if I were you, but I've also seen folks use @property and @func.setter to have it add functionality - so if I set field1, the setter also sets field2 accordingly as it's assigned.

You can do this on cleaning - so if the field is blank=True but not null=True, you can save the field, and cleaning will be where the logic gets executed. This will allow you to save() the model and pass validation (Since blank=True, I can call the save method without erroring, or manually setting it), and my cleaning ensures that the null=False condition is still met by assigning before saving is complete.

class MyModel(models.Model):
     field1 = models.ForeignKey('AnotherModel', null=False, blank=False)
     field2 = #its a choice field
     # some more fields

     def clean(self):
         if self.field2.field == 'value':
             self.field1 = AnotherModel.logic.to.get_the_right_(one)
         else:
             self.field1 = AnotherModel.some_default(value)

Here's an example where I did something similar but with less dependencies:

class Domain(models.Model):
    class Meta:
        ordering = ['domain_name']

    domain_id = models.CharField(max_length=255, unique=True, blank=True)
    domain_name = models.CharField(max_length=255, unique=True)
    domain_arrays = models.ManyToManyField('Array', blank=True)

    def __str__(self):
        return self.domain_name

    def clean(self):
        self.domain_id = self.domain_name.lower().replace('.', '_')
        self.domain_name = self.domain_name.lower()
bubthegreat
  • 301
  • 1
  • 9