0

I have two models. The model Copy should get the max_length from the model AdSpot without inheriting from it. And after trying multiple times, I failed to make this work:

class AdSpot(models.Model):

    title_max_chars = models.IntegerField(default=0)

    @property
    def title_max_chars_from_adspot(self):
        return self.title_max_chars
class Copy(models.Model):
    adspot = models.ForeignKey(AdSpot, on_delete=models.PROTECT)
    def title_max_chars_from_adspot(self, *args, **kwargs):
        return self.adspot.title_max_chars_from_adspot
    title = models.CharField('Name', max_length=title_max_chars_from_adspot, default="")

The error is

polls.Copy.title: (fields.E121) 'max_length' must be a positive integer.

What am I missing ?

8
  • try max_length=int(title_max_chars_from_adspot) Commented Jun 7, 2019 at 16:10
  • TypeError: int() argument must be a string, a bytes-like object or a number, not 'function' Commented Jun 7, 2019 at 16:11
  • Ok try max_length=title_max_chars_from_adspot(self) Commented Jun 7, 2019 at 16:14
  • Which behavior do you expect? Each row in Copy model must have different column title width depending on linked AdSpot row? Commented Jun 7, 2019 at 16:15
  • 2
    You can't use a computed value there because that is a database constraint, and it needs to exists when you apply the migration. You will need to validated that on your save method. Commented Jun 7, 2019 at 16:16

3 Answers 3

2

You are doing things in a wrong way. max_length should be integer, and your are passing python's FunctionType object. title_max_chars_from_adspot is a property of Copy class and you do not have instance of Copy class (You will never get it during makemigration/migration) process. The only way is to pass int max_length=5 for example, or write @staticmethod @classmethod for Copy class (But this case, it will be impossible to get access on ForeignKey object). Change strategy.

class AdSpot(models.Model):

    title_max_chars = models.IntegerField(default=22)

class Copy(models.Model):
    adspot = models.ForeignKey(AdSpot, on_delete=models.PROTECT)

    default_length = 255
    for field in AdSpot._meta.fields:
        if field.name == 'title_max_chars':
            default_length = field.default
    title = models.CharField('Name', max_length=default_length, default='') # default value of title_max_chars (22 this case) from AdSpot will be set as a max_length of title
Sign up to request clarification or add additional context in comments.

1 Comment

thanks, I did some initial test and this is working
0

You are setting Adspot.title_max_chars to a default equals to 0 However max_length always should be a positive integer. try not to provide a default.

Comments

0

You can use PositiveIntegerField in place of IntegerField.

class AdSpot(models.Model):

    title_max_chars = models.PositiveIntegerField(default=0)

    @property
    def title_max_chars_from_adspot(self):
        return self.title_max_chars

1 Comment

Copy.title: (fields.E121) 'max_length' must be a positive integer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.