Django Templates - Accessing a M2M attribute and value by name - django

I am trying to simply access a the values and names of a Many to Many Model in a template by name. Can someone show me what I'm doing wrong.
I have a model called IP. This model can have several attributes. I want to call the "value" of a a particular attribute.
For example:
I have an IP Block named Foo. Foo has an attribute "bar" with a value of "good luck".
How can I refer to the named attribute in a M2M and it's value from a template??
This works but YUCK!!
{% for attr in ip.attributes.all %}
{% ifequal attr.attribute.name 'vendor' %}
<td>{{ attr.value }}</td>
{% endifequal %}
{% endfor %}
Thanks so much!!
I have a models.py which looks similar to this.
models.py
VALID_IP_TYPES = (("hard", "Hard IP"),
("soft", "Soft IP"),
("verif", "Verification IP"))
class AttributeType(models.Model):
name = models.CharField(max_length = 32, primary_key = True)
ip_type = models.CharField(max_length = 16, choices = \
tuple(list(VALID_IP_TYPES) + [("all", "All IP")]))
def __unicode__(self):
return u'%s' % (self.name)
class Attribute(models.Model):
attribute = models.ForeignKey(AttributeType)
value = models.CharField(max_length = 255)
def __unicode__(self):
return u'%s : %s' % (self.attribute, self.value)
class IP(models.Model):
ip_type = models.CharField(max_length = 16, choices = \
tuple(list(VALID_IP_TYPES),
help_text = "Type of IP")
name = models.CharField(max_length = 32, help_text = "Generic Name")
attributes = models.ManyToManyField(Attribute)
def __unicode__(self):
return u'%s' % (self.name)
The relevant views.py
def search(request):
context = RequestContext(request)
if not request.POST:
form = { 'form' : IPSearch() }
return render_to_response('ip_catalog/search.html', form,
context_instance = context)
else:
form = IPSearch(request.POST)
if form.is_valid():
response_dict = {}
cd = form.cleaned_data
ips = ips.filter(**cd)
response_dict.update({'ips':ips})
response_dict.update({'success': True })
return render_to_response('ip_catalog/results.html', response_dict,
context_instance = context)
And finally the template snippet I am struggling with..
{% for ip in ips %}
<tr>
<td>{{ ip.name }}</td>
<td>{{ ip.release_id }}</td>
<td>{{ ip.release_date }}</td>
<!-- THIS WORKS BUT THERE MUST BE A BETTER WAY! -->
{% for attr in ip.attributes.all %}
{% ifequal attr.attribute.name 'vendor' %}
<td>{{ attr.value }}</td>
{% endifequal %}
{% endfor %}
<!-- THIS DOESN'T WORK! -->
<td>{{ ip.attributes.node.value }}</td>
<!-- OR THIS! -->
<td>{{ ip.attribute_id.foundry }}</td>
<!-- OR THIS.. ! -->
<td>{{ ip.attribute.process }}</td>
</tr>
{% endfor %}

Accessing a ManyToManyField in a model results in a manager, which you can use .filter() et alia on. Since most of these require at least one argument, you can't call them in a template. Create a template tag instead.

You can't do this well in templates. This is restricted by the design philosophy of Django.
The only way to do this is writing a custom template tag or helper function in model like get_vendor.
Checkout How do I perform query filtering in django templates

Related

For loop in template django with prefetch_related

I got an issue when trying to access values from other models by using prefetch_related
My model:
class testimport(models.Model):
id=models.AutoField(primary_key=True)
so_hd=models.CharField( max_length=50, unique=True)
ten_kh=models.CharField( max_length=500)
tien_dong=models.IntegerField(blank=True, null=True)
created_at=models.DateTimeField(auto_now_add=True)
objects=models.Manager()
def get_absolute_url(self):
return "/chi_tiet_hop_dong/%s/" % self.so_hd
class report(models.Model):
id=models.AutoField(primary_key=True)
so_hd=models.ForeignKey(testimport, on_delete=models.DO_NOTHING, to_field="so_hd")
nhan_vien=models.ForeignKey(Callers, on_delete=models.DO_NOTHING, null=True, blank= True, to_field="admin_id")
noi_dung=models.TextField()
My views:
....
get_contract_detail=testimport.objects.filter(so_hd__in=get_user).order_by("id").prefetch_related().values()
contract=get_contract_detail.filter(so_hd=so_hd).all()
return render(request, "caller_template/contract_detail.html", {"contract":contract,"the_next":the_next,"the_prev":the_prev, "so_hd":so_hd,"form":form,"form1":form1})
If I try to print out the content by values, it is ok:
print(get_contract_detail.filter(so_hd=so_hd).values("so_hd","report__noi_dung"))
In my template:
{% for report in contract %}
{% for content in report.so_hd.all%}
<tr>
<td>{{ forloop.counter }}</td>
<td>{{content.noi_dung}}</td>
</tr>
{% endfor %}
{% endfor %}
There is no content in cells. How can I show the content
Please help
The reason this does not work is because of the use of .values(…) [Django-doc]. Furthermore you did not specify a related_name=… parameter [Django-doc], so that means that you access the reports with .report_set.all():
contract = testimport.objects.filter(
so_hd__in=get_user, so_hd=so_hd
).order_by('id').prefetch_related() # no .values()
context = {
'contract': contract,
'the_next': the_next,
'the_prev': the_prev,
'so_hd': so_hd,
'form': form,
'form1':form1
}
return render(request, 'caller_template/contract_detail.html', context)
and in the template render with .report_set.all:
{% for report in contract %}
{% for content in report.report_set.all %}
<tr>
<td>{{ forloop.counter }}</td>
<td>{{ content.noi_dung }}</td>
</tr>
{% endfor %}
{% endfor %}

Django, How to display 2 models on a Listview

I am working with my first Django project
**model.py**
class product(models.Model):
product_code = models.CharField(max_length=15, unique=True)
product_name = models.CharField(max_length=100)
class stock_product(models.Model):
product_code = models.CharField(max_length=15)
branch_code = models.CharField(max_length=5)
quantity = models.IntegerField(default=0)
price = models.DecimalField(default=0)
**views.py**
class productList(ListView):
model = product
template_name = 'product/product_list.html'
def get_queryset(self):
queryset = super(productList, self).get_queryset()
self.filterset = productFilter(self.request.GET, queryset=queryset)
return self.filterset.qs
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['filter'] = self.filterset
return context
**product_list.html**
{% for alist in product_list %}
<tr>
<td>{{ alist.product_code }}</td>
<td>{{ alist.product_name }}</td>
<td>{{ alist.price }}</td>
<td>{{ alist.quantity }}</td>
</tr>
{% endfor %}
Sample Data in tables
**product**
['11111','paper'
'22222','Wood']
**stock_product**
['11111','BR1',150, 10
'11111','BR2',120, 10
'11111','BR3',100, 15
'22222','BR1',50, 200
'22222','BR2',70, 200
'22222','BR3',40, 250]
I want to get price and quantity from stock_product model, we can change branch_code by user
how can we do Plese help.
Thanks, But I want display only user branch (if user branch 'BR1' display only 'BR1')
**views.py**
class productList(ListView):
model = product
template_name = 'product/product_list.html'
def get_queryset(self):
queryset = super(productList, self).get_queryset()
self.filterset = productFilter(self.request.GET, queryset=queryset)
return self.filterset.qs
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
stock = stock_product.objects.all(). # this line added
context['filter'] = self.filterset
context['stock'] = stock # this line added
return context
Now having this you can access the stock from your template:
**product_list.html**
{% for alist in product_list %}
<tr>
<td>{{ alist.product_code }}</td>
<td>{{ alist.product_name }}</td>
<td>{{ alist.price }}</td>
<td>{{ alist.quantity }}</td>
</tr>
{% endfor %}
{% for s in stock %}
<tr>
<td>{{ s.product_code }}</td>
<td>{{ s.product_branch }}</td>
</tr>
{% endfor %}
BUT I have to just do not recommend you do this. Why? well, I suppose you want to make the match of the product_code. Except of that you should use ForeignKey on the models and so you will have a much simple code and logic:
Model:
class stock_product(models.Model):
product = models.ForeignKey(Product, on_delete=models.CASCADE) # this
branch_code = models.CharField(max_length=5)
quantity = models.IntegerField(default=0)
price = models.DecimalField(default=0)
And so now without modifying your view you could do this on the template to access the data:
template:
{% for alist in product_list %}
<tr>
<td>{{ alist.product_code }}</td>
<td>{{ alist.product_name }}</td>
<td>{{ alist.stock_product.branch_code }}</td>
<td>{{ alist.stock_product.quantity }}</td>
<td>{{ alist.stock_product.price }}</td>
</tr>
{% endfor %}
how about change the model with using foreign keys.
and use the django_tables2.
# **model.py**
from django.db import models
class product(models.Model):
product_code = models.CharField(max_length=15, unique=True)
product_name = models.CharField(max_length=100)
class stock_product(models.Model):
# product_code = models.CharField(max_length=15)
product = models.ForeignKey(product, on_delete=models.CASCADE)
branch_code = models.CharField(max_length=5)
quantity = models.IntegerField(default=0)
price = models.DecimalField(default=0)
this is table code for django_tables2.
class DetailedDataTable(tables.Table):
product_code = tables.Column(verbose_name='product_code', accessor='product_id')
product_name = tables.Column(verbose_name='product_name', accessor='product_id')
class Meta:
model = stock_product
template_name = "django_tables2/bootstrap.html"
fields = ('product_code', 'product_name', 'branch_code', 'quantity', 'price')
def render_product_code(self,value, record):
return product.objects.get(id=value).product_code
def render_product_name(self,value, record):
return product.objects.get(id=value).product_name
and this is view
def view(request):
template_name = 'template.html'
query_set = stock_product.objects.all()
table = DetailedDataTable(qs)
context={
'table':table,
}
return render(request, template_name, context)
and this is for template page uses.
{# tutorial/templates/tutorial/people.html #}
{% load render_table from django_tables2 %}
<!doctype html>
<html>
<head>
<title>List</title>
</head>
<body>
{% render_table table %}
</body>
</html>
:)

Display number of views for a specific post for specific user in a table using django

i want to display number of views in a table for a specific post. I already have the data stored in db. it seems that print statement print('count', context['count_view']) is working inside get_context_data method but it is not working as expected in the template. Don't worry about the data inside the image, its actually dummy data. Anyone helpenter image description here
models.py
class ObjectViewed(models.Model):
user = models.ForeignKey(User, blank=True, null=True, on_delete=models.CASCADE)
ip_address = models.CharField(max_length=220, blank=True, null=True)
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE) # User, Blog, or any other models
object_id = models.PositiveIntegerField() # User id, Blog id, or any other models id
content_object = GenericForeignKey('content_type', 'object_id')
timestamp = models.DateTimeField(auto_now_add=True)
views.py
class PostListView(ListView):
model = Post
template_name = 'edmin/post/postList.html'
context_object_name = 'posts'
ordering_by = ['-created']
def get_queryset(self):
post=Post.objects.filter(author=self.request.user)
return post
def get_context_data(self, *args, **kwargs):
context = super().get_context_data(*args, **kwargs)
post=Post.objects.filter(author=self.request.user)
c_type = ContentType.objects.get_for_model(Post)
for p in post:
context['count_view'] = ObjectViewed.objects.filter(content_type=c_type, object_id=p.id).count()
print('count',context['count_view'])
return context
postList.html
{% for post in posts %}
{% if post.status == 'Draft' %}
{% else %}
<tr>
<th scope="row">{{ forloop.counter }}</th>
<td><a style="color:blue" href="{% url 'edmin:post_detail_view' pk=post.pk %}">{{ post.title }}</a></td>
<td>{{ post.banner_title }}</td>
<td>{{ post.created }}</td>
<td>{{ count_view }}</td>
<td>{{ post.status }}</td>
<td>Edit</td>
<td>Delete</td>
</tr>
{% endif %}
{% endfor %}
Since context allows 'dict', you can pass all of your views through context.

