¿Cuál es la diferencia entre un OneToOne, ManyToMany, y un Campo ForeignKey en Django?


Estoy teniendo un poco de dificultad para conseguir mi cabeza alrededor de las relaciones en Django modelos.

¿Podría alguien explicar cuál es la diferencia entre un OneToOne, ManyToMany y ForeignKey?

Author: Johndt6, 2014-08-19

1 answers

Bueno, hay esencialmente dos preguntas aquí: {[30]]}

  1. ¿Cuál es la diferencia (en general) entre uno a uno, muchos a muchos, y las relaciones clave extranjeras
  2. Cuáles son sus diferencias específicas para Django.

Ambas preguntas se responden fácilmente a través de una simple búsqueda en Google, pero como no puedo encontrar un duplicado exacto de esta pregunta en TAN, voy a seguir adelante y responder.

Tenga en cuenta que en Django, las relaciones solo deben definirse en un lado de la relación.


ForeignKey

Una relación de clave foránea se conoce generalmente como una relación de muchos a uno. Tenga en cuenta que el reverso de esta relación es uno-a-muchos (que Django proporciona herramientas para acceder). Como su nombre lo indica, muchos objetos pueden estar relacionados con uno.

Person <--> Birthplace

En este ejemplo, una persona solo puede tener un lugar de nacimiento, pero un lugar de nacimiento puede estar relacionado con muchas personas. Veamos este ejemplo en Django. Di que estos son nuestros modelos:

class Birthplace(models.Model):
    city = models.CharField(max_length=75)
    state = models.CharField(max_length=25)

    def __unicode__(self):
        return "".join(self.city, ", ", self.state)

class Person(models.Model):
    name = models.CharField(max_length=50)
    birthplace = models.ForeignKey(Birthplace)

    def __unicode__(self):
        return self.name

Puede ver que no hay relaciones definidas dentro del modelo Birthplace, y una relación ForeignKey está definida dentro del modelo Person. Digamos que creamos los siguientes modelos (obviamente no en sintaxis Python):

  • Lugar de nacimiento: Dallas, Texas
  • Lugar de nacimiento: Nueva York, Nueva York
  • Persona: John Smith, Lugar de nacimiento: (Dallas, Texas)
  • Persona: Maria Lee, Lugar de nacimiento: (Dallas, Texas)
  • Persona: Daniel Lee, Lugar de nacimiento: (Nuevo Ciudad de York, Nueva York)

Ahora podemos ver cómo Django nos permite usar estas relaciones (tenga en cuenta que el ./manage.py shell es su amigo!):

>> from somewhere.models import Birthplace, Person
>> Person.objects.all()
[<Person: John Smith>, <Person: Maria Lee>, <Person: Daniel Lee>]
>> Birthplace.objects.all()
[<Birthplace: Dallas, Texas>, <Birthplace: New York City, New York>]

Puedes ver nuestros modelos creados. Ahora vamos a revisar el lugar de nacimiento de alguien:

>> person = Person.object.get(name="John Smith")
>> person.birthplace
<Birthplace: Dallas, Texas>
>> person.birthplace.city
Dallas

Digamos que quieres ver a todas las personas con un lugar de nacimiento determinado. Como dije antes, Django te permite acceder a relaciones inversas. Por defecto, Django crea un gestor (RelatedManager) en su modelo para manejar esto, llamado <model>_set, donde <model> es su nombre del modelo en minúsculas.

>> place = Birthplace.objects.get(city="Dallas")
>> place.person_set.all()
[<Person: John Smith>, <Person: Maria Lee>]

Tenga en cuenta que podemos cambiar el nombre de este administrador estableciendo el argumento de la palabra clave related_name en nuestra relación de modelo. Por lo tanto, cambiaríamos el campo birthplace en el modelo Person a:

birthplace = models.ForeignKey(Birthplace, related_name="people")

Ahora, podemos acceder a esa relación inversa con un nombre bonito:

>> place.people.all()
[<Person: John Smith>, <Person: Maria Lee>]

Uno a uno

Una relación uno-a-uno es bastante similar a una relación muchos-a-uno, excepto que restringe dos objetos a tener una relación única. Un ejemplo de esto sería un Usuario y un Perfil (que almacena información sobre el usuario). No hay dos usuarios que compartan el mismo perfil. Veamos esto en Django. No me molestaré en definir el modelo de usuario, ya que Django lo define para nosotros. Tenga en cuenta, sin embargo, que Django sugiere usar django.contrib.auth.get_user_model() para importar el usuario, así que eso es lo que haremos. El modelo de perfil puede definirse como sigue:

