5
\$\begingroup\$

I'm beginning with Django and I have a Civil Status project. I created my first models.py in order to get a Form, but I had some advices in order to normalize my database.

I made this process and I would like to know what do you think about this new restructuration.

My old models.py :

from django.db import models
from django.forms import ModelForm
from .countries import CHOIX_PAYS # Importation de la liste des pays
from .sexe import CHOIX_SEXE # Importation de la liste des sexes 

# Create my Form model BirthCertificate

class BirthCertificate(models.Model) :

    nom = models.CharField('Nom', max_length=30, null=False)   # Lastname
    prenom = models.CharField('Prénom', max_length=30, null = False)   # Firstname
    sexe = models.CharField('Sexe', max_length=1, choices = CHOIX_SEXE)  # Choice between 'M' or 'F'
    birthday = models.DateField('Date de naissance', null=False)
    birthhour = models.TimeField('heure de naissance', null=False)
    birthcity = models.CharField('Ville de naissance', max_length = 30, null=False)
    birthcountry = models.ForeignKey(Country)

    nom_pere = models.CharField('Nom père', max_length=30, null=False)
    prenom_pere = models.CharField('Prénom père', max_length=30, null=False)
    birthday_pere = models.DateField('Date de naissance du père', null=False)
    birthcity_pere = models.CharField('Ville de naissance du père', max_length=30, null=False)
    birthcountry_pere = models.CharField('Pays de naissance du père', max_length=2, choices= CHOIX_PAYS)
    job_pere = models.CharField('Profession du père', max_length=30, null=False)
    adress_pere = models.CharField('Adresse du père', max_length=40, null=False)
    ville_pere = models.CharField('Ville du père', max_length=30, null=False)
    zip_pere = models.IntegerField('Code Postal du père', null=False)
    pays_pere = models.CharField('Pays du père', max_length=2, choices= CHOIX_PAYS)

    nom_mere = models.CharField('Nom mère', max_length=30, null=False)
    prenom_mere = models.CharField('Prénom mère', max_length=30, null=False)
    birthday_mere = models.DateField('Date de naissance de la mère', null=False)
    birthcity_mere = models.CharField('Ville de naissance de la mère', max_length=30, null=False)
    birthcountry_mere = models.CharField('Pays de naissance de la mère', max_length=2, choices= CHOIX_PAYS)
    job_mere = models.CharField('Profession de la mère', max_length=30, null=False)
    adress_mere = models.CharField('Adresse de la mère', max_length=40, null=False)
    ville_mere = models.CharField('Ville de la mère', max_length=30, null=False)
    zip_mere = models.IntegerField('Code Postal de la mère', null=False)
    pays_mere = models.CharField('Pays de la mère', max_length=2, choices= CHOIX_PAYS)

    nom_temoin1 = models.CharField('Nom témoin n°1', max_length=30, null=False)
    prenom_temoin1 = models.CharField('Prénom témoin n°1', max_length=30, null=False)
    birthday_temoin1 = models.DateField('Date de naissance du témoin n°1', null=False)
    birthcity_temoin1 = models.CharField('Ville de naissance du témoin n°1', max_length=30, null=False)

    nom_temoin2 = models.CharField('Nom témoin n°2', max_length=30, null=False)
    prenom_temoin2 = models.CharField('Prénom témoin n°2', max_length=30, null=False)
    birthday_temoin2 = models.DateField('Date de naissance du témoin n°2', null=False)
    birthcity_temoin2 = models.CharField('Ville de naissance du témoin n°2', max_length=30, null=False)

    def __str__(self):
        return self.nom

And my new models.py :

from django.db import models
from django.forms import ModelForm


class Country(models.Model):

    code = models.CharField(max_length=3, null=False) # Example : 'FR' - 'US' 
    pays = models.CharField(max_length=50, null=False) # Example : 'France' - 'Etats-Unis'

    def __str__(self):
        return self.code

class Sexe(models.Model):

    code = models.CharField(max_length=1, null=False) # Example : 'M' or 'F'
    name = models.CharField(max_length=7, null=False) # Example : 'Mâle' or 'Femelle'

    def __str__(self):
        return self.code

class Civility(models.Model):

    code = models.CharField(max_length=4, null=False) # 'Mr' - 'Mlle' - 'Mme' - ..
    name = models.CharField(max_length=20, null=False) # 'Monsieur' - 'Mademoiselle' - ..

    def __str__(self):
        return self.code

class Parent1(models.Model):

    civility = models.ForeignKey(Civility)
    lastname = models.CharField(max_length=30, null=False)
    firstname = models.CharField(max_length=30, null=False)
    sexe = models.ForeignKey(Sexe)
    birthday = models.DateField(null=False)
    birthcity = models.CharField(max_length=30, null=False)
    birthcountry = models.ForeignKey(Country)
    job = models.CharField(max_length=30, null=False)
    adress = models.CharField(max_length=30, null=False)
    city = models.CharField(max_length=30, null=False)
    zip = models.IntegerField(max_length=10, null=False)
    country = models.ForeignKey(Country)

    def __str__(self):
        return self.lastname

