Relationship between 2 models in Django - python

I have two models- Order and Expense. The expense is a crud list respective to the particular Order. How can I make such a relationship between these two models?
models.py - Order
class Order(models.Model):
user = models.ForeignKey(User,on_delete=models.CASCADE,related_name="order",blank=True,null=True)
client_name = models.CharField(max_length=100)
event_name = models.CharField(max_length=100)
contact = models.CharField(max_length=15)
event_date = models.DateField(auto_now_add=False,auto_now=False)
expenses = models.IntegerField(default=0,null=True,blank=True)
Models.py - Expense
class ProjectExpense(models.Model):
user = models.ForeignKey(User,on_delete=models.CASCADE,related_name="project_expense",null=True,blank=True)
order_id = models.IntegerField(default='0')
exp = models.CharField(max_length=100)
exp_desc = models.TextField(null=True,blank=True)
amount = models.IntegerField(default='0')
def __str__(self):
return self.exp
I tried assigning the field Order ID with the current Order. But how will I able to pass the current Order.

I'm guessing you need a ManyToOne Relationship: One Order can have multiple expenses?
For that you can remove the expenses property from the Order model.
And you need to modify the order_id property of the ProjectExpense model like this (as #Lambo already commented):
order = models.ForeignKey(Order, on_delete=models.CASCADE)
When you are querying the Order model the related Expenses will be included if you ask for them and vice versa.
The Objects are created as following in the backend:
new Order:
# input contains the data received from frontend
Order.objects.create(user_id=input.user_id,
client_name=input.client_name,
event_name=input.event_name,
contact=input.contact,
event_date=input.event_date)
new Expense:
# input contains expense details received from frontend
ProjectExpense.objects.create(user_id=input.user_id,
order_id=input.order_id,
exp=input.exp,
exp_desc=input.exp_desc,
amount=input.amount)
It is important that you write order_id= although the property in the model itself is called order.

Thanks all for providing me the answers! The feature I'm looking at is GenericForeignKey. This tutorial helped me understand it.
The working of Expenses associated with the respective Order, is way similar to the Comments and Post like in blogs.

Related

Django, many to many relationship, how to insert value for all keys in table?

I have 3 models Company, Discount and CompanyDiscountRelation as below:
class Company(models.Model):
name = models.CharField(max_length=150)
def __str__(self):
return self.name
class Discount(models.Model):
name = models.CharField(max_length=150)
discount_value = models.IntegerField()
def __str__(self):
return self.name
class DiscountCompanyRelation(models.Model):
company= models.ForeignKey(Company, on_delete=models.CASCADE)
discount = models.ForeignKey(Discount, on_delete=models.CASCADE)
is_active = models.BooleanField(default=True)
I know how to assign a previously created discount to one company. I do it by DiscountCompanyRelationForm and choose company from form list. But i want to assign discount to all companies by one-click. How to do this? I tried get all ID's by:
Company.objects.values_list('pk', flat=True)
and iterate through them but i don't think that's how it should be done and i have problem to save form by:
form.save()
I tried all day but now I gave up.
Sorry if this is basic knowledge. I've been working with django for a few days.
If I understand the question, you want to choose a subset of companies in the Company table, and apply a particular Discount.
The first can be a ModelMultipleChoiceField, the second a ModelChoiceField. Put these in a form with appropriate querysets for the companies and discount that can be chosen, and when the form validates, apply the discount:
discount = form.cleaned_data['discount']
companies = form.cleaned_data['companies']
for company in companies:
relation = DiscountCompanyRelation(
discount = discount,
company = company,
is_active = # whatever you need
)
relation.save()
You need to think about what happens when a discount is applied to a company which already has a discount. You'll put code in the above loop to check and implement the appropriate action.
I'd strongly recommend specifying a related_name on your ForeignKeys rather than relying on whatever Django generates automagically if you don't.
You might also want to look at the "through" option of a model ManyToManyField, because that's another way to create the same DB structure but brings Django's ManyToMany support code online for you.

How do I limit a django model's field choices using one of the previous fields?

The following is in my models.py:
class SensorType(models.Model):
hardware_type = models.CharField(max_length=100)
is_static = models.BooleanField(default=False)
# Some other fields
class Sensor(models.Model):
device_id = models.CharField(max_length=100, primary_key=True)
sensor_type = models.ForeignKey(SensorType, on_delete=models.PROTECT)
# Some other fields
class Asset(models.Model):
name = models.CharField(max_length=100)
sensor_type = models.ForeignKey(SensorType, on_delete=models.PROTECT) # I need to use this field to filter below
sensor = models.ForeignKey(Sensor, on_delete=models.PROTECT, limit_choices_to={'sensor_type': WHAT DO I PUT HERE?},)
# Some other fields
I need to limit the choices in the sensor field of asset so that only sensors with the sensor_type set in the field immediately above, show up.
The reasoning behind this is that there will eventually be many sensors and it would be very useful to filter this. Initially I only need this to work from the admin page but this will eventually extend when I make my Create and Update Views.
Is this even possible? I'm essentially trying to access attributes before the object has actually been created.
After reading several other questions such as this one I have also looked into ModelChoiceField but the same issue exists of trying to access the form data before it has been submitted.
I'm very open to changing the model structure if that is what is required.

How to add more columns to pivot table in many to many relations in Django?

I have 2 models united by a Many to Many relationship, in this case is Policies and Coverages so far it works fine, but I want to add another column to the pivot table since it wont work on any of the modeled tables (I want to add a IntegerField with the name 'amount' so I can store how much money are we covering for that specific coverage in that specific Insurance Police)
class Policy(models.Model):
"""Insurance Policies Model"""
number = models.CharField(max_length=25, unique=True)
company = models.OneToOneField(Company, on_delete=models.CASCADE)
client = models.OneToOneField(Client, on_delete=models.CASCADE)
start_date = models.DateField()
end_date = models.DateField()
comission = models.PositiveIntegerField()
salesperson = models.ForeignKey(Salesperson, on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
rif = models.CharField(max_length=50)
phone = models.CharField(max_length=100)
class Meta:
db_table = 'policies'
class Coverage(models.Model):
"""Coverage of the different types of policies"""
name = models.CharField(max_length=55)
policies = models.ManyToManyField(Policy)
class Meta:
db_table = 'coverages'
I made the migrations and the pivot table was made without problems, but I don't know how to add another field to the pivot table
You can specify a through=... parameter [Django-doc] for that. In fact if you do not specify this yourself, Django will automatically make an "implicit model". For example:
class Policy(models.Model):
# ...
class Coverage(models.Model):
# ...
policies = models.ManyToManyField(Policy, through='CoveragePolicy')
class CoveragePolicy(models.Model):
policy = models.ForeignKey(Policy, on_delete=models.CASCADE)
coverage = models.ForeignKey(Coverage, on_delete=models.CASCADE)
amount = models.IntegerField()
So now you can create a relation object between a policy p1 and a coverage c2 with:
CoveragePolicy.objects.create(policy=p1, coverage=c2, amount=1)
You can obtain the related set of CoveragePolicy objects for a policy p1 with:
p1.coveragepolicy_set.all()
and then inspect the amount and the related coverage it has.
Django however will have troubles migrating from an existing through model to another one, so you probably will have to remove the migration file, and create a fresh one with the new model instead (and undo the changes in the database of the old one).

Customize related field in Django model specifying foreign keys to relate through

In my Django project I have a model for products that look like this:
class Manufacturer(models.Model):
name = models.CharField(max_length=100)
class Product(models.Model):
manufacturer = models.ForeignKey('Manufacturer')
# .favorite_set: ManyToOne relation coming from the
# 'Favorite' class (shown a couple of lines below)
My site's User(s) can mark some products as Favorite. To provide this functionality, I have a Django model that looks like this:
class Favorite(models.Model):
user = models.ForeignKey(User)
product = models.ForeignKey('Product')
class Meta:
unique_together = ('user', 'product',)
In that model, the .product ForeignKey creates a reverse relation in the Product model called favorite_set. That's all good and useful: When I get an HTTP request from a user to retrieve products, I can easily figure out whether it's been favorited by a particular user or not by doing this:
product = Product.objects.get(id='whatever_id')
is_favorited = bool(product.favorite_set.filter(user=self.user).count() == 1)
# or probably:
# is_favorited = product.favorite_set.filter(user=self.user).exists()
#
Now, I have another model that is heavily denormalized (SQL denormalized, that is) that I want to use for fast text searches.
This model "pretends" to be a Product, but includes data found through the "regular" Product's FK relationships into the model itself. Something like this:
class ProductSearch(models.Model):
product = models.OneToOneField('Product',
on_delete=models.CASCADE,
related_name='searcher')
product_name = models.CharField(max_length=100)
manufacturer_name = models.CharField(max_length=100)
This class has its own id field (since it's a Django model) and, as you can see above, it is going to have a OneToOne relationship to the products (one of this ProductSearch entries is linked to one and only one Product)
Thanks to this model, if I want to search products whose manufacturer is "Ford" (for example), I don't need to join the Product table with the Manufacturer's table. I can do the lookup directly in ProductSearch and save a few milliseconds.
Since the ProductSearch is intended to be compatible with a Product, I'm also trying to model the favorite_set that occurs "naturally" in my Product class into this ProductSearch model.
And that's where the difficulties arise: I don't know how to do that :-)
I ideally would have something like:
class ProductSearch(models.Model):
product = models.OneToOneField('Product',
on_delete=models.CASCADE,
related_name='searcher')
manufacturer_name = models.CharField(max_length=100)
#
# Couldn't find anything to do the following:
product_favorite_set = models.ManyToOneField('Favorite',
through_fields=('product',))
But I haven't been able to do that.
I have tried to "abuse" the ManyToManyField like this:
class ProductSearch(BaseModel):
product = models.OneToOneField('Product',
on_delete=models.CASCADE,
related_name='searcher')
product_name = models.CharField(max_length=100)
manufacturer_name = models.CharField(max_length=100)
product_favorite_set = models.ManyToManyField('Favorite', related_name='+',
through='Favorite',
through_fields=['product']
)
But that produces an error on System Check:
api.Favorite: (fields.E336) The model is used as an intermediate model
by 'api.ProductSearch.product_favorite_set', but it
does not have a foreign key to 'ProductSearch' or 'Favorite'.
api.ProductSearch.product_favorite_set: (fields.E339) 'Favorite.product'
is not a foreign key to 'ProductSearch'.
I imagine I could make the product_favorite_set a Python #property, and then do a custom query in it like:
class ProductSearch(BaseModel):
# ....
#property
def product_favorite_set(self):
return Favorite.objects.filter(product=self.product)
But I would like to know if I can do this using "pure" Django tools (only if out of curiosity)
Any help would be greatly appreciated. Thank you in advance.

django many to many field filter using created time

I have a model named ClassRoom,
class ClassRoom(model.Model):
class_name = models.CharField(max_lenth=100)
students = models.ManyToManyField(User)
and view.py like this.
def addstudents(request):
class_room = ClassRoom.objects.get(id=1)
class_name.students.add(request.user)
I added the students to ClassRoom like this.
I wanted to list all the students in class, who joined today.
How can I filter this students by their joining time?.
When we using django ManyToManyField, then django create an extra table in database. In that table contains created time. Can I filter using this field?
You can add extra fields to a M2M relationship table by using a custom table (docs here).
class ClassRoom(models.Model):
class_name = models.CharField(max_length=100)
students = models.ManyToManyField(User, through='ClassMate')
class ClassMate(models.Model):
class_room = models.ForeignKey(ClassRoom, on_delete=models.CASCADE)
user = model.ForeignKey(User, on_delete=models.CASCADE)
date_joined = models.DateField(auto_now_add=True)
Then you can do this:
class_room = ClassRoom.objects.get(...)
class_room.students.filter(date_joined=datetime.today())
Keep in mind that (as docs says) now you have to instance ClassMate objects to add a relationship:
class_room = ClassRoom.objects.get(...)
user = request.user
class_mate = ClassMate(class_room=class_room, user=user)
class_mate.save()

Categories