ManyToManyField is this right?

88 views
Skip to first unread message

David Wagner

unread,
Jun 27, 2012, 9:57:24 AM6/27/12
to django...@googlegroups.com
I'm a self taught programmer who hasn't done much of anything for years so please forgive me if this question is naive. I have a hard time sometimes understanding some of the lingo used by trained programmers.

With that said, I'm having trouble wrapping my brain around the ManyToMany and Many-To-One and OneToOne concepts. I'm trying to create a multi-select option for a user profile in which a user can have multiple attributes of a certain kind. Right now I'm just working on the model. This is what I have, is it right?

# Different licenses for instructors to select from
class Licenses(models.Model):
    nra = models.BooleanField()
    ccl = models.BooleanField()

# User Profile Model
class UserProfile(models.Model):
    user = models.OneToOneField(User)
   
     #.......

    licensed_instructor = models.ManyToManyField(Licenses)

Javier Guerra Giraldez

unread,
Jun 27, 2012, 10:32:19 AM6/27/12
to django...@googlegroups.com
On Wed, Jun 27, 2012 at 8:57 AM, David Wagner <cptn...@gmail.com> wrote:
> With that said, I'm having trouble wrapping my brain around the ManyToMany
> and Many-To-One and OneToOne concepts. I'm trying to create a multi-select
> option for a user profile in which a user can have multiple attributes of a
> certain kind. Right now I'm just working on the model. This is what I have,
> is it right?

these terms are used mainly in the relational database design. as you
might know, you can't have real arrays or structures on traditional
SQL databases, so you use those three types of 'links'.

the simplest is the 'many to one', you have one 'parent' table and a
'child' one with a field (called the "foreign key" field) where each
record keeps a copy of the primary key of a 'parent' record. a common
example is to have 'group' and 'member' tables. each 'member' record
has a field (sometimes called 'group_id') that tells which to which
group it belongs. with a non-unique index on that field, it's easy to
pick all members of each group.

a slight variation is the 'one to one'. here, the index on the
foreign key field is a 'unique' index, that forbids two records with
the same value, effectively making it impossible for a 'parent' record
to have more than one 'child'. sometimes instead of defining a
specific foreign key field, you assign the same primary key value to
related records.

the last one is the 'many to many'. for example, you can have users
that belong to more than one group; and of course each group has many
users. for this, you have to define a 'link table' where each record
has two foreign key fields, one for each linked table. sometimes the
primary key of the link table is just the composite index of these two
foreign keys. also there can be a second composite index with the
same foreign keys in the opposite order. Also you can choose to add
some extra fields to the link table to express some properties of the
link itself.

In Django, you handle this just by declaring fields of the appropriate
type; Django takes care of declaring the indexes, link table if
needed, and a 'reverse relationship'. that last feature is the one
that makes the 'members' pseudo array to magically appear in 'group'
objects.

hope this helps with the theory and makes the Django docs easier to read.

--
Javier

Thomas Lockhart

unread,
Jun 27, 2012, 10:35:50 AM6/27/12
to django...@googlegroups.com
On 12-06-27 6:57 AM, David Wagner wrote:
> I'm a self taught programmer who hasn't done much of anything for
> years so please forgive me if this question is naive. I have a hard
> time sometimes understanding some of the lingo used by trained
> programmers.
>
> With that said, I'm having trouble wrapping my brain around the
> ManyToMany and Many-To-One and OneToOne concepts. I'm trying to create
> a multi-select option for a user profile in which a user can have
> multiple attributes of a certain kind. Right now I'm just working on
> the model. This is what I have, is it right?
>
> # Different licenses for instructors to select from
> class Licenses(models.Model):
> nra = models.BooleanField()
> ccl = models.BooleanField()
I am not familiar with the licenses you are referring to. But if "nra"
and "ccl" are each a kind of license rather than attributes for each
kind of license (google implies this involves gun licensing??!!) you
will want a separate record for each license type. Something like

class Licenses(models.Model):
name = models.CharField(_("Name"), max_length=20)

then populate the license table with an entry for each license type
"nra" and "ccl".

The "many to many" relationship you are modeling would have multiple
license entries for multiple users and this is done by having multiple
entries for each model rather than stacking multiple choices into a
single model.

> # User Profile Model
> class UserProfile(models.Model):
> user = models.OneToOneField(User)
>
> #.......
>
> licensed_instructor = models.ManyToManyField(Licenses)
You may want to name this field "licenses" rather than
"licensed_instructor" for convenience and by convention.

hth

- Tom

j_syk

