Django - add summary table in admin-site - python

What I want to achieve is to have a list of associations on one column and total members on the other column, like so:
I have tried to look for other solutions here with no luck, is there something i'm missing?
Still a newbie so appreciate all your help and guidance, folks!
models.py
class Member(models.Model):
member_no = models.AutoField(primary_key=True)
association = models.ForeignKey('Association')
...
class Association(models.Model):
asoc_name = models.CharField(max_length=50, null=True, blank=True)
class Meta:
db_table = 'Association'
def __str__(self):
return self.asoc_name
def __unicode__(self):
return self.asoc_name
class AssociationSummary(Association):
class Meta:
proxy = True
verbose_name = 'Association Summary'
verbose_name_plural = 'Association Summary'
admin.py
#admin.register(AssociationSummary)
class ChartAssociationAdmin(admin.ModelAdmin):
change_list_template = 'admin/chart_association.html'
def get_total(self):
total = Member.objects.all().aggregate(association=Sum('member_no'))
return total
def changelist_view(self, request, extra_context=None):
my_context = {
'member_no': self.get_total(),
}
return super(ChartAssociationAdmin, self).changelist_view(request,
extra_context=my_context)
chart_association.html
{% extends 'admin/change_list.html' %}
{% block content_title %}
<h1> Association Summary </h1>
{% endblock %}
{% block result_list %}
<div class=”results”>
<table>
<thead>
<tr>
<th>
<div class=”text”>
<span>Association</span>
</div>
</th>
<th>
<div class=”text”>
<span>Total Members</span>
</div>
</th>
</tr>
</thead>
<tbody>
{% for row in member %}
<tr class="{% cycle 'row1' 'row2' %}">
<td> {{ row.asoc_name }} </td>
<td> {{ row.total }} </td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endblock %}
{% block pagination %}{% endblock %}

Related

Nested Regroups with django with some attributes from none regroups

