Django - how do you decide which model to put foreign key? - python

Lets say I have two models that looks like this:
class Album(models.Model):
pub_date = models.DateTimeField(auto_now_add=True)
title = models.CharField(max_length=250, blank=False, unique_for_date="pub_date")
class Track(models.Model):
title = models.CharField(max_length=250, blank=False, unique_for_date="pub_date")
album = models.ForeignKey(Album)
What is the difference between putting the ForeignKey (one-to-many) relationship on the Track model versus having a many-to-many on the Album model?
How does one decide such a thing?

Those would do completely different things.
Like you said, a ForeignKey is a one-to-many relationship. If you put it on Track, that means that many tracks belong to one album (or in other words, one album has many tracks). If you put it on Album, that means that many albums belong to one track, which is clearly not right.
The situation where there is a choice is when you're using a ManyToManyField. There, both sides are "many", so the choice of which side to put the field on is a purely semantic one.
Edit Again, these have different effects. A many-to-many would mean that both sides can have multiple items: an album can have many tracks and a track can belong to many albums.

Related

Django. Should I use ForeignKey or Addtional Cross Table for one to many relation?

I'm aware of this question was asked before, but that question doesn't have concise answer for my problem. I'm bit confused after seeing two examples in order to impelement OneToManyRelation.
In my example:
class Product(BaseModel):
name = models.CharField(max_length=255)
class Advantages(BaseModel):
title = models.CharField(max_length=255)
product = models.ForeignKey(Product, CASCADE)
Different products can have many advantages linked to it, so I'm using ForeignKey for this, but here I saw that it is also possible to use cross table relation in order to implement OneToManyRelation
categories & sub categories with many to many relationship
class ProductAdvantage(BaseModel):
title = models.CharField(max_length=255)
product = models.ForeignKey(Product, CASCADE)
Which one best practice for the OneToManyRelation? One product can have many advantages
Thank you for the answer

How to save the data that has same model but with different data in Django

I'm working on a mini project which uses Django 1.8. The aim is to build a small billing app. So, I've created two models, Bill and Product, as follows.
#bill/models.py
class Bill(models.Model):
date_of_issue = models.DateField()
name = models.CharField(max_length=50, default="N/A", null=True)
address = models.CharField(max_length=150, default="N/A", null=True)
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
def __str__(self):
return "{} {}".format(self.input_name, self.date_of_issue)
class Product(models.Model):
bill = models.ForeignKey(Bill, on_delete=models.CASCADE)
description = models.CharField(max_length=100, default="N/A")
quantity = models.IntegerField(default=0)
total = models.IntegerField(default=0)
By seeing the model, you can tell that my approach is to create Bill and Product tables and connect the Product to Bill via ForeignKey. Now, the thing is that a single bill will contain at least one product. If there are more than one product, how should I write my views in views.py. I'm a beginner in the Django development. If a Bill contains a single Product then I can write its view. But how can I store multiple Product which have different data and storing it in database.
For Example
The user will enter the name and address of the customer. Then the user will enter the details of products. Now I want to generate the Product modelform more than once (depends upon the number of products added by user). How can I accomplish this ?
Assuming
1) multiple products can be bought at once (and thus be part of one bill) and
2) one product can be bought multiple at any time (and thus be part of many bills)
a simple foreign key is the wrong modelling attempt. Instead of a m:1 relation you need a m:n relation - and thus a ManyToManyField. With a ManyToManyField you can add multiple products to one bill or have mutiple products added to multiple bills. In django-admin it's useful (and I recommend it) to put ManyToManyFields as filter_horizontal which eases the use of this field.
Plus, django will automatically resolve your m:n relation with an additional third database table, so you don't need to take care of this.

How to model this kind of a relationship in django?

I want to have two models:
class Receipt(models.Model):
# Bunch of products
class Product(models.Model):
name = models.CharField(max_length=100)
price = models.IntegerField()
I don't want the product to know about receipt but just the receipt to know about the products. How do I build this relationship?
PS: One product can be in multiple receipts.
If it is just like you say a manyTomanyField is enough.
But if you need to store also the quantity of each ingredient on each receipe then do you need a many2many with attributes relation
One2Many relationship doesn't come out the box with Django. However, I think this answer is what you're after : Django one-to-many field without reversing dependency

Having a model to relate to several different models

