2

I have a problem to make it easier : I have a relation like user -> Hotel - > Rooms . User can create Hotel and then every hotel can have many rooms .

Now I have a user model like

class UserProfile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    company_name=models.CharField(max_length=50, null=False, blank=False)
    email=models.CharField(max_length=50, null=False, blank=False)
    company_number=models.CharField(max_length=50, null=False, blank=False)

and to create restaurant

class Restaurant(models.Model):
    rest_owner = models.ForeignKey(UserProfile, on_delete=models.CASCADE, related_name='rest_owner')
    name = models.CharField(max_length=50, null=False, blank=False)
    address = models.TextField(max_length=100, null=False)
    city = models.CharField(null=True, max_length=50)
    country = models.CharField(null=True, max_length=30)

and now room

class Room(models.Model):
    rest_owner = models.ForeignKey(Restaurant, on_delete=models.CASCADE, related_name='rest_owner')
    name = models.IntegerField()
    Rooms = models.IntegerField()

is that a good approach to do this ? and to save images of room and restaurant Should I make a

class Image(models.Model):
    image = models.ImageField(null=False, upload_to='Gallery')

and then use in room and restaurant like images = models.ManyToManyField(Image) ? . I need to know best ways to doing both of these . thanks

1 Answer 1

2

Most of your design is fine, however, there are a few minor issues:

class UserProfile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    company_name=models.CharField(max_length=50, null=False, blank=False)
    email=models.CharField(max_length=50, null=False, blank=False)
    company_number=models.CharField(max_length=50, null=False, blank=False)
  1. the User model already has an email field, so you don't need one here.
  2. null=False, blank=False is the default and should be dropped.
  3. if company_name and company_number are related then you should make this 2nd Normal Form by making them a foreign key to a Company model
    class Company(models.Model):
        name = models.CharField(max_length=50)
        number = models.CharField(max_length=50)

    class UserProfile(models.Model):
        user = models.OneToOneField(User, on_delete=models.CASCADE)
        company = models.ForeignKey(Company)

For the Restaurant model:

class Restaurant(models.Model):
    rest_owner = models.ForeignKey(UserProfile, 
                                   on_delete=models.CASCADE, 
                                   related_name='rest_owner')
    name = models.CharField(max_length=50)
    address = models.TextField(max_length=100)
    city = models.CharField(null=True, max_length=50)
    country = models.CharField(null=True, max_length=30)
  1. The rest_owner foreign key says that one user can own multiple Restaurants, and the on_delete=CASCADE says that if you delete a User or UserProfile, then then all associated Restaurants should also be deleted. Are you sure this is what you want?
  2. The related_name makes it so you can say my_user.rest_owner.all() to get all the restaurants owned by the user, which doesn't exactly flow of the tongue. It's better to use a plural of the class name you're in, i.e. related_name="restaurants" will give you my_user.restaurants.all().
  3. It doesn't make sense to have TextFields with a length less than the max length for a CharField.
  4. I would make country a two character field and fill it with the country's ISO 3166-1 alpha-2 code.

For the Room model:

class Room(models.Model):
    rest_owner = models.ForeignKey(Restaurant, 
                                   on_delete=models.CASCADE, 
                                   related_name='rest_owner')
    name = models.IntegerField()
    Rooms = models.IntegerField()

I'm not sure what you want to do with the name and Rooms fields, so I'll skip those. For the foreign key to Restaurant:

  1. It is a good practice to name the foreign key field with the name of the model it points to, i.e.
    class Room(models.Model):
        restaurant = models.ForeignKey(Restaurant, ...)

that allows you to say e.g.: my_room.restaurant.city.

  1. similarly to above, the related name should be a plural of the model you're in, so
    class Room(models.Model):
        restaurant = models.ForeignKey(Restaurant, related_name='rooms', ...)

which gives you my_restaurant.rooms.all(), which is reads much better than my_restaurant.rest_owner.all() -- which would be hard to guess returned rooms...

For the images you need to consider:

  1. can images be shared between rooms (yes => ManyToMany, no => ForeignKey)
  2. if an image is edited, should all the rooms that use the image get the changes immediately (yes => ManyToMany, no => ForeignKey).

a good rule-of-thumb though is - if you're in doubt, probably use a foreign key ;-)

Sign up to request clarification or add additional context in comments.

2 Comments

perfect explanation . Just one question , if I want to have multiple image against every room I should use ManyToMany image field I think ?
Yes, if the same set of images should be used with more than one room it would be sensible to use a ManyToMany field.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.