I have three models Order, OrderEntries and Product
class Order(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
order_entries = models.ManyToManyField(OrderEntries, blank=True)
...
class OrderEntries(models.Model):
product = models.ForeignKey(Product, on_delete=models.CASCADE)
quantity = models.IntegerField()
class Product(models.Model):
title = models.CharField(max_length=1000)
slug = models.SlugField(blank=True, null=True, unique=True)
Now, I have to get history of purchased products. As I can get all previous orders placed by a user like this
queryset = Order.objects.filter(user=self.request.user, client=self.request.client)
But how I can get list of products from all those orders?
If you specify a related_name on the ForeignKey field as follows:
product = models.ForeignKey(Product, on_delete=models.CASCADE, related_name='products')
You could then access the products in your template, for example:
{% for order in orders %}
{% for order_entry in order.order_entries %}
{% for product in order_entry.products.all %}
{{ product }}
Please note: it isn't necessary to set related_name. If you don't set it, you can use BLA_set where BLA is the name of the field e.g.:
{% for product in order_entry.product_set.all %}
maybe this help :
product=[]
for e in queryset:
for ord in e['order_entries']:
for pr in ord['product'] :
product.append(pr)
Related
Hi I have two tables which are Employee(eid,eName,contact_num,e-mail,adress,salary) and Nurse(nurse_id,e_id) and the "e_id" column of Nurse model has foreign key on 'eid' of Employee model.I know how to filter by specific id, however all of them as list so that, I want to return all nurses from Employee table.You can find my models below. I am new to Django that is why any help or hint is appreciated. Thanks in advance.
class Employee(models.Model):
eid = models.IntegerField(primary_key=True)
ename = models.CharField(db_column='eName', max_length=25) # Field name made lowercase.
contact_num = models.DecimalField(max_digits=12, decimal_places=0)
e_mail = models.CharField(max_length=30)
adress = models.CharField(max_length=250, blank=True, null=True)
salary = models.IntegerField()
class Nurse(models.Model):
nurse_id = models.IntegerField(primary_key=True)
e = models.ForeignKey(Employee, models.DO_NOTHING)
from an instance of employee class you can get the nurses as follows
employee_1 = Employee.objects.first()
nurses = employee_1.nurse_set.all()
can call in templates of list view of employee by
{% for obj in object_list %}
{{ obj.ename }}
{% for nurse in obj.nurse_set.all %}
{{ nurse.eid }}
{% endfor %}{% endfor %}
I'm stuck trying to figure out how to filter my template values with the detail view PK. I have a detail view for my employee. I wish to display my employee's subjects, where I then wish to filter the subjects with the evaluations that have been made for the subject.
I've gotten so far that I can show my subject names, and show all the evaluations for each subject. However, I don't want to show ALL of them I only want to show the ones that exist for the current employee (detailView PK). As you can see in my template, I'm using _set to make the relation, but I have no clue on how to filter the PK into that equation.
Example, what I want:
Subject 1:
Evaluationname - employee Johnny
Evaluationname - employee Johnny
Example, what I currently have:
Subject 1:
Evaluationname - employee Johnny
Evaluationname - employee Chris
I don't want Chris's evaluation, I only wish to filter the primary key, so in this case Johnny's evaluations.
Template
{% for subject in subject_list %}
{{ subject.subejctname }}
{% for evaluation in subject.evaluation_set.all %}
<div>
<p>{{ evaluering.ma }} | {{ evaluering.ma.firstname }} | {{ evaluering.ma.lastname }}</p>
</div>
{% empty %}
<p>No evaluations founds.</p>
{% endfor %}
{% endfor %}
View
class EmployeeDetailView(DetailView):
template_name = 'evalsys/employee/alle_employees_eval.html'
model = Employee
# Uses employee PK to make a detail view
def view_employee_with_pk(self, pk=None):
if pk:
employee = Employee.objects.get(pk=pk)
else:
employee = self.employee
args = {'employee': employee, }
return render(self, 'evalsys/employee/alle_employees_eval.html', args)
def get_context_data(self, **kwargs):
context = super(EmployeeDetailViewDetailView, self).get_context_data(**kwargs)
context['subject_list'] = Subject.objects.all()
return context
Subject Model
class Subject(models.Model):
id = models.AutoField(primary_key=True)
subjectname = models.CharField(max_length=255, help_text="Indtast navnet på faget.")
slug = models.SlugField(max_length=200, unique=True)
Evaluation model
class Evaluation(models.Model):
id = models.AutoField(primary_key=True)
employee_num = models.ForeignKey('Employee', on_delete=models.CASCADE, null=True)
subjectname = models.ForeignKey('Subject', on_delete=models.CASCADE, null=True)
Employee model
class Employee(models.Model):
id = models.AutoField(primary_key=True)
slug = models.SlugField(max_length=200)
employee_num = models.IntegerField(help_text="Indtast medarbejderens MA-nummer. (F.eks 123456)")
firstname = models.CharField(max_length=30, help_text="Indtast medarbejderens fornavn.")
lastname = models.CharField(max_length=30, help_text="Indtast medarbejderens efternavn.")
subjectname = models.ForeignKey('Subject', on_delete=models.CASCADE, null=True)
Reverse relationships (subject.evaluation_set) can be prefetched, this is a technique for reducing the number of database queries made when you access the reverse relationship for many objects in a queryset. When using the following queryset, when you access subject.evaluation_set.all it will not perform an additional DB access as the result has already been cached on each instance
Subject.objects.all().prefetch_related('evaluation_set')
This cached result can be modified by using Prefetch objects. Using these you can limit the contents of subject.evaluation_set.all to only contain the result that you want
Subject.objects.all().prefetch_related(
Prefetch(
'evaluation_set',
queryset=Evaluation.objects.filter(employee=self.employee)
)
)
Your model structure is confusing. Are you able to detail the relationship between employee, subject and evaluation?? You have mentioned you wish to display an employee's subjects, but via your model structure, an employee can have only one subject, as employee is related to the subject by a foreign key.
Below I have suggested some changes to your model names and your model structure so it might make more sense to retrieve your evaluations in the template. Feel free to ask questions about your model design as that is crucial to design your views, templates, etc.
Also please refer here for model naming conventions
Django Foreign Key Reference
Django Model Coding Style (PEP8)
Subject Model
class Subject(models.Model):
id = models.AutoField(primary_key=True)
subject_name = models.CharField(max_length=255, help_text="Indtast navnet på
faget.")
slug = models.SlugField(max_length=200, unique=True)
Employee Model
class Employee(models.Model):
id = models.AutoField(primary_key=True)
slug = models.SlugField(max_length=200)
employee_num = models.IntegerField(help_text="Indtast medarbejderens MA-nummer. (F.eks 123456)")
first_name = models.CharField(max_length=30, help_text="Indtast medarbejderens fornavn.")
last_name = models.CharField(max_length=30, help_text="Indtast medarbejderens efternavn.")
subjects = models.ManyToManyField(Subject, related_name='employee', through='Evaluation')
Evaluation Model
class Evaluation(models.Model):
name = models.CharField(blank=True,max_length=50)
employee = models.ForeignKey('Employee', on_delete=models.CASCADE)
subject = models.ForeignKey('Subject', on_delete=models.CASCADE)
So the assumption, is an employee can have different subjects and the mapping is defined via a through model using many-to-many.
Your DetaiView can then just be
class EmployeeDetailView(DetailView):
template_name = 'evalsys/employee/alle_employees_eval.html'
model = Employee
def get_context_data(self, **kwargs):
context = super(EmployeeDetailViewDetailView,
self).get_context_data(**kwargs)
context['evaluations'] = Evaluation.objects.filter(employee=self.object)
return context
Template
{% for evaluation in evaluations %}
{{ evaluation.subject.subject_name }}
<p>{{ evaluation.name }} | {{ evaluation.employee.first_name }} |
{{evaluation.employee.last_name }}</p>
{% empty %}
<p>No evaluations founds.</p>
{% endfor %}
I'm using Django 2.2 and PostgreSQL. I want to display the product information that the user has added to the detail page. I see the information in the 'StoreOtherInfo' model, but I don't see the information in the 'Product' model. How can I do that?
store/models.py
class StoreOtherInfo(models.Model):
user = models.OneToOneField(User,on_delete=models.CASCADE,blank=True, null=True)
phone = models.CharField(max_length=11)
fax = models.CharField(max_length=11)
province = models.CharField(max_length=11)
district = models.CharField(max_length=11)
neighborhood = models.CharField(max_length=11)
def __str__(self):
return self.user.username
products/models.py
class Product(models.Model):
seller = models.ForeignKey(User, on_delete = models.CASCADE)
product_name = models.CharField(max_length = 50)
description = RichTextField()
added_date = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.seller
store/views.py
from store.models import StoreOtherInfo
from products.models import Product
def neighbor_detail(request,username):
neighbor_detail = get_object_or_404(User,username = username)
neighbor_list = StoreOtherInfo.objects.all()
product_list = Product.objects.all()
return render(request, 'store/neighbor_detail.html', {'neighbor_detail':neighbor_detail, 'neighbor_list':neighbor_list, 'product_list':product_list})
templates/neighbor_detail.html
<strong><p>{{neighbor_detail.first_name}} {{neighbor_detail.last_name}}</p></strong>
<p>{{neighbor_detail.username}}</p>
<p>{{neighbor_detail.email}}</p>
<p>{{neighbor_detail.storeotherinfo.phone}}</p>
<p>{{neighbor_detail.storeotherinfo.fax}}</p>
<p>{{neighbor_detail.storeotherinfo.province}}</p>
<p>{{neighbor_detail.storeotherinfo.district}}</p>
<p>{{neighbor_detail.storeotherinfo.neighborhood}}</p>
<p>{{neighbor_detail.product.product_name}}</p>
<p>{{neighbor_detail.product.description}}</p>
<p>{{neighbor_detail.product.added_date}}</p>
according to your Product model:
seller = models.ForeignKey(User, on_delete = models.CASCADE)
the relation between User model and Product model is one-to-many. This means every User(in this case seller) can have multiple Products.
So when you try to access the Product objects of a User object as you did in you template: <p>{{neighbor_detail.product.product_name}}</p> you end up giving an attribution error because neighbor_detail.product is not a single object of Product class it's a collection.
replace your template code with this and i hope you realize whats happening.
<strong><p>{{neighbor_detail.first_name}} {{neighbor_detail.last_name}}</p></strong>
<p>{{neighbor_detail.username}}</p>
<p>{{neighbor_detail.email}}</p>
<p>{{neighbor_detail.storeotherinfo.phone}}</p>
<p>{{neighbor_detail.storeotherinfo.fax}}</p>
<p>{{neighbor_detail.storeotherinfo.province}}</p>
<p>{{neighbor_detail.storeotherinfo.district}}</p>
<p>{{neighbor_detail.storeotherinfo.neighborhood}}</p>
{% for product in neighbor_detail.product_set.all %}
{{product.product_name}}<br/>
{{product.description}}<br/>
{{product.added_date}}<br/>
{% endfor %}
note that product_set is the default name that django associate with products related to each user.
A User can have multiple Products, so you can't do neighbor_detail.product because product isn't defined on a User. You need to loop through the list of products with {% for product in neighbor_detail.product_set.all %} and then you can display the properties of each product.
Read [this] for more information about one-to-many relationships.
I have this two models:
class MenuGroup(models.Model):
name = models.CharField(max_length=30)
class MenuProduct(models.Model):
name = models.CharField(max_length=30)
ingredients = models.CharField(max_length=250)
price = models.FloatField(null=True, blank=True, default=0.0)
group = models.ForeignKey(MenuGroup, on_delete=models.CASCADE)
I want to get all the records of MenuGroup with all the MenuProduct records related.
Template side i need to have structure like this:
{% for group in menugroups %}
...
{% product in group.menuproducts %}
How to express this into a Django CBV view?
You don't need to do anything, Django gives you that functionality already. The only thing to change is that the default accessor is <modelname>_set, and it's a Manager; so:
{% for product in group.menuproduct_set.all %}
I'm trying to write internet-shop, and I have a model Order:
class Order(models.Model):
state_choices = ('ACTIVE', 'COMPLETED', 'FROZEN')
order_date = models.DateTimeField(auto_now_add=True)
delivery_time = models.CharField(max_length=100)
address_city = models.CharField(max_length=40)
address_street = models.CharField(max_length=40)
address_building = models.CharField(max_length=40)
state = models.CharField(max_length=200, default='ACTIVE')
products = models.ForeignKey(OrderProduct)
client = models.ForeignKey(CustomUser)
And OrderProduct:
class OrderProduct(models.Model):
product = models.ForeignKey(Product)
product_ammount = models.IntegerField()
As you can see, user can add to order different products and different ammount of each product. So, with current models, I can add to order only one type of product. Then I rewrite it in the next way:
class Order(models.Model):
state_choices = ('ACTIVE', 'COMPLETED', 'FROZEN')
order_date = models.DateTimeField(auto_now_add=True)
delivery_time = models.CharField(max_length=100)
address_city = models.CharField(max_length=40)
address_street = models.CharField(max_length=40)
address_building = models.CharField(max_length=40)
state = models.CharField(max_length=200, default='ACTIVE')
client = models.ForeignKey(CustomUser)
class OrderProduct(models.Model):
product = models.ForeignKey(Product)
order = models.ForeignKey(Order)
product_ammount = models.IntegerField()
And in a view, when I need to get a user's orders, I just do next: Order.objects.get(client=request.user).orderproduct_set
But I think that it's not correct. How to rebuild these models to gain the desired result?
In my opinion the second approach is perfectly fine.
One small error in the question is that the query uses get() instead of filter(). This will lead to an exception once one user has more than one order.
So, instead of the get() it would be:
orders = Order.objects.filter(client=request.user)
for order in orders:
print order.orderproduct_set.all()
To use this in a template (question from the comments) it is enough to pass the orders:
views.py
class MyView(View):
def get(self, request):
ctx = {
'orders': Order.objects.filter(client=request.user)
}
return render(request, 'my/template.html', ctx)
my/template.html
{% for order in orders %}
{% for item in order.orderproduct_set.all %}
{{ item.product_amount }}x {{ item.product }}<br/>
{% endfor %}
{% endfor %}