Bienvenue sur IndexError.

Ici vous pouvez poser des questions sur Python et le Framework Django.

Mais aussi sur les technos front comme React, Angular, Typescript et Javascript en général.

Consultez la FAQ pour améliorer vos chances d'avoir des réponses à vos questions.

Migration vers un modèle utilisateur personnalisé en Django 1.7

+5 votes

J'ai commencé un projet avec le modèle User fourni nativement dans django. Cependant, j'aimerais passer vers un modèle personnalisé, pour pouvoir rajouter des champs et des méthodes. Après quelques recherches, je n'ai pas trouvé d'informations à jour sur la procédure à suivre avec Django 1.7 : les quelques réponses, comme celle-ci concernent les versions antérieures, avec South.

L'idéal serait de pouvoir le faire proprement avec des migrations, car j'ai déjà pas mal de données utilisateurs que je ne peux pas me permettre de perdre.

Comment générer ou écrirer ces fichiers pour :

  • Que les ForeignKey depuis d'autres modèles continuent de fonctionner
  • Que les données soient migré du modèle User natif vers mon modèle personnalisé

Je ne sais vraiment pas par ou commencer !

demandé 26-Fev-2015 par eliotberriot (678 points)
reclassée 26-Fev-2015 par foxmask

Techniquement, ce qui etait vrai pour South, l'est tjrs avec l'api native. Je suis justement entrain de tester une migration du User natif, vers un User custom. Si je me casse pas les dents, je posterai comment je m'y suis pris.

J'ai quand même l'impression qu'il y a quelques changements par rapport à South, parce que quand je suis la procédure détaillée dans la question que j'ai linkée, j'ai des erreurs lors de la génération de la migration, types conflits de noms sur les champs (forcément, le User de base et le mien qui hérite de AbstractUser ont les mêmes noms de champ). Si tu y arrive, ça m'aiderait vraiment que tu poste la démarche (ou que tu me donne le lien vers la procédure suivie). Aucune urgence de mon côté.

Justement, le fichier de migration, faut le generer, et ensuite faut l'editer, pour bien lui dire quoi faire. En fait, faut d'abord avoir ds un premier temps, une phase de transition ds laquelle les deux types de users existent.

Lorsque tout baignera cote code, faudra dire a django via un fichier de migration (generé et customisé a la main) de migrer les données d'une table vers l'autre et dire a django ensuite via settings.py de plus utiliser le User natif, mais plutot le custom.

Mais oui, c'est vrai que c'est pas forcement simple :\

Je ne suis pas sur de pouvoir repondre a cette question, tellement la reponse est longue et difficile a expliquer. Je vais me contenter d'un commentaire pointant vers deux depots git. Le premier depot explique comment etendre la class AbstractUser et creer une classe User custom. Ceci ne fonctionne qu'au tout debut, lorsqu'il n'y a pas encore eu de migrate.

Le second depot montre brivement comment migrer du default User class vers un custom User class. Je ne suis pas vraiment satisfait, mais j'ai rien trouvé de plus simple. Aussi, le projet ne fonctionne pas tel qu'il est, il faut encore creer un manager custom CustomMyUserManager pour que la classe MyUser soit complete.

Pour comprendre le processus, faut juste parcourir le code depuis le premier commit jusqu'au dernier, le tout en lisant les commentaires au fur et a mesure.

J'espere au moins que cela te mettra sur une bonne piste.

En suivant ta démarche, j'ai pu générer des fichiers de migration et transférer les données de l'ancien vers le nouveau modèle User. Je peux exécuter ces scripts de migrations, j'ai même réussi à lancer le syncdb.

Seulement, j'ai des modèles qui font référence à mon modèle utilisateur à travers des ForeignKey, via settings.AUTH_USER_MODEL. Et j'ai l'impression que ces ForeignKey pointent toujours vers l'ancienne table User (ce qui me paraît logique, car je n'ai pas lancé de migration par rapport à ce point). Du coup, j'ai des erreurs type Lookup failed for model referenced by field monapp.MonModele.user: users.CustomUser.

Je ne sais pas trop quoi faire =/

J'ai peur de pas avoir bien saisi. Tu parles de syncdb?! Tu as voulu dire migrate je suppose?! J'utilise la version 1.7.5 de django ds laquelle syncdb est deprecated :\ Si une ForeignKey pointe tjrs vers la classe User par defaut, cela signifie que tu dois modifier ton settings.py et ecrire AUTH_USER_MODEL='monApp.MaClasseUser' et non AUTH_USER_MODEL='monApp.MonModele.MaClasseUser'

1 Réponse

+4 votes
 
Meilleure réponse

Une des manieres d'ajouter des informations a ton User, est d'etendre la classe AbstractUser, cette methode n'est interessante qu'au tout debut du projet, lorsque tu n'as pas encore fait de migrate. Elle ne fonctionne pas (en tout cas, j'ai pas reussi) lorsque la base a deja des utilisateurs enregistrés avec la classe User. Exemple dans ce depot

Une maniere tres simple d'ajouter des informations supplementaires a tes utilisateurs, ici on est dans le cas où tu as deja plusieurs Users enregistrés dans ta base, (mais ça marche aussi dans le cas precedent):

  • Creer une classe UserProfile qui va contenir ces informations en plus.
  • Creer un signal qui va lancer la creation d'un UserProfile apres creation d'un User.
  • Mettre a jour la variable AUTH_USER_PROFILE pour informer django.
  • Modifier l'admin interface pour voir tout ce qu'il y a dans UserProfile.

Le depot contenant tout le code.

Cette reponse devrait suffire a resoudre le probleme. Eventuellement, je la completerai pour parler de la technique du Proxy Model et aussi de la technique du monkey patching, meme si cette methode est deconseillée.

répondu 8-Mar-2015 par Nsukami_ (1,998 points)
sélectionné 9-Mar-2015 par eliotberriot

C'est cette méthode que j'utilise actuellement sur le projet, mais je trouve que cela rajoute un poil en lourdeur puisqu'on passe apr un modèle intermédiaire systématiquement (avec les requêtes additionelles que cela implique).

Comme je n'arrive pas à migrer, je vais rester sur cette méthode du profil utilisateur.

En ce qui concerne la mise en oeuvre, je ne vois rien de plus simple que cette maniere de faire, sinon tu peux aussi faire du monkey patching comme je disais. Methode qui fait aussi le job, mais deconseillée car le best practice est de ne jamais modifier directement du code third party.

Concernant le monkey-patching, a partir de Django 1.7, si tu monkey-patch un modele de Django, makemigrations va generer une nouvelle migration directement dans la lib django (django.contrib.auth par exemple pour User). Tu peux aussi redéfinir MIGRATION_MODULES pour l'app ou tu monkey-patch afin d'avoir ces migrations dans ton projet, mais c'est pas ideal non plus. Pas encore trouve de solution parfaite...

...