Résolue

Création de table dans la base de données

# Résolution d'erreurs # Django # Migrations

bonjour à tous !

Sans le faire exprès, j'ai effacé la tables ShippingAddress et tout le contenu de mon fichier models.py. À l'intérieur du models.py, j'avais mon modèle Shopper et ma classe ShippingAddress.

J'ai réécrit le code à nouveau, mais je rencontre une KeyError lors de la migration pour recréer les tables

    fields = self.models[model_key].fields
KeyError: ('accounts', 'shippingaddress')

class CustomUserManager(BaseUserManager):
    def create_user(self, email, password, **kwargs):
        if not email:
            raise ValueError(" email is required")
        email = self.normalize_email(email)
        # on recupere notre model Shopper
        user = self.model(email=email, **kwargs)
        # on cripte le password
        user.set_password(password)
        user.save()
        return user

    def create_superuser(self, email, password, **kwargs):
        # on set les valeur sur notre dictionnaire
        kwargs["is_staff"] = True
        kwargs["is_superuser"] = True
        kwargs["is_active"] = True

        # on passe la dictionnaire a la fonction create_user
        return self.create_user(email=email, password=password, **kwargs)


class Shopper(AbstractUser):
    username = None
    email = models.EmailField(max_length=240, unique=True)

    USERNAME_FIELD = "email"
    # d'autres champs requis en + de email
    REQUIRED_FIELDS = []
    objects = CustomUserManager()

class Shippingaddress(models.Model):
    # user peut avoir plusieurs address
    user = models.ForeignKey(Shopper, on_delete=models.CASCADE)
    name = models.CharField(max_length=240)
    address_1 = models.CharField(max_length=1024, help_text="numéro de rue adresse de voirie")
    address_2 = models.CharField(max_length=1024, help_text="bâtiment, etage... ", blank=True)
    city = models.CharField(max_length=1024)
    zip_code = models.CharField(max_length=32)
    country = models.CharField(max_length=2, choices=[(c.alpha2.lower(), c.name) for c in countries])

Thibault houdon

Mentor

Salut Konimba !

Est-ce que tu peux nous montrer à quoi ressemble ton dossier de migrations ? Est-ce que tu sais si tu as fais un python manage.py makemigrations quand ton fichier models.py était vide ?

bonjour Thibault,
non je ne pense pas avoir fais cela mais les migrations doivent nous en apprendre davantage j'imagine.

voici le dossier de migration de l'application accounts :

class Migration(migrations.Migration):

    initial = True

    dependencies = [
        ('auth', '0012_alter_user_first_name_max_length'),
    ]

    operations = [
        migrations.CreateModel(
            name='Shopper',
            fields=[
                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('password', models.CharField(max_length=128, verbose_name='password')),
                ('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
                ('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
                ('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')),
                ('first_name', models.CharField(blank=True, max_length=150, verbose_name='first name')),
                ('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')),
                ('email', models.EmailField(blank=True, max_length=254, verbose_name='email address')),
                ('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')),
                ('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')),
                ('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')),
                ('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.group', verbose_name='groups')),
                ('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.permission', verbose_name='user permissions')),
            ],
            options={
                'verbose_name': 'user',
                'verbose_name_plural': 'users',
                'abstract': False,
            },
            managers=[
                ('objects', django.contrib.auth.models.UserManager()),
            ],
        ),
    ]

class Migration(migrations.Migration):

    dependencies = [
        ('accounts', '0001_initial'),
    ]

    operations = [
        migrations.AddField(
            model_name='shopper',
            name='stripe_id',
            field=models.CharField(blank=True, max_length=90),
        ),
        migrations.AlterField(
            model_name='shippingaddress',
            name='address_1',
            field=models.CharField(help_text='adresse de voirie et numéro de rue', max_length=1024),
        ),
    ]

class Migration(migrations.Migration):

    dependencies = [
        ('accounts', '0002_shopper_stripe_id_alter_shippingaddress_address_1'),
    ]

    operations = [
        migrations.AddField(
            model_name='shippingaddress',
            name='phone',
            field=phone_field.models.PhoneField(blank=True, help_text='numéro de téléphone', max_length=31),
        ),
    ]

hello,

et aussi petite question: tu avais déjà peuplé ta database avec des entrées dans chaque table ?

salut pa !
oui j'ai déjà inséré des enregistrements dans chaque table de la base de données.

Thibault houdon

Mentor

Salut Konimba !

Alors déboguer des problèmes de migration à distance c'est toujours compliqué, il y a beaucoup de choses qui peuvent faire que ça plante et on peut y passer longtemps (si tu as supprimé juste certains éléments dans ta base de données, ou seulement d'autres dans les modèles ou les migrations, il faut vraiment faire du debug assez poussé).

Ce que je te propose c'est de repartir de 0 avec ta base de données et tes migrations car vu qu'il s'agit du projet de formation j'imagine que tu n'as pas de données ultra importantes à conserver dans ta BDD.

Du coup tu peux suivre ces étapes pour repartir sur une "clean slate" :

1) Supprime tous les fichiers dans ton dossier de migration, sauf __init__.py.

2) Ensuite, ouvre ton shell Django et supprime aussi les tables de ta base de données. Tu peux faire ça avec la commande python manage.py shell suivie de :

from django.db import connection
with connection.cursor() as cursor:
    cursor.execute("DROP TABLE IF EXISTS nom_de_ta_table_1")
    cursor.execute("DROP TABLE IF EXISTS nom_de_ta_table_2")
    # continue comme ça pour chaque table que tu as.

Remplace nom_de_ta_table_1 par le nom de tes différentes tables.

Tu peux le faire aussi directement depuis le shell Postgres (psql) avec les mêmes commandes si tu préfères ou depuis une interface graphique comme TablePlus que tu sembles utiliser si je tiens compte de tes screenshots :)

3) Ensuite, sors de ton shell Django et fais un python manage.py makemigrations. Ça va recreer les fichiers de migration.

4) Et enfin, fais un python manage.py migrate pour recréer tes tables dans la base de données.

Tiens nous au courant !

Merci à vous tous,

Ça fonctionne parfaitement.
Je pense que dans les projets un peu plus avancés, comme celui-ci,
il aurait été plus prudent de ma part d'utiliser Git afin d'éviter ce genre de désagrément.
Peut-être que dans de nouveaux projets, vous pourriez l'inclure pour créer l'habitude et éviter ce type d'intervention.

Merci encore

Salut,

effectivement c'est toujours une bonne idée d'utiliser git. Surtout que Django recommande de garder les migrations dans le suivi Git. A bientôt.

Inscris-toi

(c'est gratuit !)

Inscris-toi

Tu dois créer un compte pour participer aux discussions.

Créer un compte

Rechercher sur le site

Formulaire de contact

Inscris-toi à Docstring

Pour commencer ton apprentissage.

Tu as déjà un compte ? Connecte-toi.