tabla queryset plantilla modelos girls girl formulario form example dinamica python django django-models django-orm

python - queryset - tabla dinamica django



¿Cómo crear un objeto para un modelo de Django con un campo de muchos a muchos? (5)

No puede crear relaciones m2m a partir de objetos no guardados. Si tiene los pks, intente esto:

sample_object = Sample() sample_object.save() sample_object.users.add(1,2)

Actualización: Después de leer la respuesta de Saverio , decidí investigar el tema un poco más en profundidad. Aquí están mis hallazgos.

Esta fue mi sugerencia original. Funciona, pero no es óptimo. (Nota: estoy usando Bar s y un Foo lugar de User s y un Sample , pero entiendes la idea).

bar1 = Bar.objects.get(pk=1) bar2 = Bar.objects.get(pk=2) foo = Foo() foo.save() foo.bars.add(bar1) foo.bars.add(bar2)

Genera un enorme total de 7 consultas:

SELECT "app_bar"."id", "app_bar"."name" FROM "app_bar" WHERE "app_bar"."id" = 1 SELECT "app_bar"."id", "app_bar"."name" FROM "app_bar" WHERE "app_bar"."id" = 2 INSERT INTO "app_foo" ("name") VALUES () SELECT "app_foo_bars"."bar_id" FROM "app_foo_bars" WHERE ("app_foo_bars"."foo_id" = 1 AND "app_foo_bars"."bar_id" IN (1)) INSERT INTO "app_foo_bars" ("foo_id", "bar_id") VALUES (1, 1) SELECT "app_foo_bars"."bar_id" FROM "app_foo_bars" WHERE ("app_foo_bars"."foo_id" = 1 AND "app_foo_bars"."bar_id" IN (2)) INSERT INTO "app_foo_bars" ("foo_id", "bar_id") VALUES (1, 2)

Estoy seguro de que podemos hacerlo mejor. Puede pasar varios objetos al método add() :

bar1 = Bar.objects.get(pk=1) bar2 = Bar.objects.get(pk=2) foo = Foo() foo.save() foo.bars.add(bar1, bar2)

Como podemos ver, pasar múltiples objetos guarda un SELECT :

SELECT "app_bar"."id", "app_bar"."name" FROM "app_bar" WHERE "app_bar"."id" = 1 SELECT "app_bar"."id", "app_bar"."name" FROM "app_bar" WHERE "app_bar"."id" = 2 INSERT INTO "app_foo" ("name") VALUES () SELECT "app_foo_bars"."bar_id" FROM "app_foo_bars" WHERE ("app_foo_bars"."foo_id" = 1 AND "app_foo_bars"."bar_id" IN (1, 2)) INSERT INTO "app_foo_bars" ("foo_id", "bar_id") VALUES (1, 1) INSERT INTO "app_foo_bars" ("foo_id", "bar_id") VALUES (1, 2)

No sabía que también puedes asignar una lista de objetos:

bar1 = Bar.objects.get(pk=1) bar2 = Bar.objects.get(pk=2) foo = Foo() foo.save() foo.bars = [bar1, bar2]

Desafortunadamente, eso crea un SELECT adicional:

SELECT "app_bar"."id", "app_bar"."name" FROM "app_bar" WHERE "app_bar"."id" = 1 SELECT "app_bar"."id", "app_bar"."name" FROM "app_bar" WHERE "app_bar"."id" = 2 INSERT INTO "app_foo" ("name") VALUES () SELECT "app_foo_bars"."id", "app_foo_bars"."foo_id", "app_foo_bars"."bar_id" FROM "app_foo_bars" WHERE "app_foo_bars"."foo_id" = 1 SELECT "app_foo_bars"."bar_id" FROM "app_foo_bars" WHERE ("app_foo_bars"."foo_id" = 1 AND "app_foo_bars"."bar_id" IN (1, 2)) INSERT INTO "app_foo_bars" ("foo_id", "bar_id") VALUES (1, 1) INSERT INTO "app_foo_bars" ("foo_id", "bar_id") VALUES (1, 2)