class Parent2(models.Model):

    civility = models.ForeignKey(Civility)
    lastname = models.CharField(max_length=30, null=False)
    firstname = models.CharField(max_length=30, null=False)
    sexe = models.ForeignKey(Sexe)
    birthday = models.DateField(null=False)
    birthcity = models.CharField(max_length=30, null=False)
    birthcountry = models.ForeignKey(Country)
    job = models.CharField(max_length=30, null=False)
    adress = models.CharField(max_length=30, null=False)
    city = models.CharField(max_length=30, null=False)
    zip = models.IntegerField(max_length=10, null=False)
    country = models.ForeignKey(Country)

    def __str__(self):
        return self.lastname

class BirthCertificate(models.Model):

    lastname = models.CharField(max_length=30, null=False) 
    firstname = models.CharField(max_length=30, null=False)
    sexe = models.ForeignKey(Sexe)
    birthday = models.DateField(null=False)
    birthhour = models.TimeField(null=False)
    birthcity = models.CharField(max_length=30, null=False)
    birthcountry = models.ForeignKey(Country)
    parent1 = models.ForeignKey(Parent1)
    parent2 = models.ForeignKey(Parent2)

    def __str__(self):
        return self.lastname

As you can see, I tried to make a database normalization. I think it's better than the first models.py try.

Do you think that 'JOINs' are smartly written or I need to modify one more time this file ?

\$\endgroup\$
6
  • \$\begingroup\$ Those poor people born in Llanfair­pwllgwyngyll­gogery­chwyrn­drobwll­llan­tysilio­gogo­goch. Place names can be longer than 30 characters! \$\endgroup\$
    – Graipher
    Nov 22, 2016 at 17:54
  • \$\begingroup\$ @Graipher Yeah, but this city can be called : Llanfair Pwllgwyngyll (less than 30 characters ;) ). More than 30 characters for names ? \$\endgroup\$
    – Essex
    Nov 22, 2016 at 18:40
  • \$\begingroup\$ Well, there is this guy with a last name with probably about 666 characters... But I think raising them to 100 chars should be more than enough for most people, even with long double last names. \$\endgroup\$
    – Graipher
    Nov 22, 2016 at 19:01
  • 1
    \$\begingroup\$ I have rolled back the last edit. Please see What to do when someone answers. \$\endgroup\$
    – Mast
    Nov 22, 2016 at 19:07
  • \$\begingroup\$ Basically, when an answer has been posted, please don't touch the code in your question. It makes it hard to understand what's going on for any future visitors. Feel free to post a follow-up question if you've incorporated the answers into your code, it should all be explained in the link provided in the previous comment. \$\endgroup\$
    – Mast
    Nov 22, 2016 at 19:09

1 Answer 1

6
\$\begingroup\$

Few things here:

1. Parent1 and Parent2 It's not really clear why would you need to have parents in the separate tables while they both represent a person. There is no difference between parent1 and parent2 so they can be stored in the same table.

2. Parent1/Parent2/BirthCertificate

They all share lots of common fields, so you can create an abstract class that will describe them all.

3. Separate table for sex and title

I would not go for this, I don't see much of reasons to create a table with only 2 rows in it.

So, in the end, your code should look like this:

from django.db import models

SEX_CHOICES = (
    ('M', 'Male'),
    ('F', 'Female')
)

TITLE_CHOICES = (
    ('Mr', 'Mister'),
    ('Mrs', 'Missus')
)


class Country(models.Model):

    code = models.CharField(max_length=3, null=False)  # Example : 'FR' - 'US'
    pays = models.CharField(max_length=50, null=False)  # Example : 'France' - 'Etats-Unis'

    def __str__(self):
        return self.code


class Person(models.Model):

    class Meta:
        abstract = True

    lastname = models.CharField(max_length=30, null=False)
    firstname = models.CharField(max_length=30, null=False)
    sex = models.CharField(max_length=1, choices=SEX_CHOICES)
    birthday = models.DateField(null=False)
    birthhour = models.TimeField(null=False)
    birthcity = models.CharField(max_length=30, null=False)
    birthcountry = models.ForeignKey(Country)

    def __str__(self):
        return self.lastname


class Parent(Person):

    title = models.CharField(choices=TITLE_CHOICES)
    job = models.CharField(max_length=30, null=False)
    adress = models.CharField(max_length=30, null=False)
    city = models.CharField(max_length=30, null=False)
    zip = models.IntegerField(max_length=10, null=False)
    country = models.ForeignKey(Country)


class BirthCertificate(Person):

    parent1 = models.ForeignKey(Parent)
    parent2 = models.ForeignKey(Parent)
\$\endgroup\$
3
  • \$\begingroup\$ Thank you to your post : Some elements in order to answer you. 1) If parents don't live at the same place ? Don't forget that the goal of this project is to get a civil status extract, with lots of specifications about parents/child. 2) I don't really understand why birthhour for example makes part of abstract instead of BirthCertificate (I forgot to modify the name, it's Child). 3) I agree with you \$\endgroup\$
    – Essex
    Nov 22, 2016 at 18:46
  • \$\begingroup\$ @Andromedae93 the point is that the parents can be two separate records in the same table, each with their own distinct field values. In general when you have two tables with identical columns, it's a sign something is wrong. The common fields in BirthCertificate can also be stored as a different record in the same table. \$\endgroup\$ Nov 22, 2016 at 19:06
  • \$\begingroup\$ @Mat'sMug Oh ok thank you for precisions ! I will see exactly How I can adapt the Alex's answer to my case. Perhaps some little modifications but the Alex's script is very interesting. \$\endgroup\$
    – Essex
    Nov 23, 2016 at 8:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.