Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

Python

Django Model | Relationship question. Student->School Class relationship?

My code below:

class Students(models.Model):
         first_name = models.CharField(max_length=30)
         last_name = models.CharField(max_length=30)
         classChoice1 = ?
         classChoice2 = ?
         classChouce3 = ?    


 class Class(models.Model):
     class_name = models.CharField(max_length=30)
     class_discription = models.CharField(max_length=30)    

Say for example I have Nth students, S1 S2 S3 ... and Nth classes (as in college class) C1 C2 C3 ... And I want to create a relationship where each student can only be assigned to one class uniquely for each classChoice selected. How would I create that relationship?

class Class(models.Model): class_name = models.CharField(max_length=30) class_description = models.CharField(max_length=30)

Say for example I have Nth students, S1 S2 S3 ... and Nth classes (as in college class) C1 C2 C3 ... And I want to create a relationship where each student can only be assigned to one class uniquely for each classChoice selected. How would I create that relationship?

Chris Freeman
Chris Freeman
Treehouse Moderator 68,441 Points

Not sure I follow. Are you looking to keep S1.classChoice1 unique from S1.classChoice2 and S1classChoice3, etc.

Or S1.classChoice1 unique from S2.classChoice1 and all other S{3...N}.classChoice1; and similarly for the other choices?

@Chris Freeman - "Are you looking to keep S1.classChoice1 unique from S1.classChoice2 and S1classChoice3, etc. " - YES

1 Answer

Chris Freeman
MOD
Chris Freeman
Treehouse Moderator 68,441 Points

There are two parts to this answer. The first is to create a ForeignKey for each choice to the Classes.

class Students(models.Model):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)
    classChoice1 = models.ForeignKey(Class, related_name='choice1')
    classChoice2 = models.ForeignKey(Class, related_name='choice2')
    classChoice3 = models.ForeignKey(Class, related_name='choice3')

The second part of making the values mutually exclusive is harder. There is a concept of "uniqueness" but that applies to the case you didn't want where choice1 was unique across all students. Since you want to allow multiple student to have the same Choice1, you have to solve it using Student class methods verses a database enforcement.

This can be done by treating the Choices as a Python properties.

Changing the field names to have a leading underscore:

class Students(models.Model):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)
    _classChoice1 = models.ForeignKey(Class, related_name='choice1')
    _classChoice2 = models.ForeignKey(Class, related_name='choice2')
    _classChoice3 = models.ForeignKey(Class, related_name='choice3')

    @property
    def classChoice1(self):
        return self._classChoice1

    @classChoice1.setter
    def classChoice1(self, input):
        # check if new value conflicts with other existing choices
        If input != self._classChoice2 and input != self._classChoice3
            self._classChoice1 = input
        else:
            # decide how you handle the error
            pass

    # repeat for the other two Choice fields

This blog has a similar example.

Chris Freeman
Chris Freeman
Treehouse Moderator 68,441 Points

An additional caution is to not use the name "Class" as the name of the class since it is too close to the keyword class

Thank you for your help!

Quick Question:

Could I use the

   unique=True

Property on the foreign key instead of the setter method you are showing? Or does the

  unique=True

Refer to the data base globally?

Chris Freeman
Chris Freeman
Treehouse Moderator 68,441 Points

Correct. Using unique=True on, say, classChoice1 would mean no other Students could have that same class also as their classChoice1.

As additional feedback, the name of classes are usually in singular form since each instance represents a single student. So Student would be the preferred form.

Another question. Is there a way to refactor

@property
def classChoice1(self):
    return self._classChoice1

@classChoice1.setter
def classChoice1(self, input):
    # check if new value conflicts with other existing choices
    If input != self._classChoice2 and input != self._classChoice3
        self._classChoice1 = input
    else:
        # decide how you handle the error
        pass

into a method that handle Nth class choices ? Could I use a DICT to store the the choices then have only one method to deal with the logic of making sure each choice is unique?

Chris Freeman
Chris Freeman
Treehouse Moderator 68,441 Points

There isn't much refactoring to do. Perhaps you could create a helper function that checks if the purposed new value is the same as any other attribute:

def check_attr_match(self, input):
    for item in dir(self):
        # check for name match and value match
        if 'classChoice' in item and input == getattr(self, item):
            # attribute match found return True
            return True
    return False

@property
def classChoice1(self):
    return self._classChoice1

@classChoice1.setter
def classChoice1(self, input):
    # check if new value conflicts with other existing choices
    If check_attr_match(input):
        # Match found. Decide how you handle the error
        pass
    else:
        self._classChoice1 = input