How to reference multiple foreignkeys from a model - python

I would like to reference 2 separate fields from a model into another model.
From the code below, i have:
First model with the following fields - name, owner and email
In the second model, i would like to use the data from name and owner above in the second model but renamed them org (name form group) and org_owner (owner from group)
i have tried the below code using related_name. But i get thesame value in both fields. That is a get the name field from group in both the org and org_owner field. Not what i want.
class group(models.Model):
name = models.CharField(max_length=100, unique=True, blank=False)
owner = models.CharField(max_length=100, blank=False)
email = models.EmailField(max_length=100, blank=False)
class account(models.Model):
org = models.ForeignKey('group', on_delete=models.SET_NULL, null=True, related_name='org')
org_owner = models.ForeignKey('group', on_delete=models.SET_NULL, null=True, related_name='org_owner')
account = models.CharField(max_length=100, blank=False, unique=True)
Expected result should be:
account.org = group.name
account.org_owner = group.owner

There is no need to have group owner in the account once you have added the org as a foreign key.
You should remove the line below from account:
org_owner = models.ForeignKey('group', on_delete=models.SET_NULL, null=True, related_name='org_owner')
Group name can be accessed as:
account.org.owner
And group name should be accessible as
account.org.name

Seems like what you're trying to do is join account with group using a condition on two fields. I would suggest you search for how to use a foreign key of two fields rather than using two foreign keys. The other popular way of solving this is to give the group model a generated primary key and have a group_id in the account for the relation. You could then remove (org, org_owner) from account if it serves no other purpose.

Related

Django Filter using Q Objects on two Models

I am working a Django Application where I want to search two Models Profile (surname or othernames fields) and Account (account_number field) using Q objects.
From what I did, it is searching only one Model (Account) and any attempt to search any value from the other Model (Profile) triggers an error which says: Field 'id' expected a number but got 'Ahile Terdoo'.
See my Model Code:
class Profile(models.Model):
customer = models.OneToOneField(User, on_delete=models.CASCADE, null = True)
surname = models.CharField(max_length=20, null=True)
othernames = models.CharField(max_length=40, null=True)
gender = models.CharField(max_length=6, choices=GENDER, blank=True, null=True)
address = models.CharField(max_length=200, null=True)
phone = models.CharField(max_length=11, null=True)
image = models.ImageField(default='avatar.jpg', blank=False, null=False, upload_to ='profile_images',
)
def __str__(self):
return f'{self.customer.username}-Profile'
class Account(models.Model):
customer = models.OneToOneField(User, on_delete=models.CASCADE, null=True)
account_number = models.CharField(max_length=10, null=True)
date = models.DateTimeField(auto_now_add=True, null=True)
def __str__(self):
return f' {self.customer} - Account No: {self.account_number}'
Here is my form:
class SearchCustomerForm(forms.Form):
value = forms.CharField(label = 'Enter Name or Acct. Number', max_length=30)
Here is my views
def create_account(request):
if searchForm.is_valid():
#Value of search form
value = searchForm.cleaned_data['value']
#Filter Customer by Surname, Othernames , Account Number using Q Objects
user_filter = Q(customer__profile__exact = value) | Q(account_number__exact = value)
#Apply the Customer Object Filter
list_customers = Account.objects.filter(user_filter)
else:
list_customers = Account.objects.order_by('-date')[:8]
Someone should help on how best to search using Q objects on two Models.
Not sure I properly get your question but if you want to filter Account based on profile surname you need to specify that in your Q object. write your Q object like below
user_filter = Q(customer__profile__surname__exact = value) | Q(account_number__exact = value)
User model's primary key is used as a key in both Account and Profile models.
customer__profile filter on Account model follows the relationship from Account to User to Profile models using this key. This is why it is expecting for customer field to contain a numeric id. __str__ is executed on the python side, and filters are used on the db side, so it does not replace the numeric id with the username.
By convention, a field that defines a relationship to another model should be named after the model in lowercase. So customer should be user, but it is OK to use a different name if you prefer that.
Try filtering by customer__username instead of customer__profile.
To filter by surname, try customer__profile__surname. It should follow the relationship from Account to User using customer field you defined. Then backward from User to Profile by using the lowercase model name (profile).

Unique field value Django model

