80 votes

Écrire une fonction __init__ à utiliser dans le modèle django

J'essaie d'écrire un __init__ pour l'un de mes modèles afin que je puisse créer un objet en le faisant :

p = User('name','email')

Quand j'écris le modèle, j'ai :

def __init__(self, name, email, house_id, password):
    models.Model.__init__(self)
    self.name = name
    self.email = email

Cela fonctionne et je peux enregistrer l'objet dans la base de données, mais quand je fais User.objects.all() il n'y a rien qui ressort, sauf si je sors mon __init__ fonction. Avez-vous des idées ?

2 votes

Pourquoi faites-vous cela ? Cette capacité fait partie d'un modèle Django sans que vous ayez à écrire le moindre code.

1 votes

Lorsque j'essaie sans l'init, ils sont tous placés dans le mauvais champ pour une raison quelconque, à moins que je ne spécifie User(name='aoeu'), ce qui prend beaucoup d'espace supplémentaire.

6 votes

Qu'est-ce qui ne va pas avec les affectations explicites champ=valeur ? À long terme, vous serez probablement plus heureux. Après tout, vous n'écrivez que très peu de ce type de lignes de code.

114voto

Baldu Points 3374

Le plus simple serait de s'appuyer sur les fonctionnalités intégrées de Django et de passer des paramètres nommés.

p = User(name="Fred", email="fred@example.com")

Mais si vous voulez économiser quelques frappes, je vous suggère d'ajouter une méthode de commodité statique à la classe au lieu de jouer avec l'initialisateur.

# In User class declaration
@classmethod
def create(cls, name, email):
  return cls(name=name, email=email)

# Use it
p = User.create("Fred", "fred@example.com")

2 votes

Ouais, une méthode d'usine est la voie à suivre ici. Tu pourrais aussi envisager de la mettre dans le Manager. Jouer avec la signature du constructeur va certainement casser les choses.

4 votes

La méthode @classmethod sur la création est également plus agréable.

51voto

Django s'attend à ce que la signature du constructeur d'un modèle soit (self, *args, **kwargs) ou un fac-similé raisonnable. Votre changement de signature en quelque chose de complètement incompatible l'a cassé.

4 votes

À partir de Django 2.1, la réponse d'Ignacio est la bonne et doit être acceptée. Dans la documentation de la version 2.1, il est dit que You may be tempted to customize the model by overriding the __init__ method. If you do so, however, take care not to change the calling signature as any change may prevent the model instance from being saved. de : docs.djangoproject.com/fr/2.1/ref/models/instances

0 votes

Le lien du commentaire ci-dessus contient également des suggestions sur la façon de faire différemment ce que vous voulez faire. Remplacement de __init__ peut conduire à toutes sortes de bugs étranges, comme je l'ai appris par expérience cet après-midi.

24voto

austinheiman Points 521

La bonne réponse est d'éviter d'écraser __init__ et écrivez une méthode de classe telle que décrite dans le document Documentation sur Django .

Mais cela peut être fait comme vous essayez de le faire, il suffit d'ajouter en *args, **kwargs pour être accepté par votre __init__ et les transmet à l'appel de la super méthode.

def __init__(self, name, email, house_id, password, *args, **kwargs):
        super(models.Model, self).__init__(self, *args, **kwargs)
        self.name = name
        self.email = email

7 votes

Super(models.Model, self).__init__(*args, **kwargs)

2 votes

super(<YourModelName>, self).__init__(*args, **kwargs)

2voto

unflores Points 145

Ne créez pas de modèles avec des paramètres args. Si vous créez un modèle comme ceci :

 User('name','email')

Cela devient très vite illisible car la plupart des modèles nécessitent plus que cela pour l'initialisation. Vous pourriez très facilement vous retrouver avec :

User('Bert', 'Reynolds', 'me@bertreynolds.com','0123456789','5432106789',....)

Un autre problème est que vous ne savez pas si "Bert" est le prénom ou le nom. Les deux derniers chiffres pourraient facilement être un numéro de téléphone et un identifiant système. Mais si ce n'est pas explicite, vous les confondrez plus facilement, ou vous mélangerez l'ordre si vous utilisez des identifiants. De plus, le fait de procéder par ordre imposera une contrainte supplémentaire aux autres développeurs qui utilisent cette méthode et ne se souviendront pas de l'ordre arbitraire des paramètres.

Vous devriez plutôt préférer quelque chose comme ceci :

User(
    first_name='Bert',
    last_name='Reynolds',
    email='me@bertreynolds.com',
    phone='0123456789',
    system_id='5432106789',
)

Si c'est pour des tests ou quelque chose comme ça, vous pouvez utiliser une usine pour créer rapidement des modèles. Le lien factory boy peut être utile : http://factoryboy.readthedocs.org/en/latest/

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X