I have a simple notification model:
class Notification(models.Model):
user = models.ForeignKey(User)
sender = models.ForeignKey(User)
model = '''What to put here?'''
comment = models.CharField(max_length=200)
created = models.DateTimeField(auto_now=False,auto_now_add=True)
I need the notification to relate to several different models, for example; posts, user follows, etc
Is there anyway in django you can relate to several models instead of creating a notification model for each one?
I want to avoid models like this:
PostLikeNotification, UserFollowNotification, etc.
So does django have this functionality? I couldn't find it anywhere in the docs.
You could use Content Types/Generic Relations
class Notification(models.Model):
user = models.ForeignKey(User)
sender = models.ForeignKey(User)
object_id = models.PositiveIntegerField(default=None, null=True)
content_type = models.ForeignKey(ContentType, default=None, null=True)
comment = models.CharField(max_length=200)
created = models.DateTimeField(auto_now=False,auto_now_add=True)
#property
def model_object(self):
content_type = self.content_type
object_id = self.object_id
if content_type is not None and object_id is not None:
MyClass = content_type.model_class()
model_object = MyClass.objects.filter(pk=object_id)
if model_object.exists():
return model_object.first()
return None
Here we are storing the Model (Using the Content Types framework) and Primary Key (must be an Integer in this example) of the related object in the Notification model, then adding a property method to fetch the related object.
With this you can relate your notifications to any other model. You could also use the ForeignKey.limit_choices_to argument on the content_type field to validate that it only accepts certain models.
Django need to know the model before creating a relation, you can store the model in char field like post:23 user_follow:41 and define a get_model method that will parse that field and return the right model object
All depends on your design, you have several options. Different options depend on the size of your database:
How many notifications are there?
Do you need to update the notifications often?
Or most of the notifications are inserted once and then read often?
Use an abstract model
Use an abstract model and actually create the PostLikeNotification and UserFollowNotification and other models of such a kind.
class Notification(models.Model):
# ...
class Meta:
abstract = True
class PostLikeNotification(Notification):
model = models.ForeignKey(SomePost)
class UserFollowNotification(Notifcation):
model = models.ForeignKey(Follower)
# ...
This has several advantages:
You keep your relations in your (relational) database.
You have strong foreign keys to prevent inconsistent data.
It is "Djangoic": relations in the database, starting with a normalised database, and no early optimisations are django's way of doing things.
And, of course, this has some disadvantages:
If you need to search all notifications for something the query will be complex.
Moreover, a query over all notifications will be slow, since it filters several tables.
Use a CharField
You can use a simple CharField and store in it the model name and id. Or two fields one for the name and another for the id.
class Notification(models.Model):
model_type = models.CharField(max_len=48)
model_id = models.PositiveInteger()
Advantages:
You have a single table, querying is faster if you have the right indexes.
You can get one of the types of notifications with a simple comparison (index model_type for extra speed).
Disadvantages:
Inconsistent data may appear.
You will need to add extra code at a higher level to deal with possible inconsistent data.
Parallel writes (that may need to lock the entire table) may be a problem.
The middle ground, use several foreign keys
This is just one way of implementing a middle ground between the two options below: You add several nullable foreign keys. Other ways of achieving middle ground exist.
class Notification(models.Model):
model_post = models.ForeignKey(SomePost, null=True, blank=True)
model_follow = models.ForeignKey(Follower, null=True, blank=True)
Advantage:
Verification of inconsistent data can be made without searching other tables (foreign keys are foreign keys, the database takes care of their consistency).
Disadvantage:
It has most of the disadvantages of the other two methods but to a lesser extent (at least in most of them).
Conclusion
If you're just starting a project, and you do not know (or are not worried) about the volume of data then do create several tables. Abstract models were created for this purpose.
On the other hand if you have a lot of notifications to be read and filtered (by a lot, I mean millions) then you have good reasons to create a single notification table and process the relations at a higher level. Note that this incurs locking problems, you shall (almost) never lock notifications if you have a single table.

Django OneToOneField, ManyToManyField, Foreign Key

I've read many posts on what OneToOneField, ManyToManyField, and Foreign Key are but they aren't very clear. I am very new to Django and python programming, currently trying to develop models. Can someone explain to me in simple language, preferably with example, what they each are?
Imagine a database, which stores your book collection:
from django.db import models
class Place(models.Model):
address = models.CharField(max_length=50)
country = models.CharField(max_length=50)
class Publisher(models.Model):
name = models.CharField(max_length=30)
place = models.OneToOneField(Place, primary_key=True)
class Author(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=40)
class Book(models.Model):
title = models.CharField(max_length=100)
publisher = models.ForeignKey(Publisher)
authors = models.ManyToManyField(Author)
One-to-many/Foreign Key
Every Book has one Publisher, but a Publisher might have published multiple books. Therefore they are in a one-to-many (book-to-publisher) relationship.
One-to-one
Every Publisher is located in one Place, and every Place can only hold one Publisher. Therefore they are in a one-to-one relationship. You could just have well have put the Place information (address and country) with the Publisher model in one table, but sometimes it is preferred to have seperate models. For example, if you do not know the Place for every Publisher, you don't need to take up a lot of space with empty rows.
Many-to-many
Every Book also has one or more Authors. However, an Author might have written multiple Books, so they are in a many-to-many relationship.
If you still need some guidance, I suggest taking a look at the model chapter of the Django Book.

Categories