web-dev-qa-db-fra.com

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

Je sais que depuis Django 1.7, je n'ai pas besoin d'utiliser South ni aucun autre système de migration. J'utilise donc simplement la commande python manage.py makemigrations

Cependant, tout ce que je reçois 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?

63

Vous devez fournir une valeur par défaut:

new_field = models.CharField(max_length=140, default='SOME STRING')
51
dgel

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

rm  your_app/migrations/*

rm db.sqlite3
python manage.py makemigrations
python manage.py migrate
53
Tomasz

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 consiste à déclarer 'new_field' en tant que champ nullable:

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

Si vous décidez d'accepter «new_field» en tant que champ nullable, vous pouvez accepter «aucune entrée» en tant qu'entrée valide pour «new_field». Ensuite, vous devez également ajouter l'instruction blank=True:

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

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

new_field = models.CharField(max_length=140, default='DEFAULT VALUE', blank=True, null=True)
27
Tobi

Si "site Web" peut être vide, new_field doit également être défini pour être vide.

Maintenant, si vous voulez ajouter une logique à la sauvegarde, où si new_field est vide pour récupérer la valeur de "site Web", il vous suffit de remplacer la fonction de sauvegarde de votre Model comme 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)
4
Alex Carlos

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

Supprimer/commenter ce modèle et tous ses usages. Appliquer les migrations. Cela supprime ce modèle, puis ajoute à nouveau le modèle, lance les migrations et vous avez un modèle propre avec le nouveau champ ajouté.

3
Harsh

Avez-vous déjà des entrées de base de données dans la table UserProfile? Si tel est le cas, lorsque vous ajoutez de nouvelles colonnes, la base de données ne sait pas comment la définir car elle ne peut pas être NULL. Par conséquent, il vous demande ce que vous voulez définir dans la colonne new_fields. Je devais supprimer toutes les lignes de cette table 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 tout nouveau qui voit cela.)

2
Arnold Lam

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 syncdb pour actualiser la base de données. et finalement vous exécutez ./manage.py makemigrations et ./manage.py migrate

2
gerachev

Vous pouvez utiliser la méthode de Django Doc depuis cette page https://docs.djangoproject.com/fr/1.8/ref/models/fields/#default

Créer par défaut et l'utiliser

def contact_default():
   return {"email": "[email protected]"}

contact_info = JSONField("ContactInfo", default=contact_default)
2
Denis Savenko

Honnêtement, je trouve que le meilleur moyen de contourner ce problème était de créer un autre modèle avec tous les champs nécessaires et nommés de manière légèrement différente. Effectuer des migrations. Supprimez le modèle inutilisé et réexécutez les migrations. Voila.

1
Josh

Ce que Django dit en réalité, c'est:

La table Userprofile contient des données et peut-être des valeurs new_field qui sont nuls, mais je ne sais pas, vous êtes donc sûr de vouloir marquer propriété non nullable, car si vous le faites, vous risquez une erreur si il y a des valeurs avec NULL

Si vous êtes certain qu'aucune des valeurs de la table userprofile n'est NULL, vous êtes libre et ignorez l'avertissement. 

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

2) Ignorer pour le moment et me laisser 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 rechercher toutes les instances UserProfile avec une valeur new_field vide et y placer une valeur correcte (ou une valeur par défaut, comme Django vous le demande), 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!

0
Taras Matsyk