Reputation: 143
Coming from a php background, I know how I would do this 'by hand' but I can't seem to get my head round how to structure my database with Django ORM.
The app centres around a checklist. A Checklist has some identifying features, lets say Name
, DateOfBirth
and ChecklistType
There are several ChecklistType
s, each of which has many ChecklistOption
s. A ChecklistOption
may or may not be in several ChecklistType
s
My initial thought was to create a model for ChecklistType
and ChecklistTypeOptions
to store the 'configuration' of the Checklists, and a seperate model for Checklist
and Requirements
(respectively) to link to the Customer
model. I thought I would manually look up the configuration and create the latter model entries in the view that creates the Customer
. I then realised this defeats to point of the ORM!
I'm sure that this question could be solved by a proper understanding of the way to use Many-to-many fields in the models, but the Django Documentation seems to only deal with simple applications of this. If I create a ManyTomany field in the Checklist
to ChecklistOption
(with ChecklistType
as a ChoiceField), I lose the ability to specify which options are applicable to that type.
I'm sure this type of thing must be done regularly, but I can't get my head around it.
Thanks in advance,
Cheese {boolean}
Tomato {boolean}
Bacon {boolean}
Chicken {boolean}
Coffee {boolean}
Pepperoni {boolean}
Salami {boolean}
Mushrooms {boolean}
Eggs {boolean}
ThingsToPutOnPizza: {options: Cheese, Tomato, Bacon, Chicken, Salami, Mushrooms}
ThingsToEatAtBreakfast: {options: Cheese, Bacon, Coffee, Eggs}
John Smith: {Name: "John Smith", DOB: 1984-12-17, Checklist: ThingsToEatAtBreakfast}
Jane Jones: {Name: "Jane Jones", DOB: 1987-07-22, Checklist: ThingsToPutOnPizza}
Frank Allen {Name: "Frank Allen", DOB: 1990-04-01, Checklist: ThingsToPutOnPizza}
A user creates a customer, and selects the checklist type. Another user has to 'complete' the checklist, so selects the customer from list and is presented with a list of checkboxes for the options in that checklist type, and of those options they may tick some and not others. On saving the form/model their user and the time is logged against the checklist to mark it as complete.
Upvotes: 1
Views: 787
Reputation: 16010
Тhis is probably the simplest solution:
from django.db import models
class CheckList(models.Model):
name = models.CharField(max_length=255)
checklist_type = models.ForeignKey('CheckListType')
options = models.ManyToManyField('CheckListOption', blank=True)
def __unicode__(self):
return self.name
class CheckListType(models.Model):
name = models.CharField(max_length=255)
options = models.ManyToManyField('CheckListOption')
def __unicode__(self):
return self.name
class CheckListOption(models.Model):
name = models.CharField(max_length=255)
def __unicode__(self):
return self.name
from django import forms
from .models import CheckList, CheckListOption
class CheckListForm(forms.ModelForm):
class Meta:
model = CheckList
fields = '__all__'
def __init__(self, *args, **kwargs):
super(CheckListForm, self).__init__(*args, **kwargs)
if self.instance.pk:
self.fields['options'].queryset = CheckListOption.objects.filter(
checklisttype=self.instance.checklist_type_id
)
else:
self.fields['options'].queryset = CheckListOption.objects.none()
from django.contrib import admin
from .forms import CheckListForm
from .models import CheckList, CheckListType, CheckListOption
class CheckListAdmin(admin.ModelAdmin):
form = CheckListForm
admin.site.register(CheckList, CheckListAdmin)
admin.site.register(CheckListType)
admin.site.register(CheckListOption)
There is only one drawback - when you already have a saved CheckList
instance and you want to change the checklist_type
, you wont get the new options
on the moment. The user doing the change should unselect the selected options (this is kind of an optional, but if not done, the selected options will remain until the next save), save the model and edit it again to chose the new options.
Upvotes: 1
Reputation: 174614
Lets start with the basic requirements:
The app centres around a checklist. A
Checklist
has some identifying features, lets sayName
,DateOfBirth
andChecklistType
There are several
ChecklistType
s, each of which has manyChecklistOption
s. AChecklistOption
may or may not be in severalChecklistType
s
The below models take care of your initial requirements:
class CheckListOption(models.Model):
name = models.CharField(max_length=200)
class CheckListType(models.Model):
name = models.CharField(max_length=200)
options = models.ManyToManyField(CheckListOption)
class Checklist(models.Model):
name = models.CharField(max_length=200)
dob = models.DateField()
type = models.ForeignKey(CheckListType)
Now, with those in mind; lets see how you plan to use these models:
A user creates a customer, and selects the checklist type. Another user has to 'complete' the checklist, so selects the customer from list and is presented with a list of checkboxes for the options in that checklist type, and of those options they may tick some and not others. On saving the form/model their user and the time is logged against the checklist to mark it as complete.
To take care of your tracking, you need to add a few more fields to the Checklist
model:
class Checklist(models.Model):
name = models.CharField(max_length=200)
dob = models.DateField()
type = models.ForeignKey(CheckListType)
created_by = models.ForeignKey(User, name='creator')
created_on = models.DateTimeField(auto_now_add=True)
completed_by = models.ForeignKey(User,
name='maker', blank=True, null=True)
completed_on = models.DateTimeField(blank=True, null=True)
def is_complete(self):
return self.completed_on
To take care of your requirement that "and of those options they may tick some and not others", you'll need to modify the CheckListType
model, by creating a custom through model; which will allow you specify options on a relationship:
class CheckListOptionConfig(models.Model):
checklisttype = models.ForeignKey('CheckListType')
optiontype = models.ForeignKey('CheckListOption')
is_required = models.BooleanField(default=False)
class CheckListType(models.Model):
name = models.CharField(max_length=200)
options = models.ManyToManyField(CheckListOption, through='CheckListOptionConfig')
The rest of your workflow describes the user interface; which can easily be configured to show all manners of alerts/warnings if the right options are not ticked.
Upvotes: 0