I have a django template that I have implemented regroups in it. I have a problem with how to display some of the attributes from my model into the template in a table.
I have a couple of issues to address:
How can I display the remaining 4 attributes from the ImplementationMatrix model i.e implementation_status, implementation_summary, challenges, and wayforward to be displayed at the respective columns in the table on the template (index.html) without distorting the layout for each instance of ImplementationMatrix.
The last for loop in the templates displays only one item for subactivity while I have more than subactivity for the respective activity.
Is there any better way of implementing all this?
My Models:
class Strategy(TrackingModel):
"""
Stores all the strategies related to HSSP.
"""
strategy_name = models.CharField(
max_length=255, blank=True, null=True, default="")
class Meta(TrackingModel.Meta):
verbose_name_plural = "Strategies"
def __str__(self):
return self.strategy_name
class Intervention(TrackingModel):
intervention_name = models.CharField(
max_length=255, blank=True, null=True, default=""
)
strategy = models.ForeignKey(Strategy, on_delete=models.PROTECT)
class Meta(TrackingModel.Meta):
verbose_name_plural = "Interventions"
def __str__(self):
return self.intervention_name
class Activity(TrackingModel):
activity_name = models.CharField(
max_length=255, blank=True, null=True, default="")
intervention = models.ForeignKey(Intervention, on_delete=models.PROTECT)
class Meta(TrackingModel.Meta):
verbose_name_plural = "Activities"
def __str__(self):
return self.activity_name
class SubActivity(TrackingModel):
subactivity_name = models.CharField(
max_length=255, blank=True, null=True, default=""
)
activity = models.ForeignKey(Activity, on_delete=models.PROTECT)
class Meta(TrackingModel.Meta):
verbose_name_plural = "Sub Activities"
def __str__(self):
return self.subactivity_name
class ImplementationMatrix(TrackingModel):
"""
The class for keeping track the implementation of each action plan
"""
IMPLEMENTATION_STATUS = (
("ON PROGRESS", "ON PROGRESS"),
("DONE", "DONE"),
("NOT DONE", "NOT DONE"),
)
implementation_summary = models.TextField()
implementation_status = models.CharField(
choices=IMPLEMENTATION_STATUS, max_length=100, default="",
verbose_name="Matrix Implementation Status"
)
challenges = models.TextField()
way_forward = models.TextField()
sub_activity = models.ForeignKey(
SubActivity, on_delete=models.PROTECT, verbose_name='Sub-Actions')
def __str__(self) -> str:
return self.sub_activity.activity.intervention.strategy.strategy_name
My View:
#login_required(login_url="/login")
def matrix_implementation_list(request: HttpRequest) -> HttpResponse:
all_implementations = ImplementationMatrix.objects.filter(
active=True, deleted=False).select_related(
'sub_activity',
'sub_activity__activity',
'sub_activity__activity__intervention',
'sub_activity__activity__intervention__strategy')
context = {'all_implementations': all_implementations}
return render(request, 'index.html', context)
My template (index.html)
<div class="card-body">
{% regroup all_implementations by sub_activity.activity.intervention.strategy.strategy_name as strategy_list %}
<!-- Start Table section -->
<div class="table-responsive table-bordered">
<table class="table">
<thead class="thead-light">
<tr>
<th>Policy Statement</th>
<th>Action</th>
<th>Sub-Actions</th>
<th>Implementation Summary</th>
<th>Implementation Status</th>
<th>Challenges</th>
<th>Way Forward</th>
</tr>
</thead>
{% for strategy in strategy_list %}
<tr>
<td colspan="7" class="text-center"><strong>Priority Area {{ forloop.counter }}: {{ strategy.grouper }}</strong></td>
</tr>
{% regroup strategy.list by sub_activity.activity.intervention.intervention_name as intervention_list %}
{% for intervention in intervention_list %}
{% regroup intervention.list by sub_activity.activity.activity_name as activity_list %}
{% for activity in activity_list %}
{% regroup activity.list by sub_activity.subactivity_name as subactivity_list %}
{% for subactivity in subactivity_list %}
<tr>
{% if forloop.first %}
{% if forloop.parentloop.first %}
<td rowspan="{{ intervention.list|length }}">
{{ intervention.grouper|wordwrap:30|linebreaksbr }}
</td>
{% endif %}
<td rowspan="{{ activity.list|length }}">
{{ activity.grouper|wordwrap:30|linebreaksbr }}
</td>
{% endif %}
<td>
{{ subactivity.grouper|wordwrap:20|linebreaksbr }}
</td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
{% endfor %}
{% endfor %}
{% endfor %}
{% endfor %}
</table>
</div>
<!-- end Table Section -->
</div>
I was able to display the contents of the parent model in the last 'for loop' by doing the following:
<td>{{ subactivity.grouper|wordwrap:20|linebreaksbr }}</td>
<td>{{subactivity.list.0.implementation_summary|wordwrap:30|linebreaksbr}}</td>
<td>{{ subactivity.list.0.get_implementation_status_display }}</td>
<td>{{ subactivity.list.0.challenges|wordwrap:30|linebreaksbr }}</td>
<td>{{ subactivity.list.0.way_forward|wordwrap:30|linebreaksbr }}</td>

Why my searching by multiple categories in Django has not result?

