2
\$\begingroup\$

I have a small Django project to help organize museum artwork. In my models.py file, my museum object is defined as follows:

class Museum(models.Model):
    """Model representation of an art museum"""
    title = models.CharField(max_length=50)
    website = models.URLField()
    description = models.TextField()
    image = models.ForeignKey(AppImage, blank=True, null=True)
    longitude = models.FloatField()
    latitude = models.FloatField()

    @property 
    def marker_info(self):
        """Get information accessible for google map"""
        return { "title": self.title, "website" : self.website, "description" : self.description,
            "latitude" : self.latitude, "longitude" : self.longitude, "id" : self.id }

    @property 
    def artwork(self):
        """Get the museum's artwork"""
        return Artwork.objects.filter(museum__id=self.id)

    @property
    def artists(self):
        """Get the museums' unique artists"""
        return { artwork.artist.id : artwork.artist for artwork in self.artwork }.values()

    @property
    def count(self):
        """Get the museum's number of artworks"""
        return len(self.artwork)

    @property
    def nearby(self):
        """Get neighboring museums by distance"""
        return sorted(Museum.objects.all().exclude(id__exact=self.id), key=lambda x: self.distance(x))

    def distance(self, other):
        """ Compute the Euclidean distance between
            this and another museum """
        def cartesian(obj, r=3959): # mean radius of earth in miles
            lon = math.radians(obj.longitude)
            lat = math.radians(obj.latitude)
            x = r * math.cos(lat) * math.cos(lon)
            y = r * math.cos(lat) * math.sin(lon)
            z = r * math.sin(lat)   
            return x, y, z

        x1, y1, z1 = cartesian(self)
        x2, y2, z2 = cartesian(other)
        return math.sqrt((x1 - x2)**2 + (y1 - y2)**2 + (z1 - z2)**2)

    def __str__(self):
        return '%s, %s' % (self.title, self.website)

Since most of the business logic for display is stored in the model, my views are pretty clean:

def museum(request):
    return render(request, "museum.html",
        { "museum" : center(request) })

def nearby(request):
    return render(request, "tabs/nearby.html",
        { "nearby" : center(request).nearby })

def artists(request):
    museum = center(request)
    return render(request, "tabs/artists.html",
        { "artists" : [(artist, artist.count(museum)) for artist in museum.artists] })

def gallery(request):
    return render(request, "tabs/gallery.html",
        { "artworks" : center(request).artwork })

def center(request):
    return Museum.objects.get(pk=request.GET['id'])

With the MVVM pattern, we would put these functions in a view model class rather than in a model class. Coming from this perspective, I'm concerned that my business logic is crowding and polluting the purity of my model. Is this a valid concern? Is there a better place I should be putting these properties and business logic functions?

\$\endgroup\$
2
\$\begingroup\$

Django's philosophy is Thin views, Fat models. This may be true for small applications, as application grows, it becomes extremely complex to manage all business actions in model layer.

One of the suggested approach is to have a separate layer to handle business actions. This can be similar to view, name it orchestrator or business_actions.

The responsibility of the layer is to do one business action which can touch multiple models. Say, register a new client means creating new user, new client, send notification, sync to external system. Having all these in multiple models is cumbersome.

The business action layer can be modelled as class or simple function which takes data and does all the relevant work.

Here is an example todo application which is designed to address these concerns.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.