Proper way of using Models with foriegnkey in Django - python

I'm new to Django and I know little bit about databases.
Let me explain my problem.
For example I have two models- Person and Car (A person can have multiple cars.)
class Person(models.Model):
name
username
password
#some more user attributes.
class Car(models.Model):
user = models.ForeignKey(Person)
car_name
car_price
#other car atrributes
Currently I'm working with models like this but somebody told me that you should use like below -
class Car(models.Model):
car_name
car_price
#other car atrributes
class Person(models.Model):
name
username
password
car = models.ForeignKey(Car)
#some more user attributes.
Noticed reverse relationship? from person to Car or Car to person which one should I use.
I know I can use related_name value in ForeignKey field for reverse lookup. I'm just curious about efficiency,standard and other advantages of one over other.
PS: although first one I'm using currently and its working perfectly.

Suppose a car can have only one owner.
Then, I would write it this way:
class Car(models.Model):
owner = models.ForeignKey(Person, related_name='cars")
class Person(models.Model):
# ... fields unrelated to cars

Related

Django: constrain foreign key to only rows with the same id

For a Django project, I got two models:
class User(AbstractUser):
child = models.ForeignKey('children.Child', null=True, on_delete=models.SET_NULL)
And the following:
class Child(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
What I want is that User.child can only be set to an entity that has child.user_id = user.id, with a constraint preferably. Is this possible? If it matters, I am using PostgreSQL
Aren't you looking for a one-to-one relationship?
user in Child can only be set to one User.
child in User can also only be set to one Child.
You want user in Child and child in User to point to each other.
This is exactly what a one-to-one relationship is. The following code is even simpler than your current one and it enforces the constraint at the database level:
class User(AbstractUser):
# The relationship only needs to be defined in one of the models
pass
class Child(models.Model):
user = models.OneToOneField(User, null=True, on_delete=models.CASCADE)
If there are finer points you need to cover (eg. if there are situations in which you would need the relationship to be defined in one direction but not in the other), then please clarify the use case.

Best practices for products catalogue in Django

I'm working on a catalogue application for storing product information in Django.
The challenge here is that there are a lot of products in the catalogue, each with their own attributes. Since this is a key part of the application, and a lot will be built around it, I want this to be designed as good as possible.
I know there are several options of handling this in Django, but I would like to know what others have experienced with these several options.
The first option: Single abstract class
I could just create a single abstract class, which contains all the base attributes, and let other classes derive from that one class.
class Product(models.Model):
name = models.CharField(max_length=100)
description = models.TextField(max_length=1000)
price = models.DecimalField()
class Meta:
abstract = True
class Phone(Product):
series = models.CharField(max_length=100)
This would be the most straightforward option, but this will include a lot of work in Django Forms and Views.
This will also create a single table for each Product subclass, so when the Product class is changed, all other tables will have to changed as well.
The second option: Product base class
Here the Product class is not abstract, which implies this class can be used as well.
class Product(models.Model):
name = models.CharField(max_length=100)
description = models.TextField(max_length=1000)
price = models.DecimalField()
class Phone(Product):
series = models.CharField(max_length=100)
This would also be pretty straightforward, but this would still imply a lot of work in the Forms and Views.
This would first create a table for the Product class, and then a single table for each Product subclass.
The first 2 options will also break the DRY principle, because attributes will have to be added to every Product subclass that might be common to some classes, but not to all.
Third option: Product class containing all the possible attributes.
class Product(models.Model):
name = models.CharField(max_length=100)
description = models.TextField(max_length=1000)
price = models.DecimalField()
# attributes for phones, tv's, etc...
series = models.CharField(max_length=100)
class PhoneForm(forms.ModelForm):
class Meta:
model = Product
fields = ['name', 'description', 'price', 'series']
A new form will have to be created for each product subclass. This does seem pretty easy, but the Product model will become very bloated.
In this case I could also use Proxy Models.
Fourth option: Create Abstract classes and use class Mixins
class ProductBase(models.Model):
name = models.CharField(max_length=100)
description = models.TextField(max_length=1000)
price = models.DecimalField()
class Meta:
abstract = True
class ElectronicsProduct(models.Model):
series = models.CharField(max_length=100)
class Meta:
abstract = True
class Phone(ProductBase, ElectronicsProduct):
pass
This method could solve the DRY problem I have with the issue I had above, but still not optimal.
Fifth option: One Product model with a separate attribute model
This is a method I would like to use anyway, but more to have the ability to add 'extra' features to a product that is too specific to put in a Product or Product subclass.
class Product(models.Model):
name = models.CharField(max_length=100)
description = models.TextField(max_length=1000)
price = models.DecimalField()
class Attribute(models.Model):
name = models.CharField(max_length=100)
class ProductAttribute(models.Model):
product = models.ForeignKey(Product)
attribute = models.ForeignKey(Attribute)
value = models.CharField(max_length=100)
The question here is if this method should be used for all product attributes, since I think this will add a lot of overhead on the database.
Another challenge here is the value type. In this case I can only use a character value, so what happens when I would like to use a Decimal value, or a File.
Sixth option: Something else
There are probably some methods I have not thought of at this point. So if you know something I don't please share it with me.
I am not looking for any opinions here, but for some solutions. So if you have an answer to this question please tell us why you would use the method you propose.

Django What is reverse relationship?

Can someone tell me what is reverse relationship means?
I have started using Django and in lot of places in the documentation I see 'reverse relationship, being mentioned. What is it exactly mean? why is it useful? What does it got to do with related_name in reference to this post ?
Here is the documentation on related_name
Lets say you have 2 models
class Group(models.Model):
#some attributes
class Profile(models.Model):
group = models.ForeignKey(Group)
#more attributes
Now, from a profile object, you can do profile.group. But if you want the profile objects given the group object, How would you do that? Thats' where related name or the reverse relationship comes in.
Django, by defaults gives you a default related_name which is the ModelName (in lowercase) followed by _set - In this case, It would be profile_set, so group.profile_set.
However, you can override it by specifying a related_name in the ForeignKey field.
class Profile(models.Model):
group = models.ForeignKey(Group, related_name='profiles')
#more attributes
Now, you can access the foreign key as follows:
group.profiles.all()
For a clearer picture you can assume that when we use reverse relationship, it adds an extra field in the referenced model:
For example:
class Employee(models.Model):
name = models.CharField()
email = models.EmailField()
class Salary(models.Model):
amount = models.IntegerField()
employee = models.ForeignKey(Employee, on_delete=models.CASCADE, related_name='salary')
After using related_name in Salary model, now you can assume the Employee model will have one more field: salary.
For example, the available fields would now be:
name, email, and salary
To find an employee, we can simply query in this way:
e = Employee.objects.filter(some filter).first()
To check their salary, we can check it by writing
e.salary (now we can use salary an attribute or field in employee model). This will give you the salary instance of that employee, and you can find the amount by writing e.salary.amount. This will give you the salary of that employee.
In case of many to many relationship we can use .all() and then iterate over that.
In Django 2.0 you would define a ForeignKey as follows
mainclient = models.ForeignKey( MainClient, on_delete=model.CASCADE, related_name='+')
the related_name='+' would cancel the default reverse relationship that Django sets up, so in the previous example, you would not be able to query the profiles using group.profiles.all().

Using related_name correctly in Django

I have two models that are related together using ForeignKey and related_name is used. Here is an example.
class Student(models.Model):
name = models.CharField(max_length=255)
birthday = models.DateField(blank=True)
class Class(models.Model):
name = models.CharField(max_length=255)
student = models.ForeignKey(Student,
related_name='classes',
null=True)
def __unicode__(self):
return self.name
For example, I would like to access the class name.
This is what i tried.
john = Student.objects.get(username = 'john')
print john.classes.name
nothing's get printed.
But when i try john.classes
i get django.db.models.fields.related.RelatedManager object at 0x109911410. This is shows that they are related. But i would like to get the class name.
Am i doing something wrong? How do i access the name of the class using related_name? Need some guidance.
Yes, classes is a manager. It can be several classes for one teacher. So to output their names you should do:
john = Student.objects.get(username='john')
for class2 in john.classes.all():
print class2.name
If you want only one class for one student then use one-to-one relation. In this case you can access the related field with your method.
Just be aware: you are defining a 1-many relationship. Thus, student could have multiple classes, therefore john.classes.name cannot work, since you have not specified the class of which you want to have the name. in john.classes "classes" is just a manager that you can use like any other Django Model Manager. You can do a john.classes.all() (like sergzach propsed), but also things like john.classes.get(...) or john.classes.filter(...).
you can do like this to access the first row in the table
john = Student.objects.get(username = 'john')
john.classes.all().first().name # to access first row
john.classes.all().last().name # to access last row
in the above example you don't want to iterate over the objects
it will give you the name of the class in the first row

Abstract base class inheritance in Django with foreignkey

I am attempting model inheritance on my Django powered site in order to adhere to DRY. My goal is to use an abstract base class called BasicCompany to supply the common info for three child classes: Butcher, Baker, CandlestickMaker (they are located in their own apps under their respective names).
Each of the child classes has a need for a variable number of things like email addresses, phone numbers, URLs, etc, ranging in number from 0 and up. So I want a many-to-one/ForeignKey relationship between these classes and the company they refer to. Here is roughly what I imagine BasicCompany/models.py looking like:
from django.contrib.auth.models import User
from django.db import models
class BasicCompany(models.Models)
owner = models.ForeignKey(User)
name = models.CharField()
street_address = models.CharField()
#etc...
class Meta:
abstract = True
class EmailAddress(models.model)
email = models.EmailField()
basiccompany = models.ForeignKey(BasicCompany, related_name="email_addresses")
#etc for URLs, PhoneNumbers, PaymentTypes.
What I don't know how to do is inherit EmailAddress, URLs, PhoneNumbers (etc) into the child classes. Can it be done, and if so, how? If not, I would appreciate your advice on workarounds.
I suspect you'll be better off with generic relations for the links, rather than trying to tie everything to a base class. Generic relations allow you to link a model such as EmailAddress to any other class, which would seem to be a good fit with your use case.

Categories