unread,
Jun 27, 2012, 10:38:07 AM6/27/12
to django...@googlegroups.com
One to One is the right type for linking a user to a profile in the Django world. However I think you may be mixed up on the many to many.
How you have it setup would lead to a User being connected to multiple License objects, each with a nra and ccl attribute. If I didn't realize what those stood for, I'd say you are right. But, I think that you might be thinking of it as the nra and ccl being separate licenses so in that case they shouldnt be the same object

Here's what I'd recommend. Either put those two booleans directly on the profile model or make the License class more generic for any relevant details of a potential license. For example

class License(models.Model):
    name = models.CharField(max_length=255)
    expiration = models.DateField(blank=True, null=True)
    details = models.TextField()

With something like this, the User could have multiple licenses like: Concealed Carry 5/10/2015 and NRA no expire .

David Wagner

unread,
Jun 27, 2012, 11:02:37 AM6/27/12
to django...@googlegroups.com
Thanks for all the replies and I think I'm getting it now but it gets more complex too.

So NRA Licenses is essentialy going to become a type of several certifications. For instance.

NRA Instructor
  • Home Firearm Safety Instructor
  • Refuse to be a Victim Workshop
  • and many more could be selected.....

CCL (or CCW in some states)

  • State in Which your Certified (possibility of multiple states)

Many more different types of licenses and certifications are going to be added eventually so as you can see these relationships are going to get complex. So If I'm grasping this correctly let me try some code to see if I'm on the right track....

class NRA_Certs(models.Model):
    CRSO = models.BooleanField(blank=True, null=True, "Chief Range Safety Officer")
    HFS = models.BooleanField(blank=True, null=True, "Home Firearm Safety")
    MCR = models.BooleanField(blank=True, null=True, "Metallic Cartridge Reloading")
    PPH = models.BooleanField(blank=True, null=True, "Personal Protection in the Home")
    PPO = models.BooleanField(blank=True, null=True, "Personal Protection Outside the Home")
    PS = models.BooleanField(blank=True, null=True, "Pistol Shooting")
    RS = models.BooleanField(blank=True, null=True, "Rifle Shooting")
    SSR = models.BooleanField(blank=True, null=True, "Shotgun Shell Reloading")
    SS = models.BooleanField(blank=True, null=True, "Shotgun Shooting")
    RTBVDW = models.BooleanField(blank=True, null=True, "Refuse to be a Victim Workshop")
    RTBVO = models.BooleanField(blank=True, null=True, "Refuse to be a Victim Online")
    NMLRA_MP = models.BooleanField(blank=True, null=True, "NMLRA Muzzleloading Pistol Shooting")
    NMLRA_MR = models.BooleanField(blank=True, null=True, "NMLRA Muzzleloading Rifle Shooting")
    NMLRA_MS = models.BooleanField(blank=True, null=True, "NMLRA Muzzleloading Shotgun Shooting")

class NRA(models.Model):
    cert_type = models.ForeignKey(NRA_Certs)
    name = models.CharField() # Is this necessary? Can the name be set to text in the boolean fields from NRA_Certs?
    expiration = models.DateField(blank=True, null=True)

Does that look right or am I missing it completely. I'm not sure sure on the NRA_Certs all being boolean, my thinking is that whether they have that certification should be as simple as true/false.

Thanks once again for all the help.


On Wed, Jun 27, 2012 at 7:38 AM, j_syk <jesy...@gmail.com> wrote:> One to One is the right type for linking a user to a profile in the Django

> --
> You received this message because you are subscribed to the Google Groups
> "Django users" group.
> To view this discussion on the web visit
> https://groups.google.com/d/msg/django-users/-/VModQy3bu7UJ.
>
> To post to this group, send email to django...@googlegroups.com.
> To unsubscribe from this group, send email to
> django-users...@googlegroups.com.
> For more options, visit this group at
> http://groups.google.com/group/django-users?hl=en.

Thomas Lockhart

unread,
Jun 27, 2012, 11:17:51 AM6/27/12
to django...@googlegroups.com
Probably not. What happens if another new cert gets added to the the list? You will want a separate table entry for each kind of cert so when "Howitzer" gets added you can make that available without changing your models, only changing your data in the database.

afaict your new proposed class "NRA" does not add value here. Have certs, and have users. Should be enough.

You do have more than one piece of info for the cert model: an acronym and a long name or description. Those should be two fields in the model. Then use the many to many relation to allow multiple certs for each user and to allow multiple users to have the same cert.

hth

                - Tom


                 - Tom
Message has been deleted

David Wagner

unread,
Jun 27, 2012, 2:40:59 PM6/27/12
to django...@googlegroups.com
i think I may just be over thinking this. The last time I did any significant coding for the web as pre-php5 and so this whole MVC thing is something to adapt too for sure.

