Search code examples
pythondjangomodels

django sequence:item 4 expected string or unicode int found


I'm running python manage.py migrate with my models,the database was already made i'm just making the models for it now, but getting this error when running the command

TypeError: Error when calling the metaclass bases
    sequence item 4: expected string or Unicode, int found

my models

class Publisher(models.Model):
    publisherCode = models.CharField(3,primary_key=True)
    publisherName = models.CharField(25)
    city = models.CharField(20)

class Book(models.Model):
    bookCode = models.CharField(4,primary_key=True)
    title = models.CharField(40)
    publisherCode = models.ForeignKey(Publisher)
    type = models.CharField(3)
    paperback = models.CharField(1)

class Branch(models.Model):
    branchNum = models.DecimalField(2,0,primary_key=True)
    branchName = models.CharField(50)
    branchLocation = models.CharField(50)

class Copy(models.Model):
    bookCode = models.ForeignKey(Book)
    branchNum = models.ForeignKey(Branch)
    copyNum = models.DecimalField(2,0,primary_key=True)
    quality = models.CharField(20)
    price = models.DecimalField(8,2)

Solution

  • Short answer: make from max_length an explicitly named argument.

    Based on the source code, max_length is not an explicit parameter of CharField, it thus performs a call to the __init__ of Field, and this has as arguments:

    def __init__(self, verbose_name=None, name=None, primary_key=False,
                 max_length=None, unique=False, blank=False, null=False,
                 db_index=False, rel=None, default=NOT_PROVIDED, editable=True,
                 serialize=True, unique_for_date=None, unique_for_month=None,
                 unique_for_year=None, choices=None, help_text='', db_column=None,
                 db_tablespace=None, auto_created=False, validators=(),
                 error_messages=None):
    

    So as you can see, your first unnamed parameter, actually will match with verbose_name, and this should be a string. Of course providing the number as a string will not solve the problem since then you pass the max_length to the verbose_name, instead, and furthermore max_length is, as far as I know a required parameter for CharField.

    The solution is to explicitly use max_length such that it is clear that you want to assign 4 to that parameter. The same holds for the DecimalField by the way:

    class Publisher(models.Model):
        publisherCode = models.CharField(max_length=3,primary_key=True)
        publisherName = models.CharField(max_length=25)
        city = models.CharField(max_length=20)
    
    class Book(models.Model):
        bookCode = models.CharField(max_length=4,primary_key=True)
        title = models.CharField(max_length=40)
        publisherCode = models.ForeignKey(Publisher)
        type = models.CharField(max_length=3)
        paperback = models.CharField(max_length=1)
    
    class Branch(models.Model):
        branchNum = models.DecimalField(max_digits=2, decimal_places=0, primary_key=True)
        branchName = models.CharField(max_length=50)
        branchLocation = models.CharField(max_length=50)
    
    class Copy(models.Model):
        bookCode = models.ForeignKey(Book)
        branchNum = models.ForeignKey(Branch)
        copyNum = models.DecimalField(max_digits=2, decimal_places=0, primary_key=True)
        quality = models.CharField(max_length=20)
        price = models.DecimalField(max_digits=8, decimal_places=2)

    This is more "self-explaining" as well: a user with not much Django experience, can usually guess that max_length=3 means that the string can contain at most three characters, whereas without explicit naming, he/she should have to look up what exactly this parameter means.

    I find it rather weird that you use a DecimalField with decimal_places=0, since this is basically an IntegerField, usually it is better to use an IntegerField in that case since it maps more directly to what it is conceptually, the database can store it in a more compact way, and arithmetic operations are usually correct in integer land, whereas in floating point land, there can be rounding errors.