2009-07-17 12 views
159

Quiero crear un objeto que contiene 2 enlaces a los usuarios. Por ejemplo:Django: ¿Por qué algunos campos de modelos chocan entre sí?

class GameClaim(models.Model): 
    target = models.ForeignKey(User) 
    claimer = models.ForeignKey(User) 
    isAccepted = models.BooleanField() 

pero estoy consiguiendo los siguientes errores cuando se ejecuta el servidor:

  • Accessor de campo enfrentamientos 'objetivo' campo relacionado con 'User.gameclaim_set'. Agregue un argumento related_name a la definición de 'objetivo'.

  • Accessor de choques 'claimer' campo campo relacionado con 'User.gameclaim_set'. Agregue un argumento related_name a la definición de 'claimer'.

¿Puede usted explicar porqué estoy consiguiendo los errores y cómo solucionarlos?

+0

mensajes de error _These son realmente good._ Ya explican cómo solucionarlos. Y leyendo en ** ['related_name' en la documentación] ** (https://docs.djangoproject.com/en/dev/ref/models/fields/#arguments) explicará por qué ocurren. –

Respuesta

277

Tiene dos claves foráneas para el usuario. Django crea automáticamente una relación inversa entre el usuario y GameClaim, que generalmente es gameclaim_set. Sin embargo, debido a que tiene dos FK, tendría dos atributos gameclaim_set, lo cual es obviamente imposible. Entonces debes decirle a Django qué nombre usar para la relación inversa.

Utilice el atributo related_name en la definición de FK. p.ej.

class GameClaim(models.Model): 
    target = models.ForeignKey(User, related_name='gameclaim_targets') 
    claimer = models.ForeignKey(User, related_name='gameclaim_users') 
    isAccepted = models.BooleanField() 
+47

Buena respuesta, pero no creo que haya tenido éxito en evitar la rudeza: P El "por qué" no es obvio a menos que sepa cómo funciona django internamente. – Kenny

+12

Para alguien que acaba de aprender el marco, esto no sería obvio. – jkyle

+2

Gracias, el mensaje de error tampoco fue obvio para mí, pero su explicación sobre la relación inversa fue muy útil. – ruquay

6

El modelo User está tratando de crear dos campos con el mismo nombre, uno para el GameClaims que tienen que User como el target, y otro para el GameClaims que tienen que User como el claimer. Aquí está el docs on related_name, que es la manera en que Django le permite establecer los nombres de los atributos para que los autogenerados no entren en conflicto.

5

El PO no está utilizando una clase base abstracta ... pero si usted es, usted encontrará que la codificación duro related_name en el FK (por ejemplo ..., related_name = "myname") resultará en varios de estos errores de conflicto: uno para cada clase heredada de la clase base. El enlace proporcionado a continuación contiene la solución alternativa, que es simple, pero definitivamente no es obvia.

De la documentación de Django ...

Si está utilizando el atributo related_name en un ForeignKey o ManyToManyField, debe siempre especificar un nombre único revés para el campo . Esto normalmente causar un problema en las clases base abstractas, desde los campos de esta clase son incluidos en cada uno de los niños clases, con exactamente los mismos valores para los atributos (incluyendo related_name) cada vez.

Más información here.

0

que parecen venir a través de este ocasionalmente cuando agrego un submódulo como una aplicación a un proyecto Django, por ejemplo, dada la siguiente estructura:

myapp/ 
myapp/module/ 
myapp/module/models.py 

Si añado lo siguiente para INSTALLED_APPS:

'myapp', 
'myapp.module', 

Django parece procesar el archivo myapp.mymodule models.py dos veces y arroja el error anterior. Esto se puede resolver mediante la no inclusión del módulo principal en la lista INSTALLED_APPS:

'myapp.module', 

Incluyendo el myapp en lugar de myapp.module hace que todas las tablas de bases de datos que se crean con nombres incorrectos, por lo que esta parece ser la forma correcta de hacerlo eso.

me encontré con este aviso en la búsqueda de una solución a este problema por lo pensé en poner esto aquí :)

0

Simplemente añadiendo a la respuesta de Jordan (gracias por la punta Jordan) también puede ocurrir si importa el nivel por encima de las aplicaciones y luego importar las aplicaciones, por ejemplo,

myproject/ apps/ foo_app/ bar_app/

Así que si va a importar aplicaciones, foo_app y bar_app entonces usted podría conseguir este problema. Había aplicaciones, foo_app y bar_app todos los que figuran en settings.INSTALLED_APPS

y desea evitar la importación de aplicaciones de todos modos, porque entonces usted tiene la misma aplicación instalada en 2 espacios de nombres diferentes

apps.foo_app y foo_app

-2

Tuve el mismo problema. Usando run python manage.py makemigrations "appname" lo arregló por mí. Borré accidentalmente algunos archivos de migración. No es necesario volver a eliminar ningún archivo.

0

A veces tiene que usar formato adicional en related_name - en realidad, en cualquier momento cuando se usa la herencia.

class Value(models.Model): 
    value = models.DecimalField(decimal_places=2, max_digits=5) 
    animal = models.ForeignKey(
     Animal, related_name="%(app_label)s_%(class)s_related") 

    class Meta: 
     abstract = True 

class Height(Value): 
    pass 

class Weigth(Value): 
    pass 

class Length(Value): 
    pass 

No hay conflicto aquí, pero el nombre relacionado se define una vez y Django se encargará de crear nombres de relación únicos.

a continuación en los niños de la clase de valor, tendrá acceso a:

herdboard_height_related 
herdboard_lenght_related 
herdboard_weight_related 
Cuestiones relacionadas