New to django and ORM. So a basic question about data inserts

39 views
Skip to first unread message

Cassium

unread,
Apr 10, 2017, 3:35:59 PM4/10/17
to Django users
Say I am collecting residence history and I allow the user to submit up to five previous addresses. I have a PEOPLE model and RESIDENCES model and anticipate a many-to-many relationship between. Back when I was working with Joomla I would have manages these models (well, tables) with a table in the middle called PEOPLE_RESIDENCES which would have also included the dates of that relationship. And I understand that I can do that with a model and the 'through' statement.

But here is where I'm lost. When I get a form submitted from the user, how do I get all the correct rows written to the various tables. Assume for simplicity sake that I have a new person being submitted as follows

PERSON
--RESIDENCE 1, 2005-2008
--RESIDENCE 2, 2008-2011
--RESIDENCE 3, 2012-2016

So I would need one new row on the PEOPLE table, three new rows on the PEOPLE_RESIDENCES table and up to three new rows on the RESIDENCES table. I'm lost on how the necessary rows are added to the PEOPLE_RESIDENCES table. Is there some sort of value returned from the create/insert statements or do I send the ORM a structured object which manages all of the INSERTS including the relatioinships? Or is there something else I have to do?

Lachlan Musicman

unread,
Apr 10, 2017, 6:44:17 PM4/10/17
to django...@googlegroups.com


------
The most dangerous phrase in the language is, "We've always done it this way."

- Grace Hopper

Have you read this part of the documentation? It describes exactly what you need:

https://docs.djangoproject.com/en/1.11/topics/db/models/#extra-fields-on-many-to-many-relationships
 
With regard to "how do I get the correct record written to the right table" you are putting the cart before the horse.

The whole idea of an ORM is to disappear that type of consideration (despite it being exactly what *is* happening in the background).

In the example of the documentation, when you create a Group, it is "saved to the correct table when you call the save() method (successfully)". When you create a Person, it is also saved to the correct table when you call the save() method.

When you create a Membership that links to both the Person and the Group, it too is saved to the correct table when you call the save() method.

Cheers
L.

Camilo Torres

unread,
Apr 11, 2017, 7:33:17 PM4/11/17
to Django users
Hi,
Lets suppose we simplify your problem and we have these 2 django models:
from django.db import models


class Person(models.Model):
    name = models.CharField(max_length=255, null=False, blank=False)

    def __str__(self):
        return self.name


class Residence(models.Model):
    address = models.CharField(max_length=255, null=False, blank=False)
    person = models.ForeignKey('Person', null=False, blank=False)

    def __str__(self):
        return '%s: %s' % (self.person.name, self.address)


Notice I simplified the data so save in each model.

This is how you create data for these models. I ran these command in the django shell (python manage.py shell):
In [1]: from residence.models import Person, Residence
In [3]: p = Person.objects.create(name='Abu UIfreoledo')
In [4]: p
Out[4]: <Person: Abu UIfreoledo>
In [6]: r1 = Residence.objects.create(address='yyyyyyy', person=p)
In [7]: r2 = Residence.objects.create(address='cccc', person=p)


This is another way of creating and saving models:
In [8]: other_person = Person()
In [9]: other_person.name = 'Jekolaw Yhjosw'
In [10]: other_person.save()
In [11]: res1 = Residence()
In [12]: res1.address = 'keikdioekekdiekecnchdhwe'
In [13]: res1.person = other_person
In [14]: res1.save()


Notice this generates these 2 tables in Postgres:
temp2=# \d residence_person
                                 Table "public.residence_person"
 Column |          Type          |                           Modifiers                          
--------+------------------------+---------------------------------------------------------------
 id     | integer                | not null default nextval('residence_person_id_seq'::regclass)
 name   | character varying(255) | not null
Indexes:
    "residence_person_pkey" PRIMARY KEY, btree (id)
Referenced by:
    TABLE "residence_residence" CONSTRAINT "residence_residence_person_id_d4f422a8_fk_residence_person_id" FOREIGN KEY (person_id) REFERENCES residence_person(id) DEFERRABLE INITIALLY DEFERRED

temp2=# \d residence_residence
                                  Table "public.residence_residence"
  Column   |          Type          |                            Modifiers                            
-----------+------------------------+------------------------------------------------------------------
 id        | integer                | not null default nextval('residence_residence_id_seq'::regclass)
 address   | character varying(255) | not null
 person_id | integer                | not null
Indexes:
    "residence_residence_pkey" PRIMARY KEY, btree (id)
    "residence_residence_person_id_d4f422a8" btree (person_id)
Foreign-key constraints:
    "residence_residence_person_id_d4f422a8_fk_residence_person_id" FOREIGN KEY (person_id) REFERENCES residence_person(id) DEFERRABLE INITIALLY DEFERRED


In this example the Residence instances are not reused or shared across Persons.


Now suppose one want to reuse the residences, meaning we will use 3 tables instead of 2, One for Persona, as before, one for Residence (without the foreign key to the Person) and a third relation to relate both and hold the dates.

from django.db import models


class Person(models.Model):
    name = models.CharField(max_length=255, null=False, blank=False)
    residences = models.ManyToManyField('Residence', through='ResidenceDates')

    def __str__(self):
        return self.name


class Residence(models.Model):
    address = models.CharField(max_length=255, null=False, blank=False)

    def __str__(self):
        return self.address


class ResidenceDates(models.Model):
    dates = models.CharField(max_length=255, null=False, blank=False)
    person = models.ForeignKey('Person', null=False, blank=False)
    residence = models.ForeignKey('Residence', null=False, blank=False)


Notice the join table ResidenceDates, it has foreign keys to both Person and Residence models. Also notices the many to many field. This generates the 3 tables you need (not shown here).

In [3]: p1 = Person.objects.create(name='p1')
In [4]: p2 = Person.objects.create(name='p2')
In [5]: p3 = Person.objects.create(name='p3')
In [6]: res1 = Residence.objects.create(address='a1')
In [7]: res2 = Residence.objects.create(address='a2')
In [8]: res3 = Residence.objects.create(address='a3')
In [9]: res4 = Residence.objects.create(address='a4')
In [10]: res5 = Residence.objects.create(address='a5')
In [11]: ResidenceDates.objects.create(person=p1, residence=res1, dates='2003-2005')
Out[11]: <ResidenceDates: ResidenceDates object>
In [12]: ResidenceDates.objects.create(person=p1, residence=res2, dates='2005-2008')
Out[12]: <ResidenceDates: ResidenceDates object>
In [13]: ResidenceDates.objects.create(person=p1, residence=res4, dates='2009-2017')
Out[13]: <ResidenceDates: ResidenceDates object>
In [15]: ResidenceDates.objects.create(person=p2, residence=res4, dates='2000-2001')
Out[15]: <ResidenceDates: ResidenceDates object>
In [16]: ResidenceDates.objects.create(person=p2, residence=res5, dates='2002-2010')
Out[16]: <ResidenceDates: ResidenceDates object>
In [17]: ResidenceDates.objects.create(person=p2, residence=res4, dates='2011-2016')
Out[17]: <ResidenceDates: ResidenceDates object>

Hope this help.
Please read the django tutorial and model documentation:
Reply all
Reply to author
Forward
0 new messages