5.18. Models Use Case

5.18.1. Use Case - 0x01

  • Contact

import datetime

from django.db import models
from django.utils.translation import gettext_lazy as _


class Contact(models.Model):
    STATUS_BEST_FRIEND = 'best-friend'
    STATUS_FRIEND = 'friend'
    STATUS_ACQUAINTANCE = 'acquaintance'
    STATUS_OTHER = 'other'
    STATUS_CHOICES = [
        (STATUS_BEST_FRIEND, _('Best Friend')),
        (STATUS_FRIEND, _('Friend')),
        (STATUS_ACQUAINTANCE, _('Acquaintance')),
        (STATUS_OTHER, _('Other'))]

    GENDER_MALE = 'male'
    GENDER_FEMALE = 'female'
    GENDER_OTHER = None
    GENDER_CHOICES = [
        (GENDER_MALE, _('Male')),
        (GENDER_FEMALE, _('Female')),
        (GENDER_OTHER, _('Undisclosed'))]

    created = models.DateTimeField(auto_now_add=True)
    modified = models.DateTimeField(auto_now=True)
    reporter = models.ForeignKey(verbose_name=_('Reporter'), to='auth.User', on_delete=models.CASCADE, null=True, default=None)
    is_deleted = models.BooleanField(verbose_name=_('Is deleted?'), default=False)

    firstname = models.CharField(verbose_name=_('First Name'), max_length=30)
    lastname = models.CharField(verbose_name=_('Last Name'), max_length=30, db_index=True)
    birthdate = models.DateField(verbose_name=_('Birthdate'), null=True, blank=True, default=None)
    email = models.EmailField(verbose_name=_('Email'), null=True, blank=True, default=None)
    bio = models.TextField(verbose_name=_('Bio'), null=True, blank=True, default=None)
    image = models.ImageField(verbose_name=_('Image'), null=True, blank=True, default=None)
    status = models.CharField(verbose_name=_('Status'), max_length=30, choices=STATUS_CHOICES, null=True, blank=True, default=None)
    gender = models.CharField(verbose_name=_('Gender'), max_length=30, choices=GENDER_CHOICES, null=True, blank=True, default=None)
    friends = models.ManyToManyField(verbose_name=_('Friends'), to='contact.Contact', blank=True, default=None)

    def __str__(self):
        return f'{self.firstname} {self.lastname}'

    def get_age(self):
        if not self.birthdate:
            return None

        today = datetime.date.today()
        return today.year - self.birthdate.year


    def save(self, *args, **kwargs):
        # is called at Model.save()
        return super().save(*args, **kwargs)

    class Meta:
        verbose_name = _('Contact')
        verbose_name_plural = _('Contacts')
        unique_together = ['firstname', 'lastname']

5.18.2. Assignments

Code 5.115. Solution
"""
* Assignment: Django Model AddressBook
* Complexity: medium
* Lines of code: 50 lines
* Time: 34 min

English:
    0. Install `Pillow` package:
       `python -m pip install --upgrade pillow`
    1. Use `myproject` project
    2. Create app `addressbook`
    TODO: dodaj apkę do INSTALLED_APPS is dodaj verbose_name w config
    3. Create model `Address` with fields:
        a. type (choice: home, work)
        b. street
        c. house number
        d. apartment number
        e. post-code
        f. city
        g. region
        h. country
    4. Create model `Person` with fields:
        a. first name
        b. last name
        c. date of birth
        d. photo
        e. phone (choice: home, work, mobile)
        f. email (choice: home, work)
    5. Person can have many addresses, phones and emails
    6. Generate an admin panel:
        a. You can list contacts
        b. On the main screen you can see the basic fields of the person
        c. You can search contacts by last name
        d. You can filter contacts by date of birth
    7. Run doctests - all must succeed

Polish:
    0. Zainstaluj pakiet `Pillow`:
       `python -m pip install --upgrade pillow`
    1. Użyj projekt `myproject`
    2. Stwórz apkę `addressbook`
    3. Stwórz model `Address` z polami:
        a. Typ (do wyboru typ: domowy, praca)
        b. Ulica
        c. Numer bloku
        d. Numer mieszkania
        e. Kod pocztowy
        f. Miasto
        g. Region
        h. Kraj
    4. Stwórz model `Person` z polami:
        a. Imię
        b. Nazwisko
        c. Data Urodzenia
        d. Zdjęcie
        e. Telefon (do wyboru typ: domowy, praca, komórka)
        f. Email (do wyboru typ: domowy, praca)
    5. Osoba może mieć wiele adresów, telefonów i e-maili
    6. Wygeneruj panel administracyjny:
        a. Można wylistować kontakty
        b. Na głównym ekranie widoczne są podstawowe pola osoby
        c. Można wyszukiwać kontakty po nazwisku
        d. Można filtrować kontakty po dacie urodzenia
    7. Uruchom doctesty - wszystkie muszą się powieść

Hints:
    * models.CharField
    * models.DateField
    * models.ImageField
    * models.EmailField
    * models.ForeignKey
    * search_fields
    * list_filter
    * list_display
    * admin.StackedInline
    * admin.TabularInline
"""


Code 5.116. Solution
# TODO: Wywalić panel administracyjny
"""
* Assignment: Django Model Company
* Complexity: medium
* Lines of code: 50 lines
* Time: 34 min

English:
    1. Use `myproject` project
    2. Create app `company`
    3. Create model `Department` with fields:
        a. name
        b. employees list (m2m relation to Employee)
    4. Create model `Employee` with fields:
        a. first name
        b. last name
        c. salary USD
        d. is active (yes, no, unknown)
    5. Generate an admin panel:
        a. Add search by last name
        b. Add filter by status
        c. Add filter by salary (low, medium, high)
     6. Salary:
        a. low - up to 5_000
        b. medium - from 5_000 to 10_000
        c. high - above 10_000

Polish:
    1. Użyj projekt `myproject`
    2. Stwórz apkę `company`
    3. Stwórz model `Department` z polami:
        a. nazwa
        b. lista pracowników (relacja m2m do Employee)
    4. Stwórz model `Employee` z polami:
        a. imię
        b. nazwisko
        c. pensja USD
        d. jest aktywny (tak, nie, nieznany)
    5. Wygeneruj panel administracyjny:
        a. dodaj wyszukiwarkę po nazwisku
        b. dodaj filtr po statusie
        c. dodaj filtr po pensji (low, medium, high)
    6. Pensja:
        a. low - do 5_000
        b. medium - od 5_000 do 10_000
        c. high - powyżej 10_000

Hints:
    * models.CharField
    * models.DecimalField
    * models.ManyToManyField
    * models.BooleanField
    * admin.SimpleListFilter
    * search_fields
    * list_display
    * display_filter
"""


5.18.3. References