Tratemos de asignar una lista de `pk''s, como sugirió saverio:

foo = Foo() foo.save() foo.bars = [1,2]

Como no buscamos las dos Bar , guardamos dos declaraciones SELECT , lo que da como resultado un total de 5:

INSERT INTO "app_foo" ("name") VALUES () SELECT "app_foo_bars"."id", "app_foo_bars"."foo_id", "app_foo_bars"."bar_id" FROM "app_foo_bars" WHERE "app_foo_bars"."foo_id" = 1 SELECT "app_foo_bars"."bar_id" FROM "app_foo_bars" WHERE ("app_foo_bars"."foo_id" = 1 AND "app_foo_bars"."bar_id" IN (1, 2)) INSERT INTO "app_foo_bars" ("foo_id", "bar_id") VALUES (1, 1) INSERT INTO "app_foo_bars" ("foo_id", "bar_id") VALUES (1, 2)

Y el ganador es:

foo = Foo() foo.save() foo.bars.add(1,2)

Pasar pk s a add () nos da un total de 4 consultas:

INSERT INTO "app_foo" ("name") VALUES () SELECT "app_foo_bars"."bar_id" FROM "app_foo_bars" WHERE ("app_foo_bars"."foo_id" = 1 AND "app_foo_bars"."bar_id" IN (1, 2)) INSERT INTO "app_foo_bars" ("foo_id", "bar_id") VALUES (1, 1) INSERT INTO "app_foo_bars" ("foo_id", "bar_id") VALUES (1, 2)

Mi modelo ->

class Sample(models.Model): users = models.ManyToManyField(User)

Quiero hacer esto (guardar usuarios, usuario1 y usuario2 en este modelo) ->

user1 = User.objects.get(pk=1) user2 = User.objects.get(pk=2) sample_object = Sample( users = user1, users=user2 ) sample_object.save()

Sé que está mal: D, pero estoy seguro de que obtienes lo que quiero hacer ... ¿cómo lo harías?


Para futuros visitantes, puede crear un objeto y todos sus objetos m2m en 2 consultas utilizando el nuevo bulk_create en django 1.4. Tenga en cuenta que esto solo se puede utilizar si no requiere ningún procesamiento previo o posterior en los datos con los métodos o señales save (). Lo que insertas es exactamente lo que estará en la base de datos

Puede hacer esto sin especificar un modelo "directo" en el campo. Para completar, el siguiente ejemplo crea un modelo de Usuarios en blanco para imitar lo que el cartel original estaba pidiendo.

from django.db import models class Users(models.Model): pass class Sample(models.Model): users = models.ManyToManyField(Users)

Ahora, en un intérprete de comandos u otro código, cree 2 usuarios, cree un objeto de muestra y agregue de forma masiva los usuarios a ese objeto de muestra.

Users().save() Users().save() # Access the through model directly ThroughModel = Sample.users.through users = Users.objects.filter(pk__in=[1,2]) sample_object = Sample() sample_object.save() ThroughModel.objects.bulk_create([ ThroughModel(users_id=users[0].pk, sample_id=sample_object.pk), ThroughModel(users_id=users[1].pk, sample_id=sample_object.pk) ])


Podría reemplazar el conjunto de objetos relacionados de esta forma (nuevo en Django 1.9):

new_list = [user1, user2, user3] sample_object.related_set.set(new_list)


RelatedObjectManagers son diferentes "atributos" que los campos en un modelo. La forma más sencilla de lograr lo que estás buscando es

sample_object = Sample.objects.create() sample_object.users = [1, 2]

Eso es lo mismo que asignar una lista de usuarios, sin las consultas adicionales y la construcción del modelo.

Si el número de consultas es lo que le molesta (en lugar de la simplicidad), la solución óptima requiere tres consultas:

sample_object = Sample.objects.create() sample_id = sample_object.id sample_object.users.through.objects.create(user_id=1, sample_id=sample_id) sample_object.users.through.objects.create(user_id=2, sample_id=sample_id)

Esto funcionará porque ya sabemos que la lista de "usuarios" está vacía, por lo que podemos crear sin pensar.


Django 1.9
Un ejemplo rápido:

sample_object = Sample() sample_object.save() list_of_users = DestinationRate.objects.all() sample_object.users.set(list_of_users)