Search code examples
pythondjangomodels

Many-to-many relationship children exclusive to parent model. How?


If there is a way to better word the title of this question please let me know.

In django I am attempting to create this sort of hierarchy of models:

User
-Author [Author model]
--Sentence [Sentence model]
--Find_Replace [FindReplace model]

A user sets up multiple authors as "pen names". An author has his own sentences, and his own predefined find/replace sets. A sentence can be associated with multiple find/replace sets, but only with the sentences created by that author.

The thing I am getting stumped on is this: How do you make such a relationship?

Here is what I have - without programmatic amendments, I am at a loss as to a good way to keep these relationships strictly defined.

Here are the models thus far, only partially correct:

class Author(models.Model):
    created_by = models.ForeignKey(User)  


class FindReplace(models.Model):     
    created_by = models.ForeignKey(User)   
    author = models.ForeignKey(Author)              

    find = models.CharField(max_length=256)
    replace = models.CharField(max_length=5000)


class Sentence(models.Model):      
    created_by = models.ForeignKey(User)   
    account = models.ForeignKey(Account)   


    text = models.CharField(
        max_length=500, 
        blank=False, 
        null=False, 
        )

Solution

  • I don't see why you will require created_by field in every model, because they are related to Author hence related to User. I will suggest to use like this:

    class Author(models.Model):
        created_by = models.ForeignKey(User)  
    
    
    class FindReplace(models.Model):       
        author = models.ForeignKey(Author)              
    
        find = models.CharField(max_length=256)
        replace = models.CharField(max_length=5000)
    
    
    class Sentence(models.Model):        
        account = models.ForeignKey(Account)  #Is account related to user? The you can query it by user.
        # Or add an FK relation to Author. 
    
    
        text = models.CharField(
            max_length=500, 
            blank=False, 
            null=False, 
            )
    

    About strictly maintaining the rule, you can't define that in model structure. You can use model validation or Modelform validation or write your own function in models like this: (For Example)

    class FindReplace(models.Model):       
            author = models.ForeignKey(Author)              
    
            find = models.CharField(max_length=256)
            replace = models.CharField(max_length=5000)
    
           def _validate_creation(self, user_id):
              if self.author.created_by.id == user_id:
                  return True
              else:
                  return False
    

    Usage: in views.py:

    def someview(request):
          fr= FindRepace()
          fr.author = author_obj
          fr.find = 'Foo'
          fr.replace = 'Bar'
    
          if fr._validate_creation(request.user.id):
             fr.save()