Vous essayez d'ajouter un champ non Nullable 'new_field' à userprofile sans valeur par défaut

109

Je sais qu'à partir de Django 1.7, je n'ai pas besoin d'utiliser South ou tout autre système de migration, donc j'utilise juste une commande simple python manage.py makemigrations

Cependant, tout ce que j'obtiens, c'est cette erreur:

You are trying to add a non-nullable field 'new_field' to userprofile without a default;
we can't do that (the database needs something to populate existing rows).

Voici models.py:

class UserProfile(models.Model):
    user = models.OneToOneField(User)
    website = models.URLField(blank=True)
    new_field = models.CharField(max_length=140)

Quelles sont les options?

Irmantas Želionis
la source
3
Je voulais ajouter que le problème se produit lorsque vous modifiez une table existante, pas lorsque vous en créez une nouvelle.
x-yuri

Réponses:

93

Vous devez fournir une valeur par défaut:

new_field = models.CharField(max_length=140, default='SOME STRING')
dgel
la source
Que faire si j'ai besoin d'avoir new_field une copie d'un champ de site Web. À quoi cela devrait-il ressembler? default = websitene fait pas le travail
Irmantas Želionis
8
Vous voudrez d'abord effectuer la migration avec une valeur par défaut fausse, puis créer une migration de données pour parcourir chaque enregistrement et définir new_fieldsur website.
dgel
La valeur par défaut devrait être facultative pour CharField
Florent le
88

Si vous êtes au début du cycle de développement et que vous ne vous souciez pas des données de votre base de données actuelles , vous pouvez simplement les supprimer, puis migrer. Mais vous devez d'abord nettoyer le répertoire des migrations et supprimer ses lignes de la table (django_migrations)

