0

How can I set a django field that gets data from a function depending on other fields? Let me explain using the following example.

class Test(models.Model):
    def testType(self):
        return str(self.__class__.__name__)
    sources = models.CharField(default= testType, max_length=50, null=True, blank=True)

In this case, if I go to django front-end interface and hit "add Test", I can see a box for 'sources' to fill out. This is not the way I wanted. I want: 1. a field named 'sources' in the back-end MySQL database, 2. No box for 'sources' to fill out in the "add Test" form, and 3. The 'sources' field will get data as soon as I add a new record.

Any suggestion that can help me to solve this issue would be appreciated.

Dubar Alam
  • 79
  • 1
  • 10
  • Possible duplicate of [How to set a Django model field's default value to a function call / callable (e.g., a date relative to the time of model object creation)](http://stackoverflow.com/questions/12649659/how-to-set-a-django-model-fields-default-value-to-a-function-call-callable-e) – themanatuf Feb 27 '17 at 19:57

2 Answers2

1

It sounds like you only want this done on creation of a new record, which is easily done by overriding the save method of a Django model.

class Test(models.Model):
    sources = models.CharField(default= testType, max_length=50, null=True, blank=True)

    def save(self, *args, *kwargs):
        if not self.pk:                # No pk attribute if not saved to DB
            self.sources = self.testType()
        super(Test, self).save(*args, **kwargs)    # call parent save method

    def testType(self):
        return str(self.__class__.__name__)

This doesn't involve form logic at all, instead relying purely on model logic. Any time a new Test is created, it will attempt write the sources field through this method.

Ian Price
  • 7,416
  • 2
  • 23
  • 34
  • Hi Ian, this issue is partially solved. Now, the 'sources' field gets data as soon as I add a new record. However, it doesn't update data when I edit the entry later. Do you have any suggestion? – Dubar Alam Mar 08 '17 at 20:30
  • 1
    Never mind. I just removed the if statement "if not self.pk:". It works fine. – Dubar Alam Mar 08 '17 at 23:25
1

You have a couple different things to do here to achieve what you want.

  1. a field named 'sources' in the back-end MySQL database
  2. The 'sources' field will get data as soon as I add a new record.

You already have that. Setting a default from a callable does exist. The problem is trying to have the default set off of self during creation.

You can achieve that by overriding the save() on Test

Here is what your Test model could look like:

class Test(models.Model):
    sources = models.CharField(max_length=50, null=True, blank=True)

    def save(self):
        self.sources = str(self.__class__.__name__)
        super(Test, self).save()

Now, whenever you save (create or update) a Test model instance, it will set the sources field.

  1. No box for 'sources' to fill out in the "add Test" form

The docs show you how to select what fields you want to appear in the form. You can either use fields or exclude. It tends to be a better security practice to explicitly list what fields you want to show in a form, rather than doing it implicitly with exclude.

With fields:

class Meta: #Put this in your Test form
    model=Test
    fields = ('someField',)

Now, only someField would be rendered in your form. Only fields you put in there will be rendered, all others ignored.

With exclude:

class Meta: #Put this in your Test form
    model=Test
    exclude= ['sources']

All fields on your model will be rendered except sources

Fred
  • 563
  • 3
  • 12
  • Hi Fred, sorry for my late response, I have been traveling. I am still getting error. Let me explain that. first, I called the testType function at sources this way 'sources = models.CharField(default= testType, max_length=50, null=True, blank=True)'. The error message is "sampleTtype() takes exactly 1 argument (0 given)". Second, I tried putting parenthesis "sources = models.CharField(default= testType(), max_length=50, null=True, blank=True)". It showed me same error. Although the error goes away if I use None in the paranthesis "testType(None)", it does not work. Any more suggestion? – Dubar Alam Mar 03 '17 at 19:00
  • Hi again Fred, controlling the appearance in the form using "fields" was successful. Just to let you know, I placed 'fields' at TestAdmin(admin.ModelAdmin) in the admin.py file and it worked. – Dubar Alam Mar 03 '17 at 20:13
  • Sorry for the confusion. Since you are handling setting sources in the save, you don't need the default anymore. Updated my answer to remove it. – Fred Mar 05 '17 at 22:34
  • Hi Fred, while this issue is solved, it doesn't update data when I edit the entry later. Do you have any suggestion? – Dubar Alam Mar 08 '17 at 21:30
  • @DubarAlam is there anything I need to update my answer with, or was the problem you had elsewhere? – Fred Mar 09 '17 at 20:51
  • I got the issue elsewhere. – Dubar Alam Mar 10 '17 at 00:02