# Django Models
Django models define how the data is structured in the database. Basic model structure will include the following:
# Typical Imports
Take what you need 🎉 💯
from django.db import models
from tinymce.models import HTMLField
from django.template.defaultfilters import slugify
from django.contrib.auth.models import User
from django.utils import timezone
from uuid import uuid4
from django.conf import settings
from django.urls import reverse
import json
import os
#Import models from other apps
from .xxxxx import *
# Basic Model Structure
In this example, we use Contact as an example
class Contact(models.Model):
#Standard Variables
title = models.CharField(null=True, blank=True, max_length=200)
#### ADD OTHER VARIABLES HERE
#Related Variables
user = models.ForeignKey(User, null=True, blank=True, on_delete=models.CASCADE)
#Utility Variable
uniqueId = models.CharField(null=True, blank=True, max_length=100)
slug = models.SlugField(max_length=500, unique=True, blank=True, null=True)
date_created = models.DateTimeField(blank=True, null=True)
last_updated = models.DateTimeField(blank=True, null=True)
def __str__(self):
return '{}{}'.format(self.title, self.uniqueId)
def get_absolute_url(self):
return reverse('contact-detail', kwargs={'slug': self.slug})
def save(self, *args, **kwargs):
if self.date_created is None:
self.date_created = timezone.localtime(timezone.now())
if self.uniqueId is None:
self.uniqueId = str(uuid4()).split('-')[4]
self.slug = slugify('{}{}'.format(self.title, self.uniqueId))
self.slug = slugify('{}{}'.format(self.title, self.uniqueId))
self.last_updated = timezone.localtime(timezone.now())
super(Contact, self).save(*args, **kwargs)
# Model Elements
These are the typical elements that go in to a model
#Character field
name = models.CharField(null=True, blank=True, max_length=200)
#Slug field
slug = models.SlugField(max_length=500, unique=True, blank=True, null=True)
#Datetime field
date = models.DateTimeField(blank=True, null=True)
#Text area field
description = models.TextField(null=True, blank=True)
#Foreignkey SET NULL
user = models.ForeignKey(User, null=True, blank=True, on_delete=models.SET_NULL)
#Foreign key CASCADE
user = models.ForeignKey(User, null=True, blank=True, on_delete=models.CASCADE)
#Multiple choice field
OPTIONS = [
('option1', 'option1'),
('option2', 'option2'),
('option3', 'option3'),
]
selection = models.CharField(choices=OPTIONS, null=True, blank=True, max_length=100)
#Boolean field
check = models.BooleanField(default=False)
#Image Field
image = models.ImageField(default='default.jpg', upload_to='profile_imgs')
#Resized Image Field
image = ResizedImageField(size=[400, 400], crop=['middle', 'center'], default='default.jpg', upload_to='profile_imgs')
#File Uploading to dynamic directory - including File Renaming to UUID name
def the_upload_path(self, filename):
ext = filename.split('.')[-1]
filename = '{}.{}'.format(str(uuid4()).split('-')[4], ext)
return os.path.join('{}/directory'.format(self.uniqueId), filename)
file = models.FileField(upload_to=the_upload_path, null=True, blank=True,)
#File uploading to fixed directory
file = models.FileField(upload_to='upload_directory', null=True, blank=True,)
#OneToOneField with RELATED Field
user = models.OneToOneField(User, on_delete = models.CASCADE, related_name='related_employee')
#Integer field
days = models.IntegerField()
#Float Field
amount = models.FloatField()
# Documentation Handling
Validate Document size in the model
def validate_doc_size(value):
filesize= value.size
if filesize > 5242880:
raise ValidationError("The maximum document size that can be uploaded is 5MB")
else:
return value
document = models.FileField(upload_to=the_upload_path, null=True, blank=True, validators=[validate_doc_size])
Make sure documents are deleted from storage when a model instance is deleted, or updated.
from django.db.models.signals import post_delete, pre_save
from django.dispatch import receiver
""" Whenever ANY model is deleted, if it has a file field on it, delete the associated file too"""
@receiver(post_delete)
def delete_files_when_row_deleted_from_db(sender, instance, **kwargs):
for field in sender._meta.concrete_fields:
if isinstance(field,models.FileField):
instance_file_field = getattr(instance,field.name)
delete_file_if_unused(sender,instance,field,instance_file_field)
""" Delete the file if something else get uploaded in its place"""
@receiver(pre_save)
def delete_files_when_file_changed(sender,instance, **kwargs):
# Don't run on initial save
if not instance.pk:
return
for field in sender._meta.concrete_fields:
if isinstance(field,models.FileField):
#its got a file field. Let's see if it changed
try:
instance_in_db = sender.objects.get(pk=instance.pk)
except sender.DoesNotExist:
# We are probably in a transaction and the PK is just temporary
# Don't worry about deleting attachments if they aren't actually saved yet.
return
instance_in_db_file_field = getattr(instance_in_db,field.name)
instance_file_field = getattr(instance,field.name)
if instance_in_db_file_field.name != instance_file_field.name:
delete_file_if_unused(sender,instance,field,instance_in_db_file_field)
""" Only delete the file if no other instances of that model are using it"""
def delete_file_if_unused(model,instance,field,instance_file_field):
dynamic_field = {}
dynamic_field[field.name] = instance_file_field.name
other_refs_exist = model.objects.filter(**dynamic_field).exclude(pk=instance.pk).exists()
if not other_refs_exist:
instance_file_field.delete(False)