Django: Two questions on extending ListView with get_context_data

I tried something similar to this. I have three models:
class PartBase(models.Model):
name = models.CharField('Name', max_length=120)
price = models.DecimalField("Price per part", decimal_places=2, max_digits=6)
class Sett(models.Model):
name = models.CharField('Name', max_length=120)
class PartRelation(models.Model):
part = models.ForeignKey(PartBase, on_delete=models.CASCADE)
qty = models.PositiveIntegerField("Quantity")
sett = models.ForeignKey(Sett, related_name='setts', on_delete=models.SET_NULL, null=True)
def get_position_price(self):
return self.qty * self.part.price
now I want to add the price of all the items in a Sett in a row in my HTML.
{% extends 'base.html' %}
{% block title %}
Add Set
{% endblock title %}
{% block content %}
<table class="table">
<tr>
<th>Set Name</th>
<th>Total price</th>
</tr>
{% for set in setts %}
<tr>
<td>{{ set.name }}</td>
<td>{{ set.test }}</td>
</tr>
{% endfor %}
</table>
{% endblock %}
I wanted to override the get_context_data method somehow like this:
class SetListView(ListView):
model = Sett
context_object_name = "setts"
def get_context_data(self,**kwargs):
context = super(SetListView, self).get_context_data(**kwargs)
context['test'] = "price"
return context
But I only get an empty field in the template (which I assumed would have the word "price".
I can access the price in the shell via
for s in Sett.objects.all():
pr = PartRelation.objects.filter(sett=s)
price = 0
for p in pr:
price += p.get_position_price()
But how would I put the code from the shell in the get_context_data() function, so that for every row I get the corresponding total price?
This did the trick:
class SetListView(ListView):
model = Sett
context_object_name = "setts"
def get_context_data(self, **kwargs):
context = super(SetListView, self).get_context_data(**kwargs)
for s in context["setts"]:
pr = PartRelation.objects.filter(sett=s)
s.total_price = 0
for p in pr:
s.total_price += p.get_position_price()
return context
I would gladly get feedback if that is a good approach (and why not/how to do better).

django user fields shown empty in template

cannot access fields in templates
model.py:
class DSS(models.Model):
title = models.CharField(max_length=255, null=True, blank=True, verbose_name='عنوان')
usr = models.ForeignKey(User, related_name='owner', verbose_name='کاربر')
view.py:
def state(request):
result = DSS.objects.values('usr').order_by('usr').annotate(count=Count('usr'))
context = {'result': result,}
return render(request, 'state.html', context)
my template:
<tr>
<td>{{ item.usr }}{{ item.usr.get_username}}{{ item.usr.username}}{{ item.usr.get_full_name}}</td>
<td>{% with item.usr.get_username as usrnm %}
{{ item.usr.get_full_name|default:usrnm }}
{% endwith %}</td>
<td>{{ item.usr.first_name }} {{ item.usr.lastname }}</td>
<td>{{ item.owner.first_name }}</td>
<td>{{ item.count }}</td>
</tr>
{{ item.count }} work well and {{ item.usr }} just show user id, but I need to display username however none of this tries worked!
Instead of values(), try to send the actual queryset. And to reduce DB hits, you can use select_related(). For example:
result = DSS.objects.select_related('usr').order_by('usr')
Also .annotate(count=Count('usr')) will not work properly. It will show 1 for each item of queryset. Instead, try aggregating.
def state(request):
result = DSS.objects.select_related('usr').order_by('usr')
user_count = result.aggregate(u_count=Count('usr')).get('u_count')
context = {'result': result, 'user_count': user_count}
return render(request, 'state.html', context)
And render it in template:
{{ user_count }}
Instead of
result = DSS.objects.values('usr').order_by('usr').annotate(count=Count('usr'))
Try
result = DSS.objects.values('usr', 'usr__username').order_by('usr').annotate(count=Count('usr'))
And in html
{{ item.usr__username }}
Try to add the __str__ method in the user model.
def __str__(self):
return self.first_name + " " + self.last_name
# use the fields you have in your user model, mine was first_name and last_name