I think I need to start thinking of the Model in the same way I would design a database back in the day with phpMyAdmin. I think I'm getting bogged down in trying to understand how it will relate to the View. Perhaps I need to just put the View out of my mind for the time being.

So thinking of this as just a database schema it would be something like (in psuedo-code)....

cert_types
  • type
  • date_created

certs

  • type = foreignkey(cert_types)
  • name
  • state (optional)
  • date_created

person

  • name
  • etc...
  • certificates = foreignkey(certs)

Does that make sense? If so each table would be represented by a single class and I think I understand then how they relate to each other and I just need to stop worrying about the View.

Thanks for all your patience everyone as well. Like I said, I'm not classically trained in computer science so there are a lot of concepts that elude me and some lingo that I don't get but the concepts I may grasp if I just understand the translation.

On Wed, Jun 27, 2012 at 10:55 AM, Dennis Lee Bieber <wlf...@ix.netcom.com> wrote:
On Wed, 27 Jun 2012 08:02:37 -0700, David Wagner <cptn...@gmail.com>
declaimed the following in gmane.comp.python.django.user:
       Ugh!...

       I'm not familiar enough with Django's internal format so I'm using a
form of old relational theory notation: tablename(_key_, /foreignkey/,
other, fields...)

NRACertificate(_ID_, certificateName, other, type, specific,
attributes))

       {I forget your individual model so a generic}

Person(_ID_, name, other, stuff)

Person_NRACertificate(_ID_, /personID/, /nracertificateID/,
dateCertified, dateExpires, other, certificate, specfic, data)

       Django can build this intersection table automatically -- but it
would only have _ID_, /personID/, /nracertificateID/! I think, for your
information, you'd want to define your own "through" table to hold the
data specific to an instance of a certificate as held by a person.

       Same with concealed carry permits IF you need a list on a, say, per
state basis.

       Note though, that if the /lists/ don't carry any significant