rm  your_app/migrations/*

rm db.sqlite3
python manage.py makemigrations
python manage.py migrate
Tomasz
la source
8
Encore une chose. Vous devez nettoyer la table des migrations, par exemple:mysql -u[user] [database] -e "delete from django_migrations where app=[your_app]"
helpse
Ceci est le chemin. Je pense que Django est nul en matière de migration et de détection de modèles, etc. Je veux une mise à jour majeure pour cela.
WesternGun
J'ai supprimé tous les fichiers des migrations et supprimé toutes les lignes de django_migrations et maintenant j'obtiens "django.db.migrations.exceptions.NodeNotFoundError: Migration stories.0001_initial dependencies reference inexistent parent node ('sources', '0002_auto_20180903_1224')" lors de l'exécution migration.
brainLoop
1
Assurez-vous également de ne pas supprimer le __init__.py des migrations, ou de le restaurer après, sinon les migrations ne fonctionneront pas stackoverflow.com/a/46362750/1649917
nmu
python manage.py sqlmigrate name_of_your_app nb_of_the_migrationest également requis
zar3bski
38

Une option consiste à déclarer une valeur par défaut pour 'new_field':

new_field = models.CharField(max_length=140, default='DEFAULT VALUE')

une autre option est de déclarer 'new_field' comme un champ Nullable:

new_field = models.CharField(max_length=140, null=True)

Si vous décidez d'accepter 'new_field' comme champ Nullable, vous voudrez peut-être accepter 'no input' comme entrée valide pour 'new_field'. Ensuite, vous devez également ajouter la blank=Truedéclaration:

new_field = models.CharField(max_length=140, blank=True, null=True)

Même avec null=Trueet / ou, blank=Truevous pouvez ajouter une valeur par défaut si nécessaire:

new_field = models.CharField(max_length=140, default='DEFAULT VALUE', blank=True, null=True)
Tobi
la source
7
«Évitez d'utiliser null sur des champs basés sur des chaînes tels que CharField et TextField. Si un champ basé sur une chaîne a null = True, cela signifie qu'il a deux valeurs possibles pour «pas de données»: NULL et la chaîne vide. » - Référence du champ du modèle
Chema
7

Si vous êtes au début du cycle de développement, vous pouvez essayer ceci -

Supprimez / commentez ce modèle et toutes ses utilisations. Appliquez les migrations. Cela supprimerait ce modèle, puis ajouterait à nouveau le modèle, exécuterait des migrations et vous auriez un modèle propre avec le nouveau champ ajouté.

Dur
la source
Et nettoyez la table des migrations django_migrations comme indiqué ici: stackoverflow.com/questions/26185687/ ... Ou utilisez simplement une interface graphique et supprimez les lignes requises.
RusI
5

Au cas où quelqu'un définirait a ForeignKey, vous pouvez simplement autoriser les champs Nullable sans définir de valeur par défaut:

new_field = models.ForeignKey(model, null=True)

Si vous avez déjà des données stockées dans la base de données, vous pouvez également définir une valeur par défaut:

new_field = models.ForeignKey(model, default=<existing model id here>)
Justin Lange
la source
4

Si «site Web» peut être vide, il new_fielddevrait également être défini comme vide.

Maintenant, si vous voulez ajouter une logique lors de l'enregistrement où si new_fieldest vide pour récupérer la valeur de "site Web", tout ce que vous avez à faire est de remplacer la fonction de sauvegarde pour votre Modelcomme ceci:

class UserProfile(models.Model):
    user = models.OneToOneField(User)
    website = models.URLField(blank=True, default='DEFAULT VALUE')
    new_field = models.CharField(max_length=140, blank=True, default='DEFAULT VALUE')

    def save(self, *args, **kwargs):
        if not self.new_field:
            # Setting the value of new_field with website's value
            self.new_field = self.website

        # Saving the object with the default save() function
        super(UserProfile, self).save(*args, **kwargs)
Alex Carlos
la source
3

Vous ne pouvez pas ajouter de référence à une table contenant déjà des données.
Changement:

user = models.OneToOneField(User)

à:

user = models.OneToOneField(User, default = "")

faire:

python manage.py makemigrations
python manage.py migrate

changer à nouveau:

user = models.OneToOneField(User)

refaire la migration:

python manage.py makemigrations
python manage.py migrate
E. Kristiyono
la source
2

Dans new_file, ajoutez la propriété booléenne null.

new_field = models.CharField(max_length=140, null=True)

après avoir exécuté un ./manage.py syncdbpour actualiser la base de données. et enfin tu cours ./manage.py makemigrations et./manage.py migrate

gératchev
la source
2

Avez-vous déjà des entrées de base de données dans le tableau UserProfile? Si tel est le cas, lorsque vous ajoutez de nouvelles colonnes, la base de données ne sait pas sur quoi la définir car elle ne peut pas l'être NULL. Par conséquent, il vous demande sur quoi vous souhaitez définir ces champs dans la colonne new_fields. J'ai dû supprimer toutes les lignes de ce tableau pour résoudre le problème.

(Je sais que cela a été répondu il y a quelque temps, mais je viens de rencontrer ce problème et c'était ma solution. J'espère que cela aidera toute personne nouvelle qui verra cela)

Arnold Lam
la source
1
Je n'ai pas inséré de lignes dans le tableau et je reçois toujours cela. Je dois supprimer tout l'historique de migration, effacer le tableau de migration pour changer le modèle, comme suggéré par Tomasz.
WesternGun
1

Je trouve honnêtement que le meilleur moyen de contourner ce problème était de simplement créer un autre modèle avec tous les champs dont vous avez besoin et dont le nom est légèrement différent. Exécutez des migrations. Supprimez le modèle inutilisé et réexécutez les migrations. Voila.

Josh
la source
1

Si vous ne parvenez pas à tronquer la table du modèle en question, vous pouvez spécifier une valeur par défaut unique de Nonedans l'invite. La migration sera superflue default=Nonealors que votre code n'a pas de valeur par défaut. Il peut être appliqué très bien car il n'y a plus de données dans le tableau qui nécessiteraient une valeur par défaut.

jnns
la source
1

J'étais au début de mon cycle de développement, donc cela peut ne pas fonctionner pour tout le monde (mais je ne vois pas pourquoi cela ne fonctionnerait pas).

J'ai ajouté blank=True, null=Trueaux colonnes où j'obtenais l'erreur. Ensuite, j'ai exécuté la python manage.py makemigrationscommande.

Immédiatement après avoir exécuté cette commande (et avant d'exécuter python manage.py migrate), j'ai supprimé le blank=True, null=Truede toutes les colonnes. Puis j'ai couru à python manage.py makemigrationsnouveau. J'ai eu la possibilité de simplement modifier les colonnes moi-même, ce que j'ai sélectionné.

Ensuite, j'ai couru python manage.py migrateet tout a bien fonctionné!

Joseph Gill
la source
0

Ce que dit Django, c'est:

La table Userprofile contient des données et il peut y avoir des new_fieldvaleurs nulles, mais je ne sais pas, alors êtes-vous sûr de vouloir marquer la propriété comme non nullable, car si vous le faites, vous pourriez obtenir une erreur s'il y a des valeurs avec NULL

Si vous êtes sûr qu'aucune des valeurs de la userprofiletable n'est NULL, laissez tomber et ignorez l'avertissement.

La meilleure pratique dans de tels cas serait de créer une migration RunPython pour gérer les valeurs vides comme indiqué dans l'option 2

2) Ignorez pour le moment et laissez-moi gérer moi-même les lignes existantes avec NULL (par exemple, parce que vous avez ajouté une opération RunPython ou RunSQL pour gérer les valeurs NULL dans une migration de données précédente)

Dans la migration RunPython, vous devez trouver toutes les UserProfileinstances avec une new_fieldvaleur vide et y mettre une valeur correcte (ou une valeur par défaut comme Django vous demande de définir dans le modèle). Vous obtiendrez quelque chose comme ceci:

# please keep in mind that new_value can be an empty string. You decide whether it is a correct value.
for profile in UserProfile.objects.filter(new_value__isnull=True).iterator():
    profile.new_value = calculate_value(profile)
    profile.save() # better to use batch save

S'amuser!

Taras Matsyk
la source
Je n'arrive pas à trouver où cela est écrit dans la documentation. Pouvez-vous poster le lien s'il vous plaît
Cody
0

Dans models.py

class UserProfile(models.Model): user = models.OneToOneField(User) website = models.URLField(blank=True) new_field = models.CharField(max_length=140, default="some_value")

Vous devez ajouter des valeurs par défaut.

George Devasia
la source
-1

Si le SSH, il vous donne 2 options, choisissez le numéro 1, et mettez "Aucun". Juste ça ... pour le moment.

Geovanni Atavales
la source