Suggestions for improving efficiency of simple models design

Hi everyone,

I’m new to Django and web development, coming from a background of Data Engineering. I’m running into a problem (probably very basic to an expert) while I’m creating a simple application which displays Services offered by Shops. I’ve solved the problem but I want to know if I’m doing things efficiently.

Here is my models.py (simplified version):

from django.db import models

# Represent a shop that offers services
class Shop(models.Model):
    name = models.CharField(max_length=100)
    
    def __str__(self):
        return self.name

# Represents the services offered
class Service(models.Model):
    name = models.CharField(max_length=100)
    price = models.DecimalField(max_digits=10, decimal_places=2, default = 0)
    shop = models.ManyToManyField(Shop, related_name='shop_services')
    
    def __str__(self):
        return self.name

Context :

On my home view I have a search bar, which allows users to look up a service like ‘Cleaning’. When the user submits text here, I have a reverse filter through the Shops model to find all the shops which provide the service related to what was searched. Then on the search view, I am iterating through shops and then another iteration through all the services to find all the related services. I basically want to show cards with each applicable shop with their associated service and price.

The problem area, looking for suggestions to improve:

I want to be able to display all related services offered by a shop in one card, rather than creating a new card for every shop-service combination. So is my model design correct? Are there long term efficiency issues that can arise when the data size increase?

Here is my views.py:

def home(request):
    if request.method == 'POST':
        # Fetching the requested service
        service_name = request.POST.get('service_name')
        return redirect('search', service_name = service_name)
    else:
        return render(request, template_name='main/home.html', {})

def search(request, service_name):
  
    shops = Shop.objects.filter(shop_services__name__icontains = service_name).distinct()
    return render(request, 'main/search.html', context = {'searched' : service_name, 'shops_found': shops}) 

From what you’ve shown so far, it looks good. There’s nothing obviously wrong.

But since we don’t have a deep understanding of the requirements for your application, or what it is you’re trying to model, and what operations you are going to perform on that model, it wouldn’t be appropriate for anyone else to describe it as “correct” or “incorrect”.

The only improvement I see to this query would be to include a prefetch_related('shop_services') call to your query.

There is another way to approach this.

service = Service.objects.all(name__icontains=service_name)

(with a .prefetch_related('shop') if desired)

Depending upon what exactly you’re trying to produce here, this may (or may not) be a better solution.
The difference between these two is that this version will return the same shop multiple times if there are difference services that match the search criteria.

1 Like

Thank you Ken!

Yeah, this would still work but I’m trying to avoid returning the same shop multiple times for related services on the search view. Since on the search view, I want to show:

  • SHOP 1: Service – Price, Service–Price
  • SHOP 2: Service – Price, Service–Price

I’ll provide some more information on the application to get your thoughts on other things I can change. I want to implement a shop service scheduling website. A shop will be able to list their business by providing the services they offer and the prices they will charge. Users will be able to log in and search for a service (‘Semi-Detached Home Cleaning’), which will return multiple shops that offer any related services and their prices on the search view.

So for example if the user searches for “Cleaning”, then we might return the following on the search view:

  • SHOP 1: ‘Garage Cleaning’ – $ 250.00, ‘Roof Shingle Cleaning’ – $200.00
  • SHOP 2: ‘Garage Cleaning’ – $ 250.00,

I also want users to be able to schedule appointments on my website, which I suppose will impact my model.

Yep, I can understand that, and what you’ve got should serve you well for it.

However, I wouldn’t want to rule out the other query as an option. There is something to be said for a listing like:

  • Garage cleaning: Shop 1 - $250, Shop 2 - $200
  • Roof shingle cleaning: Shop 1 - $200