Correct way to make python module smaller by delegating
Question: I'm trying to reduce clutter in my project's models.py and I decide to move
out "utility" methods of some models.

The idea was to create a bunch of utility modules with classes and functions
which will be used by model classes, but since there is no significant piece
of code that doesn't use other models, it results in a circular dependence.
E.g. in `models.py`:

    
    
    from myproject import parse_util
    
    class Entry(models.Model):
        text = models.TextField()
        parser = parse_util.Parser(self)
    
        def get_some_object():
            return parser.parse_text()
    
    class SomeModel(models.Model):
        name = models.CharField(max_length=32, null=False, unique=True)
    

In `parse_util.py`:

    
    
    from myproject.models import SomeModel
    
    class Parser():
    
        def __init__(self, entry):
            self.entry = entry
    
        def parse_text(self):
            # parsing self.entry.text
            ...
            some_object = SomeModel.objects.get(name=parsed_value)
            return some_object
    

I can avoid it by importing `SomeModel` directly in the function, instead of
doing it module-wide, or use `get_model('myapp', 'SomeModel')`. But both of
these don't look good.

After the whole day in thoughts I generalised the problem: what is the correct
and pythonic way (if any) to move some code coupled with another code in the
module out of that module?

That is if there is a module with `classA` and `classB` and there are lengthy
methods of `classB`, which use both `classA` and `classB` in some way, is
there any good solution to cut down described module by splitting it into
several models, but keeping entry points to `classA` and `classB` in place.


Answer: So you have the following hardcoded dependencies: Entry → Parser → SomeModel.

The way I would break the dependency is to make `Parser` generic like this:

    
    
    class Parser(object):
    
        def __init__(self, entry, model):
            self.entry = entry
            self.model = model
    
        def parse_text(self):
            # parsing self.entry.text
            ...
            some_object = self.model.objects.get(name=parsed_value)
            return some_object
    

Now the hardcoded dependencies are just: Entry → Parser

