Django: Defining 'present_company' from 'company_name' ManytoManyField - python

I have 2 models, Company and Employee, and defined company history as a ManytoManyField. I am trying to save the present company name of the employee which I get from the company name ManytoManyField. What should be the method to save it?
This is what I tried:
I tried to override the save method in Models.
models.py
from django.db import models
class Company(models.Model):
name = models.CharField(max_length=100)
def __str__(self) -> str:
return self.name
class Employee(models.Model):
name = models.CharField(max_length=100)
company_name = models.ManyToManyField(Company, blank=True)
present_company = models.CharField(max_length=100, blank=True)
def save(self):
super(Employee, self).save()
last_index = self.company_name.count()-1
self.present_company=str(Company.objects.filter(employee__name=self.name)[last_index])
super(Employee, self).save()
def __str__(self) -> str:
return self.name
I face two problems with this method:
I add/edit the models from the admin site, when I try to save the models and print the names of the company, it prints out the previous edit and not the latest one.
The order of the companies is not according to the order in which I save the models.
So, what could be the changes in this method, or, some other method to do this job.

As #Sahil mentions in comments that he wants the ordering based on employees joined the company.
when you use a Many-to-Many field Django in the backend created a separate table for mapping(through table). you can see this table in DB. now you want the details of Employee joined you can create a table(this table is just same as Many-to-Many field but with extra fields such as joined_in etc.) with details such as follow:
class EmployeeCompnyMap(models.Model):
employee = models.ForeignKey(
Employee, on_delete=models.CASCADE, related_name='employee_company_map')
company = models.ForeignKey(
Company, on_delete=models.CASCADE, related_name='company_employee_map')
is_active = models.BooleanField(default=True)
joined_on = models.DateField(auto_now_add=True)
resigned_on = models.DateField(blank=True, null=True)
Now if you want second_latest you can do the following in your save model:
last_company = self.employee_company_map.all().order_by('-resigned_on')[1]

Related

Dynamic django choice field

I have 4 models: Products (the list of products: freezers, microwaves, tvs and pcs), ProductType (entertainment and home appliances), Credit (a credit is registered on each purchase) and PurchaseReason (the reason why the customer has bought the product).
The PurchaseReason depend on the productType, so the purchaseReason has a foreignKey field productType.
In addition, each credit has a product as foreignKey and a purchaseReason as foreignKey.
Also, I have the ProductReason field as a choice field in the credit model, and I want the options to be set dynamically based on the product field of the credit model.
I'm creating an API so I think this cant be handle with modelForms, but i'm not sure. The hard work would be with the serializers (DRF) and with the django-admin (specially this one because in my product the django admin plays an important role)
What would be the best approach to manage my models in Django?
Here are my models. In credit I'm not sure how to implemente the purchase reason:
class Credit(models.Model):
client = models.ForeignKey('clients.Client', on_delete=models.SET_NULL)
name = models.CharField(max_length=30, null=False, blank=True)
product = models.ForeignKey('product',on_delete=models.SET_NULL)
reason_purchase = models.ChoiceField(????)
class PurchaseReason(models.Model):
product_type = models.ForeignKey(product_type, on_delete=models.CASCADE)
reason = models.CharField(max_length=30, null=False, blank=True)
class ProductType(models.Model):
name = models.CharField(max_length=30, null=False, blank=False)
class Product(models.Model):
model = models.CharField(max_length=30, default=None, null=True)
product_type = models.ForeignKey(product_type, on_delete=models.CASCADE)
When we use the foreign key, we need to mention the model name of that particular model so that we can integrate that particular model in that model as a reference entity. Have a look at this example.
from django.db import models
class Reporter(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
email = models.EmailField()
def __str__(self):
return "%s %s" % (self.first_name, self.last_name)
class Article(models.Model):
headline = models.CharField(max_length=100)
pub_date = models.DateField()
reporter = models.ForeignKey(Reporter, on_delete=models.CASCADE)
def __str__(self):
return self.headline
class Meta:
ordering = ['headline']
you've not mentioned the model name properly. it should be Product in place of 'product' in the Credit class, product field.
use this reference https://docs.djangoproject.com/en/3.2/topics/db/examples/many_to_one/
i think you should be able to use the Foreignkey field properly after this. Although, if you can't, you can share the actual objective. i will help you to write the correct model.
Best wishes :)

Django: Filter records based on one to many relationship

