Wednesday, February 22, 2017

Re: Models/Foreign Keys best practice

Hi Richard,

 

good questions and your initial data model defines your application challenges. It is by far the most important step in application design, so it's important to get it "as right as possible".

 

On Wednesday 22 February 2017 06:25:24 Richard Jackson wrote:

 

> The app lists performances, who's performing, what my role is with

> them (i.e. conductor, pianist etc.), the venue and the start

> date/time of these performances.

 

I come up with these separate entities:

- Performance (or "Show" or "Series")

- Ensemble

- Role within Ensemble

- Venue

- Event: performance using a certain Ensemble, playing a Role at a certain date

 

Date is a bad class name to use for a variety of reasons, but also doesn't cover the load. Event does.

 

Now you can see the links clearly:

- Role: Ensemble

- Event: Ensemble, Role, Performance

 

The questions to answer is: Within each ensemble can you switch roles? If so, they don't need to be linked and Event will link them

 

In fact, it's probably best not to link them, as you can always enforce this in logic.

 

A more general remark:

While you're free to use the class name as the field name, most of us will use "name", "title" or "designation" if you're Borg minded, for the field name. So Role.role becomes Role.name.

 

Results:

 

> class Performance(models.Model):

> """First attempt at a thing!"""

> performance_name = models.CharField(max_length=200)

> link = models.CharField(max_length=200)

>

> def __unicode__(self):

> return self.performance_name

>

>

> class Ensemble(models.Model):

> performance = models.ForeignKey(Performance)

 

No key here

 

> ensemble = models.CharField(max_length=200)

>

> def __unicode__(self):

> return self.ensemble

>

>

> class Role(models.Model):

> performance = models.ForeignKey(Performance)

 

No key here

 

> role = models.CharField(max_length=200)

>

> def __unicode__(self):

> return self.role

>

>

> class Venue(models.Model):

> performance = models.ForeignKey(Performance)

 

No key here. This is just the place. It should be possible to do two different performances at the same venue, without having to create two venues.

 

> venue = models.CharField(max_length=200)

>

> def __unicode__(self):

> return self.venue

>

>

> class Date(models.Model):

 

Event

 

> performance = models.ForeignKey(Performance)

ensemble = models.ForeignKey(Ensemble)

role = models.ForeignKey(Role)

venue = models.ForeignKey(Venue)

 

> start_date = models.DateTimeField('Start Date',

> default=timezone.now)

 

I would use "start" or start_time since it's not just a date.

 

> end_date = models.DateTimeField('End Date',

> default=timezone.now)

 

I would use duration = models.DurationField()

 

 

Now, if you look at "Event", it contains foreign keys to models that only have a charfield. So, it makes sense to simply make those CharFields.

But...a Venue, has an address. An Ensemble has members and you may get different but fixed wages for each role. These are reasons to use Foreign Keys. Otherwise, just use a CharField.

 

If you don't need to record anything special about roles, there's also the middle ground using a field's choices. You use choices instead of a Foreign Key if they hardly ever change and don't need to be managed in the Admin.

 

Hope this helps.

--

Melvyn Sopacua

No comments:

Post a Comment