So, i have two models: RetailStore and Product. Product contains a ForeignKey to RetailStore and a field named sku. Basically what i need is to make sure that the sku field is unique into a store, but not between all stores, e.g:
Store1: Product(sku="sku1"), Product(sku="sku2"), Product(sku="sku3"), Product(sku="sku1") <- can't have this last one because it already exists.
Store2: Product(sku="sku1"), Product(sku="sku2"), Product(sku="sku3") <- This is ok
Store3: [...] <- Same goes for others Store.
My Models
class RetailStore(StandardModelMixin):
cnpj = models.CharField(
blank=False, null=False, unique=True, max_length=200, validators=[validate_cnpj], verbose_name="CNPJ"
)
[other fields...]
class Product(StandardModelMixin, SoftDeletionModel):
sku = models.CharField(blank=False, null=False, max_length=200, verbose_name="SKU")
[other fields...]
retail_store = models.ForeignKey(
RetailStore,
on_delete=models.CASCADE,
blank=True,
null=True,
related_name="products",
verbose_name="Retail Store",
)
You can use UniqueConstraint so you can have the same SKUs in different stores, but not in one.
class Product(StandardModelMixin, SoftDeletionModel):
...
class Meta:
constraints = [models.UniqueConstraint(
fields=['sku', 'retail_store'],
name='unique_sku_in_store'
)]
You'll need to apply validate_unique to this.
Django offers unique_together, but it grants uniqueness to a single model and not between models.
Docs: https://docs.djangoproject.com/en/dev/ref/models/instances/#django.db.models.Model.validate_unique

How to set a Foreign Key based on multiple column with django-import-export?

There's a model defining which combination of department/position needs what types of training. Another model shows employees with all related information. All the data comes from xlsx file via django-import-export. The problem is that I can't figure out how to set a foreign key in employees model based on the unique combination of department and position rows, so each employee gets the training field value accordingly. I've tried this solution but it didn't work (or maybe I did something wrong): https://github.com/django-import-export/django-import-export/issues/375
I'm new to programming and this is my first project. Hope some of you can help.
Here is my model defining training for each combination of department/position:
class TrainingMatrix(models.Model):
department = models.ForeignKey(Department, on_delete=models.CASCADE,blank=False, null=True)
position = models.ForeignKey(Position, on_delete=models.CASCADE,blank=False, null=True)
training = models.ManyToManyField(Training)
Here is the Employee model:
class Employee(models.Model):
badge = models.CharField(max_length=15, primary_key=True, unique=True)
name = models.CharField(max_length=200)
department = models.ForeignKey(TrainingMatrix, on_delete=models.CASCADE, null=True, blank=True,related_name='department_name')
position = models.ForeignKey(TrainingMatrix, on_delete=models.CASCADE, null=True, blank=True,related_name='position_title')
training = models.ForeignKey(TrainingMatrix, on_delete=models.CASCADE, null=True)
And the xlsx file's column titles I import:
badge, name, position, department

How to apply filter on Many to many field without using for loop

I Model is like
class Company(models.Model):
name = models.CharField(max_length=400, blank=True, null=True)
class Intership(models.Model):
company = models.ForeignKey(Company)
location = models.CharField(max_length=400, blank=True, null=True)
class Student(models.Model):
name = models.CharField(max_length=400, blank=True, null=True)
intership = models.ManyToManyField(Intership,null= True, blank=True)
I am looking forward to get all the student who done internship in a company with name "xyz".
i have the code
company_name = "xyz"
stds
for student in students:
interships = student.intership.all()
for intership in interships:
if intership.company.name == company_name:
stds.append(student)
Is it possible to get it all this on a single query??
You can just filter on the Students itself:
Student.objects.filter(intership__company__name='xyz')
You might want to use .distinct() here, since otherwise a Student that multiple internships in the same company will be listed multiple times:
Student.objects.filter(intership__company__name='xyz').distinct()
Note: It is internship, not intership.
Mymodel.objects.filter(username='abcd') will give list of match record
Mymodel.objects.get(pk='abcd') will return single record with matching on primary key value

Filter by presence in a model's set

I have a Customer model that has many Locations, i.e., there is a location_set attribute on the model that returns a list of locations. Each Location also has many customers, i.e., a customer_set attribute.
I have one customer instance with all of its corresponding attributes. What I want to do is return all other customers who are present in at least of the locations in the customer's location_set. Is there a clean way to do this without having to manually manipulate the queryset and make a ton of calls to the DB?
class Customer(AbstractUser):
current_location = models.ForeignKey('device.Location',
null=True, blank=True, related_name='customers_present')
default_location = models.ForeignKey('device.Location',
null=True, blank=True, related_name='default_customers')
class Location(models.Model):
name = models.CharField(max_length=50, help_text="The name of the location")
customers = models.ManyToManyField(settings.AUTH_USER_MODEL,
through='customer.Membership')
class Membership(models.Model):
customer = models.ForeignKey(Customer)
location = models.ForeignKey('device.Location')
date_joined = models.DateTimeField(auto_now_add=True)
Without your model definitions it is very difficult to provide an exact answer to your question, something like the below could work:
Customer.objects.filter(location__in=your_customer_instance.location_set.all()).exclude(pk=your_customer_instance.pk)

Categories

Resources