2010-12-23 12 views
11

Tengo un método que funciona, pero parece muy torpe, y creo que hay una mejor manera de hacerlo.Instancia instancia de modelo con manytomany campo en Django

Tengo un modelo que relaciona a un usuario de mi sitio (un clon de twitter para fines de aprendizaje) con una lista de otros usuarios.

Ahora cuando creo un nuevo usuario, quiero inicializar esa lista con el usuario como miembro de la lista.

mi modelo es:

class FollowerList(models.Model) 
    follower = models.ForeignKey(User,related_name="follower") 
    followed = models.ManyToManyField(User,related_name="followed" 

el código en mi opinión de que estoy usando en este momento es

user = User.objects.get(username=uname) 
flst = FollowerList() 
flst.follower = user 
flst.save() 
flst.followed.add(user) 
flst.save() 

Me parece que hay debería ser un método para la creación de este sin llamar a save() dos veces, pero parece que no puedo encontrarlo en los documentos ni en ningún otro lado.

Respuesta

12

No es necesario llamar a guardar después de la many2many.add()

También podría acortar el código de 2 líneas:

flst = FollowerList.objects.create(follower=user) 
flst.followed.add(user) 
+0

el problema cuando hago esto es que me sale un error diciendo que el objeto FollowerList debe tener una clave primaria antes de que pueda agregarle las instancias de ManyToManyField. Y la única forma en que puedo ver para obtener eso es crear una instancia primero y guardarlo, luego agregar el otro campo. –

+0

Bueno, FollowerList.objects.create (seguidor = usuario) le dará una clave principal. Hace el salvado. –

+0

¿hay algún enlace a documentos sobre este tema? No puedo encontrar ningún ... – jperelli

4

respuesta de Yuji es correcta. No puede agregar un objeto a un campo M2M hasta que se haya guardado. Sin embargo, quería mencionar una forma más corta de crear instancias.

user = User.objects.get(username=uname) 
flst = FollowerList(follower=user) #use key word args to assign fields 
flst.save() 
flst.followed.add(user) 
# don't need to save after adding an object to many to many field. 

Me parece que la sintaxis ligeramente mejor que la creación de una instancia vacía y la asignación de campos. Aunque el método objects.create() (mencionado por Yuki) es aún más agradable.

2

Una respuesta tardía a esta: también se puede anular el constructor (__init__) de la siguiente manera:

class FollowerList(models.Model): 
    follower = models.ForeignKey(User,related_name="follower") 
    followed = models.ManyToManyField(User,related_name="followed" 

    def __init__(*args, followed=[], **kwargs): 
     super(FollowerList, self).__init__(*args, **kwargs) 
     self.save() 
     for user in followed: 
      self.followed.add(user) 

es decir que aquí he manejado de manera explícita el argumento followed palabra clave en la función __init__, al pasar de todo otros args y kwargs en el constructor predeterminado. La llamada a save asegura que el objeto ha sido registrado y, por lo tanto, puede utilizarse en una relación m2m.

Este continuación, le permite hacer crear FollowerList con una línea, por ejemplo

flst = FollowerList(follower=user, followed=[user,]) 

Por otra parte, como ha señalado Johannes, el ahorro de un modelo en el __init__ No es de esperar. El enfoque preferido sería la creación de un método Manager - ver aquí para más detalles: https://docs.djangoproject.com/en/1.9/topics/db/managers/ y luego crear un FollowerList:

fl = FollowerList.objects.create(*args, followed, **kwargs) 
+1

no realmente Sin embargo, si guardar el modelo en el método init es una buena idea. no esperaría que eso ocurriera si creo una instancia de un nuevo objeto (si quiero tenerlo guardado directamente en la base de datos, prefiero llamar a objects.create()) –

Cuestiones relacionadas