Question

I stuck on a simple design decision with some Django Models. As from my understanding either a Foreignkey nor a ManyToMany fits in here.

Let's take the pizza/topping example from the Django docs to work with:

class Topping(models.Model):
    # ...

class Pizza(models.Model):
    # ...
    toppings = models.ManyToManyField(Topping)

This is clearly a ManyToMany relationship.

Now let's take another example. I have 10 bikes to lend out, and also I have some equipment (i.e. helm, gloves).

Then the Model should be:

class Bike(models.Model):
    # ...

class Equipment(models.Model):
    # ...

class LendBike(models.Model):
    # ...
    bike = models.ForeignKeyField(Bike)
    equipment_1 = models.ForeignKey(Equipment)
    equipment_2 = models.ForeignKey(Equipment)
    ...

But how can I manage this if I don't know how many equipment someone got?

Was it helpful?

Solution

A design using events can help you to track actions of your users. In the code bellow, you have 3 classes dedicated to your stuff here (Bike, Glove, Helmet), and an Event class which will be instantiated every time a user borrow stuff or render stuff.

With all this data in your database, you are able to know the state of your stuff (borrowed or available) in real time plus have an history of everything.

You can add fields like "lender" to your stuff classes, but it's not DRY and can create inconsistency. On the other hand, it can help you to NOT create impossible events (like borrowing already borrowed stuff).

class Bike(models.Model):
    lender = models.ForeignKeyField(User)
    # lender == None means your Bike is available!

class Glove(models.Model)
    lender = models.ForeignKeyField(User)

class Helmet(models.Model)
    lender = models.ForeignKeyField(User)

class BorrowOrRenderEvent(models.Model):
    date = models.DateTimeField(auto_now_add=True)

    # Stuff borrowed or rendered (we assume we can't borrow AND render stuff in the same event)
    bike = models.ForeignKeyField(Bike)
    gloves = models.ManyToManyField(GloveEquipment)
    helmets = models.ManyToManyField(HelmetEquipment)

    # Who is performing this action?
    user = models.ForeignKey(User)

    # We need to know if the event is about borrowing or rendering stuff
    is_rendering = models.BooleanField()

How to know how many equipment someone currently got?

In a class that extends the User class, add a method like this:

def count_borrowed_equipment_per_user(self):
    nb_bikes = Bike.objects.filter(lender=self.user).count()
    nb_helmets = Helmet.objects.filter(lender=self.user).count()
    nb_gloves = Glove.objects.filter(lender=self.user).count()
    return nb_bikes, nb_helmets, nb_gloves

Note

I'd like to tell that in my opinion, in general and in that case, database only cannot ensure functional consistency. It's easy to insert crap in DB even with good designing, if your business logic is bad :)

OTHER TIPS

I think this is what you want:

class Bike(models.Model):
    # ...

class Equipment(models.Model):
    # ...

class LendBike(models.Model):
    # ...
    bike = models.ForeignKeyField(Bike)
    equipments = models.ManyToManyField(Equipment)

A M2M relation between LendBike and Equipment this way you can assign as many equipment as you like.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top