ValueError on foreignkey default value

白昼怎懂夜的黑 提交于 2021-02-10 05:39:50

问题


I deleted my db.sqlite3 and the file on my migration folder except __init__.py but including the __pycache__ folder.

My app's models are multiple files in a folder with an __init__.py file with some import and an __all__ variable (I don't know if this matter).

From the prompt I give the first migrate command and it look to work (migrating sessions, admin, auth, registration, contenttypes. There isn't my app 'core').

So i give the first makemigrations command and again the migrate command. This time it give an error:

ValueError: invalid literal for int() with base 10: 'basic'

In a model there's an ForeignKey fields with default='basic'. basic will be an object of the related class but actually it don't exist (before I create the database, then I will populate it). I think it's normal.

Anyway I change in default=1 and it works (but 1 will not be an object, so it's wrong!)

My model:

Class Payment(models.Model):
    name = models.CharField(max_length=32)

Class ProfileUser(models.Model):
    payment = models.ForeignKey(Payment, blank=True, null=True, 
        default='basic', on_delete=models.PROTECT)
    #etc

There is a way to use 'basic'? I prefer to not use id=1 because I'm not sure to know the id that basic will have (remember that now it don't exist yet).

Btw in other models I have alike situations and they appear to works...

The Whole error:

(myvenv) c:\Python34\Scripts\possedimenti\sitopossedimenti>manage.py migrate
Operations to perform:
  Apply all migrations: contenttypes, core, registration, admin, auth, sessions
Running migrations:
  Rendering model states... DONE
  Applying core.0001_initial...Traceback (most recent call last):
  File "C:\Python34\Scripts\possedimenti\sitopossedimenti\manage.py", line 10, i
n <module>
    execute_from_command_line(sys.argv)
  File "c:\Python34\Scripts\possedimenti\myvenv\lib\site-packages\django\core\ma
nagement\__init__.py", line 353, in execute_from_command_line
    utility.execute()
  File "c:\Python34\Scripts\possedimenti\myvenv\lib\site-packages\django\core\ma
nagement\__init__.py", line 345, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "c:\Python34\Scripts\possedimenti\myvenv\lib\site-packages\django\core\ma
nagement\base.py", line 348, in run_from_argv
    self.execute(*args, **cmd_options)
  File "c:\Python34\Scripts\possedimenti\myvenv\lib\site-packages\django\core\ma
nagement\base.py", line 399, in execute
    output = self.handle(*args, **options)
  File "c:\Python34\Scripts\possedimenti\myvenv\lib\site-packages\django\core\ma
nagement\commands\migrate.py", line 200, in handle
    executor.migrate(targets, plan, fake=fake, fake_initial=fake_initial)
  File "c:\Python34\Scripts\possedimenti\myvenv\lib\site-packages\django\db\migr
ations\executor.py", line 92, in migrate
    self._migrate_all_forwards(plan, full_plan, fake=fake, fake_initial=fake_ini
tial)
  File "c:\Python34\Scripts\possedimenti\myvenv\lib\site-packages\django\db\migr
ations\executor.py", line 121, in _migrate_all_forwards
    state = self.apply_migration(state, migration, fake=fake, fake_initial=fake_
initial)
  File "c:\Python34\Scripts\possedimenti\myvenv\lib\site-packages\django\db\migr
ations\executor.py", line 198, in apply_migration
    state = migration.apply(state, schema_editor)
  File "c:\Python34\Scripts\possedimenti\myvenv\lib\site-packages\django\db\migr
ations\migration.py", line 123, in apply
    operation.database_forwards(self.app_label, schema_editor, old_state, projec
t_state)
  File "c:\Python34\Scripts\possedimenti\myvenv\lib\site-packages\django\db\migr
ations\operations\fields.py", line 62, in database_forwards
    field,
  File "c:\Python34\Scripts\possedimenti\myvenv\lib\site-packages\django\db\back
ends\sqlite3\schema.py", line 221, in add_field
    self._remake_table(model, create_fields=[field])
  File "c:\Python34\Scripts\possedimenti\myvenv\lib\site-packages\django\db\back
ends\sqlite3\schema.py", line 103, in _remake_table
    self.effective_default(field)
  File "c:\Python34\Scripts\possedimenti\myvenv\lib\site-packages\django\db\back
ends\base\schema.py", line 210, in effective_default
    default = field.get_db_prep_save(default, self.connection)
  File "c:\Python34\Scripts\possedimenti\myvenv\lib\site-packages\django\db\mode
ls\fields\related.py", line 912, in get_db_prep_save
    return self.target_field.get_db_prep_save(value, connection=connection)
  File "c:\Python34\Scripts\possedimenti\myvenv\lib\site-packages\django\db\mode
ls\fields\__init__.py", line 728, in get_db_prep_save
    prepared=False)
  File "c:\Python34\Scripts\possedimenti\myvenv\lib\site-packages\django\db\mode
ls\fields\__init__.py", line 968, in get_db_prep_value
    value = self.get_prep_value(value)
  File "c:\Python34\Scripts\possedimenti\myvenv\lib\site-packages\django\db\mode
ls\fields\__init__.py", line 976, in get_prep_value
    return int(value)
ValueError: invalid literal for int() with base 10: 'basic'

Thank You

PS: I'm using python 3.4 Django 1.9 Windows7


回答1:


In your Payment model you have not explicitly designated a primary key. So django will create one for you. It will be an integer auto increment field.

Class Payment(models.Model):
    name = models.CharField(max_length=32)

Now when you define Payment as a foreign key for ProfileUser, django thinks that it should be the primary key field in Payment that ought to be used as the reference.

Class ProfileUser(models.Model):
    payment = models.ForeignKey(Payment, blank=True, null=True, 
        default='basic', on_delete=models.PROTECT)
    #etc

In order to enforce this reference, the payment field needs to be an integer. And you cannot insert 'basic' into an integer field.

One solution is to use the ForeignKey.to_field option to explicitly refer to a different field in the Payment class.

ForeignKey.to_field¶ The field on the related object that the relation is to. By default, Django uses the primary key of the related object.

Thus your class would become

Class ProfileUser(models.Model):
    payment = models.ForeignKey(Payment, blank=True, null=True, 
        default='basic', on_delete=models.PROTECT,
        to_field = 'name' )
    #etc

Now the payment field here becomes a CharField. Note that it would be more efficient to use an integer field as a foreign key in most cases.

Another possibility is for you to define the name field in Payment as it's primary key.




回答2:


Create a function to return the id (put it before the ProfileUser defenition).

def get_basic_id():
    payment = Payment.options.get(name='basic')
    return payment.id 

Class ProfileUser(models.Model):
    payment = models.ForeignKey(Payment, blank=True, null=True, 
        default=get_basic_id(), on_delete=models.PROTECT)

Though if you don't know what id 'basic' will have, are you certain that it will be in the database? One way around this would be to populate the payment table using fixtures.

https://docs.djangoproject.com/en/1.9/howto/initial-data/



来源:https://stackoverflow.com/questions/37070557/valueerror-on-foreignkey-default-value

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!