Hi everyone! I want search by multiple categories, but my code is not working. When I type categories name, I got nothing. Can anyone help me?
'''views.py'''
class ExpenseListView(ListView):
model = Expense
paginate_by = 5
def get_context_data(self, *, object_list=None, **kwargs):
queryset = object_list if object_list is not None else self.object_list
form = ExpenseSearchForm(self.request.GET)
if form.is_valid():
name = form.cleaned_data.get('name', '').strip()
if name:
queryset = queryset.filter(name__icontains=name)
return super().get_context_data(
form=form,
object_list=queryset,
summary_per_category=summary_per_category(queryset),
get_per_year_month_summary=get_per_year_month_summary(queryset),
**kwargs)
def get_queryset(self):
queryset = super(ExpenseListView, self).get_queryset()
q = self.request.GET.get("q")
if q:
return queryset.filter(date__icontains=q)
return queryset
def get_gategory(request, pk_test):
category = Category.objects.get(id=pk_test)
orders = category.order_set.all()
order_count = orders.count()
myFilter = OrderFilter(request.GET, queryset=orders)
orders = myFilter.qs
context = {'category': category, 'orders': orders,
'order_count': order_count, 'myFilter': myFilter }
return render(request, 'expense_list.html',context)
'''May be my problem is in my vieews or in models. I m new in Django and dont nkow many things..'''
''' Here my models.py'''
class Category(models.Model):
class Meta:
ordering = ('name',)
name = models.CharField(max_length=50, unique=True)
def __str__(self):
return f'{self.name}'
class Expense(models.Model):
class Meta:
ordering = ('-date', '-pk')
category = models.ForeignKey(Category, models.PROTECT, null=True, blank=True)
name = models.CharField(max_length=50)
amount = models.DecimalField(max_digits=8, decimal_places=2)
date = models.DateField(default=datetime.date.today, db_index=True)
def __str__(self):
return f'{self.date} {self.name} {self.amount}'
'''html''
{% extends "base.html" %}
{% block content %}
add
<form method="get">
{{form.as_p}}
<button type="submit">search</button>
</form>
<hr>
{% if expenses %}
<form action="#" method="GET">
{% endif %}
<input type="text" name="q" placeholder="category">
<input type="text" name="q" placeholder="name">
<input type="submit" value="Search">
</form>
<hr>
<form method="GET" action={% url 'expenses:expense-list' %}>
{% csrf_token %}
From: <input type="date" name="q"/>
To: <input type="date" name="q"/>
From_category:
<select>
<option selected disabled="true"></option>
{% for obj in object_list %}
<option value="{{ obj.category }}">{{obj.category}}</option>
{%endfor%}
</select>
<button type="submit">search</button>
</form>
</div>
<br>
<table border="1">
<caption>Expenses</caption>
<thead>
<tr>
<th>no.</th>
<th>category</th>
<th>name</th>
<th>amount</th>
<th>date</th>
<th>actions</th>
</tr>
</thead>
<tbody>
{% for obj in object_list %}
<tr>
<td>{{ page_obj.start_index|add:forloop.counter0 }}.</td>
<td>{{ obj.category|default:"-" }}</td>
<td>{{ obj.name|default:"-" }}</td>
<td>{{ obj.amount|floatformat:2 }}</td>
<td>{{obj.date}}</td>
<td>
edit
delete
</td>
</tr>
{% empty %}
<tr>
<td colspan="5">no items</td>
</tr>
{% endfor %}
</tbody>
</table>
</form>
{% include "_pagination.html" %}
<hr>
<table border="1">
<caption>Summary per category</caption>
<tr>
{% for category, total in summary_per_category.items %}
<tr>
<td>{{category}}:</td>
<td>{{total|floatformat:2}}</td>
</tr>
{% endfor %}
</tr>
</table>
<hr>
<table border="2">
<caption>Summary per year-month </caption>
<tr>
{% for year, total_year in get_per_year_month_summary.items %}
<tr>
<td>{{year}}</td>
<td>{{total_year|floatformat:2}}</td>
</tr>
{% endfor %}
</tr>
</table>
{% endblock %}
'''urls'''
urlpatterns = [
path('expense/list/',
ExpenseListView.as_view(),
name='expense-list'),
path('expense/create/',
CreateView.as_view(
model=Expense,
fields='__all__',
success_url=reverse_lazy('expenses:expense-list'),
template_name='generic_update.html'
),
name='expense-create'),
path('expense/<int:pk>/edit/',
UpdateView.as_view(
model=Expense,
fields='__all__',
success_url=reverse_lazy('expenses:expense-list'),
template_name='generic_update.html'
),
name='expense-edit'),
path('expense/<int:pk>/delete/',
DeleteView.as_view(
model=Expense,
success_url=reverse_lazy('expenses:expense-list'),
template_name='generic_delete.html'
),
name='expense-delete'),
path('category/list/',
CategoryListView.as_view(),
name='category-list'),
path('category/create/',
CreateView.as_view(
model=Category,
fields='__all__',
success_url=reverse_lazy('expenses:category-list'),
template_name='generic_update.html'
),
name='category-create'),
path('category/<int:pk>/delete/',
DeleteView.as_view(
model=Category,
success_url=reverse_lazy('expenses:category-list'),
template_name='generic_delete.html'
),
name='category-delete'),
path('category/<int:pk>/update/',
UpdateView.as_view(
model=Category,
fields='__all__',
success_url=reverse_lazy('expenses:category-list'),
template_name='generic_update.html'
),
name='category-update'),
]
this is screen of my projects views

Unable to display the image through the result of CRUD operations in django

i am working on hotel booking app , in this i want to display the image of a hotel, based on user entered location . In this if i am displaying all hotels , i am able to display an image , if i am trying to displaying an image through some CRUD operations, i am unable to display it. Here are my code snippets.
class Customer_details(models.Model):
Name = models.CharField(max_length=128)
Age = models.IntegerField()
Mobile_number = models.IntegerField()
Email = models.EmailField()
Address = models.CharField(max_length=50)
Special_request = models.CharField(max_length=50, blank=True)
user = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
return self.Name
hotel_rating_choices = (
('1','1'),
('2','2'),
('3','3'),
('4','4'),
('5','5'),
('6','6'),
('7','7'),
)
class Hotel(models.Model):
Hotel_Name = models.CharField(max_length=50)
location = models.CharField(max_length=20)
no_of_rooms = models.IntegerField()
rating = models.CharField(max_length=1, choices=hotel_rating_choices, default=3)
hotel_img = models.ImageField(upload_to='hotel_images/')
uploaded_at = models.DateTimeField(auto_now_add=True)
user = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
return self.Hotel_Name
class Hotel_image(models.Model):
hotel_img = models.ImageField(upload_to = 'hotel_images/')
hotel = models.ForeignKey(Hotel, on_delete=models.CASCADE)
def __str__(self):
return self.hotel
Ignore the remaining models just concentrate on Hotel model .
`Below code snippet is my view regarding to query.
def get_hotels_by_location(request):
location = request.POST.get('location')
print(location)
location = location.lower()
result = Hotel.objects.values('Hotel_Name', 'rating', 'hotel_img').filter(location=location)
context = {'hotels': result, 'header': ['Hotel_Name', 'Rating', 'image'] }
return render(
request,
template_name='display_hotel_by_location.html',
context=context
)
And below is my django html template
<table class="table">
<tr>
{% for i in header %}
<th>
{{ i }}
</th>
{% endfor %}
</tr>
{% for element in hotels %}
<tr>
{% with i=0 %}
{% for key, value in element.items %}
{% if i == 2 %}
<td> <img src="{{ element.url }}" width = "300" height="300"> </td>
{% endif %}
<td> {{ value }} </td>
{% with j=i %}
j=j+1
i=j
{% endwith %}
{% endfor %}
</tr>
{% endfor %}
</table>
Please help me on this issue.
Change your Hotel_image class to add related name at your foreign to use it further
class Hotel_image(models.Model):
hotel_img = models.ImageField(upload_to = 'hotel_images/')
hotel = models.ForeignKey(Hotel, on_delete=models.CASCADE, related_name="hotel_images")
Clean up a bit your views, you dont really need use values in that case.
from .models import Hotel
def get_hotels_by_location(request):
location = request.POST.get('location').lower()
result = Hotel.objects.filter(location=location)
context = {'hotels': result, 'header': ['Hotel_Name', 'Rating', 'image'] }
return render(
request,
template_name='display_hotel_by_location.html',
context=context
)
HTML 1 - If you consuming the hotel_img from class Hotel use this one
<table class="table">
<tr>
{% for i in header %}
<th>{{ i }}</th>
{% endfor %}
</tr>
{% for hotel in hotels %}
<tr>
{% if forloop.counter0 == 2 and hotel.hotel_img %}
<td> <img src="{{ hotel.hotel_img.url }}" width="300" height="300"> </td>
{% endif %}
<td> {{ hotel.Hotel_Name }} </td>
</tr>
{% endfor %}
</table>
HTML 2 - If you using the class Hotel_image use like that
<table class="table">
<tr>
{% for i in header %}
<th>{{ i }}</th>
{% endfor %}
</tr>
{% for hotel in hotels %}
<tr>
{% for img in hotel.hotel_images %}
{% if img.hotel_img %}
<td> <img src="{{ img.hotel_img.url }}" width="300" height="300"> </td>
{% endif %}
{% endfor %}
<td> {{ hotel.Hotel_Name }} </td>
</tr>
{% endfor %}
</table>
More info about Django relations: https://docs.djangoproject.com/en/2.0/ref/models/fields/#django.db.models.ForeignKey.related_name
You can use Template Tags too to filter all images from your Hotel_Image
1 - Create one folder called templatetag and inside that one file inside it to be your templatetag inside your app folder
hotel/templatetags/hotel_templatetag.py
Inside the file put that code
from django import template
from .models import Hotel_image
register = template.Library()
def get_hotel_images(self):
return Hotel_image.objects.filter(id=self.id)
You Html should be like that
<table class="table">
<tr>
{% for i in header %}
<th>{{ i }}</th>
{% endfor %}
</tr>
{% for hotel in hotels %}
<tr>
{% for img in hotel|get_hotel_images %}
{% if img.hotel_img %}
<td> <img src="{{ img.hotel_img.url }}" width="300" height="300"> </td>
{% endif %}
{% endfor %}
<td> {{ hotel.Hotel_Name }} </td>
</tr>
{% endfor %}
</table>
More info about templatetags: https://docs.djangoproject.com/en/2.0/howto/custom-template-tags/

Django Inline Formset - possible to follow foreign key relationship backwards?

I'm pretty new to django so I apologize if this has an obvious answer.
Say you have the following three models:
models.py
class Customer(models.Model):
name = models.CharField()
slug = models.SlugField()
class Product(models.Model):
plu = models.Charfield()
description = models.Charfield()
class Template(models.Model):
customer = models.ForeignKey(Customer)
product = models.ForeignKey(Product)
price = models.DecimalField()
The inline formset would look something like:
TemplateFormSet = inlineformset_factory(Customer, Template, extra=0,
fk_name='customer', fields=('price'))
Is it possible to follow the Template formset's Product foreign key backwards so you could display the plu and description fields within the same table?
For example something like this:
<table>
<tbody>
{% for obj in customer.template_set.all %}
<tr>
<td>{{ obj.product.plu }}</td>
<td>{{ obj.product.description }}</td>
<td>{% render_field formset.form.price class="form-control form-control-sm" %}</td>
</tr>
{% endfor %}
</tbody>
</table>
The formset's fields appear with the html above but the data from the bound form instance doesn't appear and I can't save by editing the empty fields.
I've also tried below but each formset is repeated for each object (for x formsets there are x*x rows):
<tbody>
{% for obj in customer.template_set.all %}
{% for form in formset %}
<tr>
<td>{{ obj.product.plu }}</td>
<td>{{ obj.product.description }}</td>
<td>{% render_field form.price class="form-control" %}</td>
</tr>
{% endfor %}
{% endfor %}
</tbody>
Basically I'm trying to go from the top portion of the image to the bottom
The formset functionality is only to show forms but something that you can do is create a custom form that display the 2 fields with the function of readonly like:
class your_form(models.ModelForm):
class Meta()
model = Template
fields = ['price', 'product']
def __init__(self, *args, **kwargs):
super(ItemForm, self).__init__(*args, **kwargs)
self.fields['product'].widget.attrs['readonly'] = True
TemplateFormSet = inlineformset_factory(Customer, Template, extra=0,
fk_name='customer', form=your_form)
That's my best tried, if you wanna display both try returning in your models something like:
class Product(models.Model):
plu = models.Charfield()
description = models.Charfield()
def __str__(self, *args, **kwargs):
a = '<td>' + self.plu + '</td><td>' + self.plu '</td>'
return self.plu + self.description # Or return 'a'
I managed to get it working although I'm not sure its the most efficient way. If anyone has a better way please let me know.
{{ formset.management_form }}
<table>
<thead>
...
</thead>
<body>
{% for obj in customer.template_set.all %}
{% with forloop.counter as outer_counter %}
{% for form in formset %}
{% if forloop.revcounter == outer_counter %}
{% for hidden in form.hidden_fields %} {{ hidden }} {% endfor %}
<tr>
<td>{{ obj.product.plu }}</td>
<td>{{ obj.product.description }}</td>
<td>{% render_field form.price class="form-control" %}</td>
</tr>
{% endif %}
{% endfor %}
{% endwith %}
{% endfor %}
</tbody>
</table>
Should also mention I'm using django-widget-tweaks which is where {% render_field %} comes from.
Update (the proper way):
{% for template in customer.template_set.all %}
{% for form in formset %}
{% if form.instance.id == template.pk %}

query set on model with setattr

class Product(models.Model):
name = models.CharField(max_length=50)
desc = models.CharField(max_length=50)
def __unicode__(self):
return self.name
class ProductModels(models.Model):
product = models.ForeignKey(Product)
name = models.CharField(max_length=50)
price = IntegerField(max_length=50)
def __unicode__(self):
return self.name
class Sold(model.Model)
product = models.ForeignKey(Product)
model_name = models.ForeignKey(ProductModels)
sold_date = models.DateField()
model_qty = models.IntegerField()
def __unicode__(self):
return self.sold_date
this is with reference to my previous question( that problem is solved)
what i am trying to find out is how many models have been sold from Jan to Dec for the particular product.
so far i have done this, i know it's little crude. but it would help he if it written correctly:
views.py
allmonths = ['jan' , ....., 'dec']
products = Products.objects.all()
for each_product in products :
models = ProductModels.objects.filter(product = each_product)
for each_model in models:
for months in allmonths :
att_name = str(each_model.model_name) + str(months)
print 'attname %s' % att_name
val = sold.objects.filter(product = each_product ,
model_name = each_model ,(sold_date =(allmonths.indesx(month) + 1))) .aggregate(qty=Sum('model_qty'))
val = temp(val['qty'])
setattr(each_product, att_name , val)
I am not sure if this correct or not , but this approach has worked earlier. i used getattribute template tag from here.
This is how my template looks like :
{% for record in products %}
<tr class="odd gradeX">
<td><span class="label label-warning">{{ record.name }}</span></td>
<td>
<table class="table table-striped table-bordered table-hover" id="pipelineTbl">
{% for model in record.ProductModels_set.all %}
<tr class="odd gradeX">
<td>
<span class="label label-success">{{ model }}</span>
</td>
</tr>
{% endfor %}
</table>
</td>
{% for months in allmonths %}
<td>
<table class="table table-striped table-bordered table-hover" id="pipelineTbl3">
{% for model in record.ProductModels_set.all %}
{% with model|add:months as val %}
<tr>
<td>{{ record|getattribute:val }}</td>
</tr>
{% endwith %}
{% endfor %}
</table>
</td>
{% endfor %}
</tr>
{% endfor %}
You can make the following query:
product = some_product()
year = 2013
product_sells = Sold.objects.filter(product=product, sold_date__year=year)
If you want to know how many individual sells do this:
product_sells.count()
If you want to sum the product sold quantities:
from django.db.models import Sum
product_sells.Sum('model_qty')
In general avoid iterating over Products.objects.all(), as it's really expensive on database and memory.

Categories