class Profile(models.Model):
    user = models.OneToOneField(settings.AUTH_USER_MODEL) # Note that Django suggests getting the User from the settings for relationship definitions
    fruit = models.CharField(max_length=50, help_text="Favorite Fruit")
    facebook = models.CharField(max_length=100, help_text="Facebook Username")

    def __unicode__(self):
        return "".join(self.fruit, " ", self.facebook)

Todo lo que necesitamos es un usuario con un perfil para probar esto en el shell:

  • Usuario: johndt6
  • Perfil: usuario: johndt6," Kiwi","blah_blah"

Ahora puede acceder fácilmente al perfil del usuario desde el modelo de usuario:

>> user = User.objects.all()[0]
>> user.username
johndt6
>> user.profile
<Profile: Kiwi blah_blah>
>> user.profile.fruit
Kiwi
>> profile = Profile.objects.get(user=user)
>> profile.user
<User: johndt6>

Por supuesto, puede personalizar el nombre de la relación inversa utilizando el argumento related_name como se indica anteriormente.


Muchos a muchos {[43]]}

Las relaciones de muchos a muchos pueden ser un poco complicadas. Permítanme comenzar diciendo que los campos de muchos a muchos son desordenados, y deben evitarse cuando sea posible. Teniendo en cuenta que, hay un montón de situaciones en las que una relación de muchos a muchos tiene sentido.

Una relación de muchos a muchos entre dos modelos define que cero, uno o más objetos del primer modelo pueden estar relacionados con cero, uno o más objetos del segundo modelo. Como ejemplo, imaginemos una empresa que defina su flujo de trabajo a través de proyectos. Un proyecto puede estar relacionado con ningún pedido, solo un pedido o varios pedidos. Una orden puede estar relacionada con ningún proyecto, un proyecto o muchos. Definamos nuestros modelos como así:

class Order(models.Model):
    product = models.CharField(max_length=150)  # Note that in reality, this would probably be better served by a Product model
    customer = models.CharField(max_length=150)  # The same may be said for customers

    def __unicode__(self):
        return "".join(self.product, " for ", self.customer)

class Project(models.Model):
    orders = models.ManyToManyField(Order)

    def __unicode__(self):
        return "".join("Project ", str(self.id))

Tenga en cuenta que Django creará un RelatedManager para el campo orders para acceder a la relación muchos a muchos.

Vamos a crear los siguientes objetos (en mi sintaxis inconsistente!):

  • Orden:" Nave espacial","NASA"
  • Orden: "Submarino", "US Navy"
  • Orden:" Coche de carreras","NASCAR"
  • Proyecto: órdenes: []
  • Proyecto: órdenes: [(Orden: "Nave espacial", "NASA")]
  • Proyecto: órdenes: [(Orden: "Nave espacial", "NASA"), (Orden: "Raza car", "NASCAR")]

Podemos acceder a estas relaciones de la siguiente manera:

>> Project.objects.all()
[<Project: Project 0>, <Project: Project 1>, <Project: Project 2>]
>> for proj in Project.objects.all():
..     print(proj)
..     proj.orders.all()  # Note that we must access the `orders`
..                        # field through its manager
..     print("")
Project 0
[]

Project 1
[<Order: Spaceship for NASA>]

Project 2
[<Order: Spaceship for NASA>, <Order: Race car for NASCAR>]

Tenga en cuenta que la orden de la NASA está relacionada con 2 proyectos, y la orden de la Marina de los Estados Unidos está relacionada con ninguno. También tenga en cuenta que un proyecto no tiene órdenes, y uno tiene múltiples.

También podemos acceder a la relación en sentido inverso de la misma manera que lo hicimos antes: {[30]]}

>> order = Order.objects.filter(customer="NASA")[0]
>> order.project_set.all()
[<Project: Project 0>, <Project: Project 2>]

Recursos

Buena explicación de las relaciones db proporcionada por @MarcB

Página de Wikipedia sobre Cardinalidad

Django Docs:

models.ForeignKey

models.OneToOneField

models.ManyToManyField

Relaciones uno-a-uno

Relaciones de muchos a muchos

 68
Author: Johndt6,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-10 18:29:00