I have following models,
class User(models.Model):
name = models.CharField(max_length=255)
...
class InsuranceProfile(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
...
class ProductExpertiseMaster(models.Model):
class Meta:
db_table = 'product_expertise_master'
name = models.CharField(max_length=255)
main_category = models.CharField(max_length=255)
class UserProductExpertise(models.Model):
user = models.ForeignKey(User, on_delete=models.DO_NOTHING)
product_expertise = models.ForeignKey(ProductExpertiseMaster, on_delete=models.DO_NOTHING)
So what I am trying to do is I want to filter records based on various fields some of the belong to User model & some of them belong to the InsuranceProfile model.I am filter the records based on User & InsuranceProfile model which is working fine. Now i want to add one more filter which will be based on the UserProductExpertise model.I want to get all the InsuranceProfiles with User details who have some matching condition with product expertise entries in UserProductExpertise model. Any help would appreciated.
You can try like this using __isnull:
InsuranceProfile.objects.filter(user__userproductexpertise__isnull=False)
It will return all the users who has an entry in in UserProductExpertise model. For querying, you need to use all lowercase of the model name, (ie userproductexpertise) and add __isnull at the end of it.
I think you should make some changes in your models before proceeding further.
UserProductExpertise model is the bridge table between ProductExpertiseMaster and User, which provides a many-to-many relationship. If you won't add additional fields to UserProductExpertise model, you can drop it and define user relation in ProductExpertiseMaster model.
If you prefer using seperate model for this relationship, on_delete=models.DO_NOTHING is prone to errors, you can change it to models.CASCADE
Here is an example with many-to-many relation:
class User(models.Model):
name = models.CharField(max_length=255)
class InsuranceProfile(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
content = models.CharField(("Content"), max_length=500)
class ProductExpertiseMaster(models.Model):
class Meta:
db_table = 'product_expertise_master'
name = models.CharField(max_length=255)
main_category = models.CharField(max_length=255)
user = models.ManyToManyField(User, verbose_name=("Users"), related_name="expertises")
For filtering your query:
InsuranceProfile.objects.filter(user__expertises__isnull=False)

Is there any way to select a value dynamically for a model's related field in runtime?

I want to achieve a functionality, where I need to select a django model (e.g from a drop down list), and after selecting one, all the objects of that model shows up.
class Thread(models.Model):
sender = models.(???) # This need to be a field that can store a different model on a run time.
receiver = models.(???) # same here.
Is there any way that I can dynamically first select the model and then pick an object of that list. I have seen this functionality in odoo. But is there anything in Django?
Use Inheritance for in your Model and map your foreign key to User, and then pass either a teacher of student object.
You can use the many-to-many filed with multiple available choices of "Student" and "Teacher" from another Model.
class UserRole(models.Model):
STUDENT = 'STUDENT'
TEACHER = 'TEACHER'
ROLE_CHOICES = (
(STUDENT, 'student'),
(TEACHER, 'teacher'),
)
role_name = models.CharField(max_length=255, choices=ROLE_CHOICES)
def __str__(self):
return "{}".format(self.role_name)
class User(AbstractUser):
username = models.CharField(max_length=50, unique=True)
email = models.EmailField(_('email address'))
role = models.ManyToManyField(UserRole)
Class Thread(models.Model):
sender = models.OneToOneField(User, on_delete=models.CASCADE)
receiver = models.OneToOneField(User, on_delete=models.CASCADE)
This way you can only put available roles in sender and receiver fields of Thread.
The solution was possible with ajax too, but there also is another way in django which I was searching for.
class Test(models.Model):
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type', 'object_id')
Have a good one.

Update Table Relationship in Django Admin

I'm trying to create a directory of sites, I'm new in Django. What I need is: one site can have many payment processors and one payment processors (Paypal, Payza, etc) can belong to many sites. I'm trying to create a table relationship to represents this. My models are like this:
# Models.py
class Sites(models.Model):
name = models.CharField(max_length=75)
link = models.CharField(max_length=150)
description = models.TextField(blank=True, null=True)
def __str__(self):
return self.name
class PaymentProcessors(models.Model):
name = models.CharField(max_length=75)
def __str__(self):
return self.name
class Sites_PaymentProcessors(models.Model):
site = models.ManyToMany(Sites)
payment_processor = models.ManyToMany(PaymentProcessors)
First, I'd like to know if my models are right. If not, how can I fix it?
Second, I'm using Django Admin site to create the sites and payment processors, how can I populate automatically my Sites_PaymentProcessors table with the relation between Sites and Payment_Processors when I add a new Site?
I would slightly change the models to accomodate ManyToManyFields like this:
class Sites(models.Model):
name = models.CharField(max_length=75)
link = models.CharField(max_length=150)
description = models.TextField(blank=True, null=True)
def __str__(self):
return self.name
class PaymentProcessors(models.Model):
name = models.CharField(max_length=75)
sites = models.ManyToManyField('Sites', related_name='payment_processors')
def __str__(self):
return self.name
Now, if you want custom fields or store more information along with the relationship, you can make use of the through table
For example, if you want to associate the amount limit or something more custom:
class Sites(models.Model):
name = models.CharField(max_length=75)
link = models.CharField(max_length=150)
description = models.TextField(blank=True, null=True)
def __str__(self):
return self.name
class PaymentProcessors(models.Model):
name = models.CharField(max_length=75)
sites = models.ManyToManyField('Sites', related_name='payment_processors', through='SitePaymentProcessor')
def __str__(self):
return self.name
from django.core.validators import MaxValueValidator
class SitePaymentProcessor(models.Model):
site = models.ForeignKey('Site')
payment_processors = models.ForeignKey('PaymentProcessors')
amount_limit = models.IntegerField(default=1000,
validators=[
MaxValueValidator(100)
])
Now, again this is just an example.
Now, registering the admin classes would enable you to populate data into the models via the admin interface.
To auto-populate a large dataset, I would consider using fixtures rather than populating elements individually.

Query ManyToMany relations without a named through field

I have this setup in my models:
class Author(models.Model):
name = models.CharField(max_length=100)
class Topic(models.Model):
name = models.CharField(max_length=100)
class Article(models.Model):
name = models.CharField(max_length=100)
authors = models.ManyToManyField(Author, null=True, blank=True)
topics = models.ManyToManyField(Topic, null=True, blank=True)
Given an author, I want to know which topics he wrote about:
def author_info(request, pk):
author = get_object_or_404(Author, pk=pk)
topics = ????
If I had specified a through field, I could use that, but now Django makes the through field for me, and since its supposed to be transparent, Id rather not reference the field (unless there is a proper Django construction for that).
Use Lookups that span relationships:
topics = Topic.objects.filter(article__authors=author).distinct()
Note: you have to use distinct here, because the same topic can be selected by different articles.

Categories