Partage
  • Partager sur Facebook
  • Partager sur Twitter

[DJANGO] ForeignKey et valeur par défaut

Ajouter une valeur par défaut sur une Foreignkey

    17 octobre 2020 à 12:33:03

    Bonjour tout le monde !

    Débutant sur Django, j'essaye actuellement de comprendre le framework en réalisant un blog basique. Je cherche à ajouter une valeur par défaut sur une relation entre modèles. Je m'explique j'ai une classe "Post" et une classe "Category". Les deux sont liées via une foreignkey ajoutée à la classe "Post". J'aimerai qu'à la création d'un nouvel article, la valeur "Unknown" soit automatiquement assignée à la catégorie de l'article.

    Avant toute chose voici ma configuration :
     
    système -> Windows
    jeu d'instructions -> 64 bits
    distribution -> 6.3.9600
    version python -> 3.8.2
    version django -> 3.1.2

    Voici le modèle de la classe "Post" :

    class Post(models.Model):
        title = models.CharField(max_length=255)
        author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
        text = models.TextField()
        published_date = models.DateField(auto_now_add=True)
        category = models.ForeignKey(Category, on_delete=models.CASCADE)
    
        def __str__(self):
            return self.title + " | " + str(self.author)
    
        def get_absolute_url(self):
            return reverse("home")
    
    
    


    et celui de la classe "Category" :

    class Category(models.Model):
        name = models.CharField(max_length=40, unique=True, default="Unknown")
    
        def __str__(self):
            return self.name


    A noter que des articles étaient déjà existant avant l'ajout de la catégorie.
    Lorsque j'effectue le makemigrations, la console m'affiche ceci :

    (venv) C:\geomaps>python manage.py makemigrations
    You are trying to add a non-nullable field 'category' to post without a default; we can't do that (the database needs something to populate existing rows).
    Please select a fix:
     1) Provide a one-off default now (will be set on all existing rows with a null value for this column)
     2) Quit, and let me add a default in models.py
    Select an option: 1
    Please enter the default value now, as valid Python
    The datetime and django.utils.timezone modules are available, so you can do e.g. timezone.now
    Type 'exit' to exit this prompt
    >>> 'Unknown'
    Migrations for 'blog':
      blog\migrations\0002_auto_20201016_2354.py
        - Create model Category
        - Add field category to post


    et lorsque je fais le migrate :

    (venv) C:\geomaps>python manage.py migrate
    Operations to perform:
      Apply all migrations: admin, auth, blog, contenttypes, sessions
    Running migrations:
      Applying blog.0002_auto_20201016_2354...Traceback (most recent call last):
      File "C:\geomaps\venv\lib\site-packages\django\db\models\fields\__init__.py", line 1774, in get_prep_value
        return int(value)
    ValueError: invalid literal for int() with base 10: 'Unknown'
    
    The above exception was the direct cause of the following exception:
    
    Traceback (most recent call last):
      File "manage.py", line 22, in <module>
        main()
      File "manage.py", line 18, in main
        execute_from_command_line(sys.argv)
      File "C:\geomaps\venv\lib\site-packages\django\core\management\__init__.py", line 401, in execute_from_command_line
        utility.execute()
      File "C:\geomaps\venv\lib\site-packages\django\core\management\__init__.py", line 395, in execute
        self.fetch_command(subcommand).run_from_argv(self.argv)
      File "C:\geomaps\venv\lib\site-packages\django\core\management\base.py", line 330, in run_from_argv
        self.execute(*args, **cmd_options)
      File "C:\geomaps\venv\lib\site-packages\django\core\management\base.py", line 371, in execute
        output = self.handle(*args, **options)
      File "C:\geomaps\venv\lib\site-packages\django\core\management\base.py", line 85, in wrapped
        res = handle_func(*args, **kwargs)
      File "C:\geomaps\venv\lib\site-packages\django\core\management\commands\migrate.py", line 243, in handle
        post_migrate_state = executor.migrate(
      File "C:\geomaps\venv\lib\site-packages\django\db\migrations\executor.py", line 117, in migrate
        state = self._migrate_all_forwards(state, plan, full_plan, fake=fake, fake_initial=fake_initial)
      File "C:\geomaps\venv\lib\site-packages\django\db\migrations\executor.py", line 147, in _migrate_all_forwards
        state = self.apply_migration(state, migration, fake=fake, fake_initial=fake_initial)
      File "C:\geomaps\venv\lib\site-packages\django\db\migrations\executor.py", line 227, in apply_migration
        state = migration.apply(state, schema_editor)
      File "C:\geomaps\venv\lib\site-packages\django\db\migrations\migration.py", line 124, in apply
        operation.database_forwards(self.app_label, schema_editor, old_state, project_state)
      File "C:\geomaps\venv\lib\site-packages\django\db\migrations\operations\fields.py", line 104, in database_forwards
        schema_editor.add_field(
      File "C:\geomaps\venv\lib\site-packages\django\db\backends\sqlite3\schema.py", line 328, in add_field
        self._remake_table(model, create_field=field)
      File "C:\geomaps\venv\lib\site-packages\django\db\backends\sqlite3\schema.py", line 189, in _remake_table
        self.effective_default(create_field)
      File "C:\geomaps\venv\lib\site-packages\django\db\backends\base\schema.py", line 303, in effective_default
        return field.get_db_prep_save(self._effective_default(field), self.connection)
      File "C:\geomaps\venv\lib\site-packages\django\db\models\fields\related.py", line 971, in get_db_prep_save
        return self.target_field.get_db_prep_save(value, connection=connection)
      File "C:\geomaps\venv\lib\site-packages\django\db\models\fields\__init__.py", line 823, in get_db_prep_save
        return self.get_db_prep_value(value, connection=connection, prepared=False)
      File "C:\geomaps\venv\lib\site-packages\django\db\models\fields\__init__.py", line 2388, in get_db_prep_value
        value = self.get_prep_value(value)
      File "C:\geomaps\venv\lib\site-packages\django\db\models\fields\__init__.py", line 1776, in get_prep_value
        raise e.__class__(
    ValueError: Field 'id' expected a number but got 'Unknown'.


    j'ai donc supprimé le fichier de migration et refait un makemigrations en rentrant 1 à la place de 'Unknown':

    (venv) C:\geomaps>python manage.py makemigrations
    You are trying to add a non-nullable field 'category' to post without a default; we can't do that (the database needs something to populate existing rows).
    Please select a fix:
     1) Provide a one-off default now (will be set on all existing rows with a null value for this column)
     2) Quit, and let me add a default in models.py
    Select an option: 1
    Please enter the default value now, as valid Python
    The datetime and django.utils.timezone modules are available, so you can do e.g. timezone.now
    Type 'exit' to exit this prompt
    >>> 1
    Migrations for 'blog':
      blog\migrations\0002_auto_20201016_2356.py
        - Create model Category
        - Add field category to post


    et voici le message d'erreur du migrate :

    (venv) C:\geomaps>python manage.py migrate
    Operations to perform:
      Apply all migrations: admin, auth, blog, contenttypes, sessions
    Running migrations:
      Applying blog.0002_auto_20201016_2356...Traceback (most recent call last):
      File "manage.py", line 22, in <module>
        main()
      File "manage.py", line 18, in main
        execute_from_command_line(sys.argv)
      File "C:\geomaps\venv\lib\site-packages\django\core\management\__init__.py", line 401, in execute_from_command_line
        utility.execute()
      File "C:\geomaps\venv\lib\site-packages\django\core\management\__init__.py", line 395, in execute
        self.fetch_command(subcommand).run_from_argv(self.argv)
      File "C:\geomaps\venv\lib\site-packages\django\core\management\base.py", line 330, in run_from_argv
        self.execute(*args, **cmd_options)
      File "C:\geomaps\venv\lib\site-packages\django\core\management\base.py", line 371, in execute
        output = self.handle(*args, **options)
      File "C:\geomaps\venv\lib\site-packages\django\core\management\base.py", line 85, in wrapped
        res = handle_func(*args, **kwargs)
      File "C:\geomaps\venv\lib\site-packages\django\core\management\commands\migrate.py", line 243, in handle
        post_migrate_state = executor.migrate(
      File "C:\geomaps\venv\lib\site-packages\django\db\migrations\executor.py", line 117, in migrate
        state = self._migrate_all_forwards(state, plan, full_plan, fake=fake, fake_initial=fake_initial)
      File "C:\geomaps\venv\lib\site-packages\django\db\migrations\executor.py", line 147, in _migrate_all_forwards
        state = self.apply_migration(state, migration, fake=fake, fake_initial=fake_initial)
      File "C:\geomaps\venv\lib\site-packages\django\db\migrations\executor.py", line 229, in apply_migration
        migration_recorded = True
      File "C:\geomaps\venv\lib\site-packages\django\db\backends\sqlite3\schema.py", line 35, in __exit__
        self.connection.check_constraints()
      File "C:\geomaps\venv\lib\site-packages\django\db\backends\sqlite3\base.py", line 343, in check_constraints
        raise IntegrityError(
    django.db.utils.IntegrityError: The row in table 'blog_post' with primary key '1' has an invalid foreign key: blog_post.category_id contains a value '1' that does not have a corresponding value i
    n blog_category.id.
    


    J'ai essayé de trouver des éléments de réponse ici :

    Auriez-vous des idées pour résoudre mon problème ? Merci d'avance et belle journée !

    -
    Edité par guismoche 19 octobre 2020 à 8:49:30

    • Partager sur Facebook
    • Partager sur Twitter
      19 octobre 2020 à 12:59:08

      Le problème vient, je pense, en partie, de ta classe category: tu lui dis que c'est un champ unique avec en valeur par défaut Unknown (je pense que par principe, un champ unique ne peut pas avoir de valeur par défaut)

      Pour pouvoir affecter la valeur Unknown par défaut à ta clé, il faut que cette valeur soit présente dans la table Category; et il faut que le choix de valeur par défaut soit défini dans la table Post au niveau de la clé étrangère (on doit lui affecté l'id de la Category Unknown) et non pas dans la table Category.

      • Partager sur Facebook
      • Partager sur Twitter

      [DJANGO] ForeignKey et valeur par défaut

      × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
      × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
      • Editeur
      • Markdown