information beyond the name of the item, you just need one-to-many
configurations. For example, if the only information you track for CCW
is: who (foreign key to Person), license number, issuing state (or other
government entity), date issued, date expires... then a one-to-many is
all you need. (Though you may find you need another one-to-many --
California's rare CCW includes a list of /which/ firearm(s) are
permitted [if you sell one gun and buy a different one, you have to beg
the government to update the CCW with the new gun's information]).

       The NRACertificates table may also not be needed if all it provides
is a list of names to populate a dropdown selection box -- might speed
up processing by just hard-coding the list and saving the name directly
(replace the /nracerticateID/ in the intersect table with the actual
text of the certificate as selected from the dropdown selection.

       Bigger note: You will NOT be using a multiple selection list... More
reasonable is an "add new certificate" button which brings up a form
from which to select one certificate (by name in dropdown), and fields
for the dates, and whatever else is common to certificates.

       When displaying a person, the certificates would be (if I recall
Django terms) a "formset" (where the "form" is for a single
certificate's data).
--
       Wulfraed                 Dennis Lee Bieber         AF6VN
       wlf...@ix.netcom.com    HTTP://wlfraed.home.netcom.com/

--
You received this message because you are subscribed to the Google Groups "Django users" group.

David Wagner

unread,
Jun 27, 2012, 2:48:22 PM6/27/12
to django...@googlegroups.com
Looking at that I think I may need to add a foreignkey to cert_types relating to person since a person can have multiple certification types (NRA Instructor, CCL Instructor, etc).
Message has been deleted

David Wagner

unread,
Jun 27, 2012, 6:51:38 PM6/27/12
to django...@googlegroups.com
Ah, I think that makes sense. Sorry if I wasn't clear earlier on but yes, I am looking for instructors who are certified to teach a certain course. So basically a user could sign up and select some or none of the types of courses they are certified to teach this way other users who want to learn can find them easily. As far as the difference between NRA and CCL, there are several different types of NRA courses one could take however a Concealed Carry course is dependent on which state your certified to teach in. This is what was getting me all confused as I was trying to abstract the type of course from the actual courses provided since there are a number of organizations and individuals (not attached to an organization) that can provide not only courses but services, such as a state certified hunting guide (for instance in Alaska you need one to hunt large game).

I guess though from your example data structure I could put any type of organization, state, etc into the IssuingAuthority and when it comes time to create the profile forms I could just create a drop down list of all issuing authorities for a person to choose from and then populate a select box with all classes that belong to that issuing authority. I would like for people to be able to multi-select and have fields auto-populate all on one page at one time but I'll jump that hurdle when I get there I suppose. Probably need to dive into Javascript/Ajax to make that work.

Thanks much for your help.



On Wed, Jun 27, 2012 at 3:31 PM, Dennis Lee Bieber <wlf...@ix.netcom.com> wrote:
On Wed, 27 Jun 2012 11:48:22 -0700, David Wagner <cptn...@gmail.com>

declaimed the following in gmane.comp.python.django.user:

> Looking at that I think I may need to add a foreignkey to cert_types
> relating to person since a person can have multiple certification types
> (NRA Instructor, CCL Instructor, etc).

       Well, this has just added a different aspect... That of INSTRUCTOR
(my memory of the first messages came across more as a certificate that
one had attended a course <G>, not that it meant they could teach the
course).

       In the case of instructors -- what is the difference between "NRA"
and "CCL" instructor? "NRA" specifies an organization that provides the
certification in /something/, but "CCL" is a /something/ but who issues
it?

       Okay, looking at these as teaching certificates...

Certificates
       ID #primary key
       Name    #text string for the common name of the class
       IssuingAuthority        #NRA or government entity
       DateFirstAuthorized     #not date of issuance, but a double check that
                                                       #an issued certificate date does not come
                                                       #before the "class" was created
       RenewalPeriod           #how often the certificate needs to be renewed

Persons
       ID
       Name
       Address
       whatever

Issued                  #or PersonsCertificates if you want to name the sources
       ID
       pID             foreign key     (Persons.ID) #who this certificate was issued to
       cID             foreign key (Certificates.ID)   #what type of certificate
       DateIssued              #constraint DateIssued > DateFirstAuthorized
       CertificateNumber       #document number
       DateExpires             #for things that need to be renewed periodically
                                               #= DateIssued + RenewalPeriod
       UniqueKey (pID, cID, CertificateNumber)
               #including certificate number means you can track renewals
               #as a renewal would have a different serial number

       This is a many-to-many between Persons and Certificates, in which
the intersection table (Issued) contains additional information.

Thomas Lockhart

unread,
Jun 27, 2012, 8:27:00 PM6/27/12
to django...@googlegroups.com
On 6/27/12 11:48 AM, David Wagner wrote:
Looking at that I think I may need to add a foreignkey to cert_types relating to person since a person can have multiple certification types (NRA Instructor, CCL Instructor, etc).
No. See below.


On Wed, Jun 27, 2012 at 11:40 AM, David Wagner <cptn...@gmail.com> wrote:
i think I may just be over thinking this. The last time I did any significant coding for the web as pre-php5 and so this whole MVC thing is something to adapt too for sure.
Yes you are :)


I think I need to start thinking of the Model in the same way I would design a database back in the day with phpMyAdmin. I think I'm getting bogged down in trying to understand how it will relate to the View. Perhaps I need to just put the View out of my mind for the time being.
Yes. If you've done databases (that is some of my background too) then the models (always the first step here) should become comfortable fairly quickly, even if you are rusty. See below...


So thinking of this as just a database schema it would be something like (in psuedo-code)....

cert_types
  • type
  • date_created

certs

  • type = foreignkey(cert_types)
  • name
  • state (optional)
  • date_created

person

  • name
  • etc...
  • certificates = foreignkey(certs)
OK, "cert_types" is good (or at least a good start). "person" needs to have a manytomany on cert_types rather than a foreign key on certs. And "certs" can be the explicit intermediate table used for the manytomany relationship and can hold things like dates. Look at the django docs on how to explicitly define the intermediate table, but it is in the musician and musical group example; google for "paul ringo django extra fields" :)

hth

                             - Tom

David Wagner

unread,
Jun 27, 2012, 8:49:50 PM6/27/12
to django...@googlegroups.com
Thanks Tom. Is this the example your talking about, https://docs.djangoproject.com/en/1.4/topics/db/models/#intermediary-manytomany ? If so, I think this should work...

# Different groups and states that issue teaching certificates/licenses
class IssuingAuthority(models.Model):
    name = models.CharField(max_length=254)
    state = USStateField()
    date_added = models.DateTimeField(auto_now_add=True)

# Certifications issued related to IssuingAuthority
class Certifications(models.Model):
    certs = models.ManyToManyField(License_Types, through='UserProfile')
    name = models.CharField(max_length=254)
    date_added = models.DateTimeField(auto_now_add=True)


# User Profile Model
class UserProfile(models.Model):
    user = models.OneToOneField(User)
    address_1 = models.CharField(max_length=254)
    address_2 = models.CharField(max_length=254)
    state = USStateField()
    zip = models.IntegerField(max_length=7)
    phone = PhoneNumberField()
    issuing_authority = models.ForeignKey(IssuingAuthority)
    certification = models.ForeignKey(Certifications)

I'll try to load that up later (most likely tomorrow) and see if I can get it to work.

Thanks much.

--
Reply all
Reply to author
Forward
Message has been deleted
0 new messages