I am iterating through a queryset in the template using template tags to show the data of existing database entries (i.e. Customer Orders). However, I want to allow users to edit one of these fields (i.e. Delivery Remarks) for each Customer Order.
My approach was to use ModelForm but I cannot iterate the instances for each form as I iterate through the Customer Orders in the template.
I tried to iterate through an instance to a ModelForm but I get stuck because I am unable to pass the instance to a ModelForm in a template when in context(in views.py) it is the entire queryset that is passed to the template, not an instance. Perhaps I am approaching this problem the wrong way.
My code is below and I am thankful for any help you can give:
Models.py
from django.db import models
from products.models import Product
from counters.models import Counter
from promo.models import Promo
from django.contrib.auth.models import User
class Order(models.Model):
order_status = models.ForeignKey('OrderStatus')
products = models.ManyToManyField(Product, through='OrderProductDetails', through_fields=('order','product'), null=True, blank=True)
counter = models.ForeignKey(Counter, null=True, blank=True)
order_type = models.ForeignKey('OrderType')
order_remarks = models.CharField(max_length=1000, null=True, blank=True)
order_date = models.DateTimeField(auto_now_add=True, auto_now=False)
ordered_by = models.ForeignKey(User, null=True, blank=True)
promo = models.ForeignKey('promo.Promo', verbose_name="Order for which Promotion (if applicable)", null=True, blank=True)
delivery_date = models.DateField(blank=True, null=True)
delivery_remarks = models.CharField(max_length=1000, null=True, blank=True)
updated_on = models.DateTimeField(auto_now_add=False, auto_now=True)
class Meta:
verbose_name = "Order"
verbose_name_plural = "*Orders*"
def __unicode__(self):
return str(self.id)
class OrderProductDetails(models.Model):
order = models.ForeignKey('Order')
product = models.ForeignKey('products.Product')
quantity = models.PositiveIntegerField()
selling_price = models.DecimalField(decimal_places=2, max_digits=10)
order_product_remarks = models.ForeignKey('OrderProductRemarks',blank=True, null=True)
class Meta:
verbose_name_plural = "Order - Product Details"
verbose_name = "Order - Product Details"
def __unicode__(self):
return str(self.id)
class OrderProductRemarks(models.Model):
order_product_remarks = models.CharField(max_length=240, null=False, blank=False)
class Meta:
verbose_name_plural = "Order Product Remarks"
def __unicode__(self):
return str(self.order_product_remarks)
class OrderStatus(models.Model):
order_status_number = models.PositiveIntegerField(null=False, blank=False)
order_status = models.CharField(max_length=100, null=False, blank=False)
class Meta:
verbose_name_plural = "Order Status"
def __unicode__(self):
return str(self.order_status_number) + ". " + str(self.order_status)
class OrderType(models.Model):
order_type = models.CharField(max_length=100, null=False, blank=False)
class Meta:
verbose_name_plural = "Order Type"
def __unicode__(self):
return str(self.order_type)
Views.py
from django.shortcuts import render
from django.contrib.auth.decorators import login_required, user_passes_test
from django.contrib.admin.views.decorators import staff_member_required
from orders.models import Order
from orders.forms import OrderForm, RemarksForm
from products.models import Product
#login_required(login_url='/admin/login/?next=/')
def warehouseOrders(request):
queryset = Order.objects.filter(order_status__order_status_number = 2) #Filter through default queryset manager with filter through FK
form = RemarksForm(request.POST or None)
if form.is_valid():
form.save()
context = {'queryset': queryset, 'form': form}
template = 'warehouse_orders.html'
return render(request, template, context)
Forms.py
from django import forms
from .models import Order
class RemarksForm(forms.ModelForm):
class Meta:
model = Order
fields = ['delivery_remarks']
Template.html
{% extends 'base_frontend.html' %}
{% load crispy_forms_tags %}
{% block head_title %}
({{ queryset|length}}) Warehouse Orders
{% endblock %}
{% block head_styles %}
{% endblock %}
{% block jquery %}
{% endblock %}
{% block content %}
<h1>Orders to Pack</h1>
<br>
{% for item in queryset %}
Order ID: {{ item }}<br>
<b>Order Status: {{ item.order_status }}</b><br>
Counter: {{ item.counter }}<br>
Order Type: {{ item.order_type }}<br>
Order Remarks: {{ item.order_remarks }}<br>
Order Date: {{ item.order_date }}<br>
Sales Rep: {{ item.ordered_by }}<br>
Promo: {{ item.promo }}<br>
Delivery Date: {{ item.delivery_date }}<br>
<table class="table table-striped table-bordered">
<tr>
<th class="bottom-align-th">#</th>
<th class="bottom-align-th">Article No.</th>
<th class="bottom-align-th">Barcode No.</th>
<th class="bottom-align-th">Color</th>
<th class="bottom-align-th">Free Size</th>
<th class="bottom-align-th">3MTH<br>110<br>S</th>
<th class="bottom-align-th">6MTH<br>120<br>M</th>
<th class="bottom-align-th">9MTH<br>130<br>L</th>
<th class="bottom-align-th">------<br>140<br>XL</th>
<th class="bottom-align-th">------<br>150<br>XXL</th>
<th class="bottom-align-th">Unit Price</th>
<th class="bottom-align-th">Total Quantity</th>
<th class="bottom-align-th">Remarks</th>
</tr>
{% for product in item.products.all %}
<tr>
<td>{{ forloop.counter }}</td>
<td>{{ product.article_number }}</td>
<td>{{ product.barcode }}</td>
<td>{{ product.color }}</td>
<td>{{ product.quantity }}</td>
</tr>
{% endfor %}
</table>
<br>
Delivery Remarks: {{ item.delivery_remarks }}<br>
{% if form %}
<form method="POST" action=""> {% csrf_token %}
{{ form|crispy }}
<input type="submit" value="Save" class="btn btn-default"/>
</form>
{% endif %}
<br>
<button class="btn btn-success btn-lg">Start Packing</button>
<button class="btn btn-primary btn-lg">Finish Packing</button>
<button class="btn btn-danger btn-lg">Send Order to HQ for Changes</button>
{% endfor %}
{% endblock %}
Btw, using Django 1.7.2 here.
Related
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>
hoping for some guidance around my below problem with displaying reverse lookup field in a template inside formsets.
Maintenance Item Model
class Maintenance_Item(CommonInfo):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=100, unique=True)
name_description = models.CharField(max_length=255)
is_active = models.BooleanField(default=True)
def __str__(self):
return self.name
Checklist Model
class MaintenanceCheckList(CommonInfo):
CHOICES = (
('P','Compliant'),
('F','Non-Compliant'),
)
id = models.AutoField(primary_key=True)
item = models.ForeignKey(Maintenance_Item, on_delete=PROTECT, related_name='item_name')
is_compliant = models.CharField(max_length=20, choices= CHOICES, default=CHOICES[0][0])
def __int__(self):
return self.item
EDIT Form
class MaintenanceCheckListComplianceForm(forms.ModelForm):
is_compliant = forms.ChoiceField(
choices=MaintenanceCheckList.CHOICES,
widget=forms.RadioSelect,
required=False,
)
class Meta:
model = MaintenanceCheckList
fields = ('item','is_compliant',)
END EDIT
The current template
<form class="" method='post'>
{% csrf_token %}
{{ form.management_form }}
<table class="table my-0" id="dataTable">
<thead>
<tr>
<th>Maintenance Items</th>
</tr>
</thead>
<tbody>
{% for sub_form in form %}
<tr>
{% for i in sub_form.item_name.all %}
<td>Item: {{ i.name }}</p>
{% endfor %}
{{ sub_form.item|add_class:"form-select" }}<p>
</p>{{ sub_form.is_compliant }}</td>
</tr>
{% endfor %}
</table>
<div class="divider"></div>
<div class="col-md-12">
<p class='pt-sm-2'>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
Currently, I have generic formset view which creates an row for each item in the Maintenance_Item which works brilliant and generates the formset view as shown.
The challenge, I have is I want to hide the ModelChoice fields (I can do that easily with a Widget), and just display the friendly name in the ModelChoice field as a simple Text Label in the template.
Note setting disabled won't work because POST ignores disabled fields (already troubleshooted using that)
I've ran into a little problem. I want to construct a proper queryset to get values which represent the number of the expenses per category to display this like that.
This is what I got now:
class CategoryListView(ListView):
model = Category
paginate_by = 5
def get_context_data(self, *, category_object_list=None, **kwargs):
**categories = Category.objects.annotate(Count('expense'))
queryset = categories.values('expense__count')**
return super().get_context_data(
category_object_list=queryset,
**kwargs)
Of course it doesnt work and I have terrible table like this. I suppose the problem isn't in HTML but in my absolutely wrong query... What should I do?
This is my HTML in case it would be needed:
{% for category in object_list %}
<tr>
<td>
{{ category.name|default:"-" }}
</td>
<td>
{% for number in category_object_list %}
{{ number.expense__count }}
{% endfor %}
</td>
<td>
edit
delete
</td>
{% endfor %}
</tr>
Also my models.py:
class Category(models.Model):
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, null=True, blank=True,
on_delete=models.CASCADE)
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}'
You can try like this within your template with the reverse look up of
Foregin Keys. See the docs for more detail.
{% for category in object_list %}
<tr>
<td>
{{ category.name|default:"-" }}
</td>
<td>
{{category.expense_set.all.count}}
</td>
<td>
edit
delete
</td>
{% endfor %}
</tr>
Now in the view you can just pass all the categories with the ListView
class CategoryListView(ListView):
model = Category
paginate_by = 5
i'm pretty new to django and i'm struggling with models and database but i managed to get some stuff right but this here isnt working out for me.
so basically what i want to do is when i click on a course it shows me a table with the students who are registered to this course but i keep getting an empty table
models.py
from django.db import models
from django.contrib.auth import get_user_model
from django.urls import reverse
from django.utils.text import slugify
User = get_user_model()
# Create your models here
class student (models.Model):
S_id = models.IntegerField(unique=True)
S_fname = models.CharField(max_length=255)
S_lname = models.CharField(max_length=255)
def __str__(self):
return self.S_id
class classes(models.Model):
C_id = models.CharField(max_length=255,unique=True)
C_name = models.CharField(max_length=255)
C_room = models.CharField(max_length=255)
Start_time = models.CharField(max_length=255)
Instructs = models.ManyToManyField(User, through='Teaches')
Registered = models.ManyToManyField(student, through='Registered')
slug = models.SlugField(allow_unicode=True, unique=True)
def __str__(self):
return self.C_id
def save(self,*args,**kwargs):
self.slug = slugify(self.C_id)
super().save(*args,**kwargs)
def get_absolute_url(self):
return reverse('classes:single',kwargs={'slug':self.slug})
class Meta:
ordering = ['C_name']
class Teaches(models.Model):
Instructor = models.ForeignKey(User, related_name='St_id', on_delete=models.CASCADE)
Course = models.ForeignKey(classes, related_name='Co_id', on_delete=models.CASCADE)
class Registered(models.Model):
Student = models.ForeignKey(student, related_name='Stu_id', on_delete=models.CASCADE)
Course = models.ForeignKey(classes, related_name='Cou_id', on_delete=models.CASCADE)
classes_detail.html
{% extends "classes/classes_base.html" %} {% block pregroup %}
<div class="container">
<h1>{{classes.C_name}}</h1>
<div class="table-responsive">
<table class="table">
<thead>
<tr>
<th>Student ID</th>
<th>Student First Name</th>
<th>Student Last Name</th>
<th>attendance</th>
</tr>
</thead>
<tbody>
{% for student in object_list %}
{% if student in classes.Registered.all %}
<tr class="">
<td>{{ student.S_id }}</td>
<td>{{ student.S_fname }}</td>
<td>{{ student.S_lname }}</td>
<td></td>
</tr>
{% endif %}
{% endfor %}
</tbody>
</table>
</div>
</div>
{% endblock pregroup %}
views.py
from django.shortcuts import render
from django.contrib.auth.mixins import LoginRequiredMixin,PermissionRequiredMixin
from django.shortcuts import get_object_or_404
from django.urls import reverse
from django.views import generic
from .models import classes,Teaches
from django.contrib import messages
# Create your views here.
class ListClasses(generic.ListView):
model = classes
class SingleClass(generic.DetailView):
model = classes
This is what your classes details template should look like:
{% for student in object.Registered.all %}
<tr class="">
<td>{{ student.S_id }}</td>
<td>{{ student.S_fname }}</td>
<td>{{ student.S_lname }}</td>
<td></td>
</tr>
{% endfor %}
I'm new to Django. I am making a simple store.
Currently I am working on the Order section.
Every Order has Order Items inside it. Every order item has some values and a product id.
What I am trying to display on the index.html, is the orders and its items inside it. However order.items always outputs order.OrderItem.None
views.py
class IndexView(generic.ListView):
template_name = 'order/index.html'
context_object_name = 'all_orders'
def get_queryset(self):
return Order.objects.all().prefetch_related('items')
def get_context_data(self, **kwargs):
context = super(IndexView, self).get_context_data(**kwargs)
return context
views.py
# Create your models here.
class Order(models.Model):
user = models.ForeignKey(User, related_name='orders')
created_at = models.DateTimeField(auto_now_add=True, null=True)
class OrderItem(models.Model):
product = models.ForeignKey(Product)
order = models.ForeignKey(Order, related_name='items')
item_name = models.CharField(max_length=255, null=True, blank=True)
item_price_in_usd = models.DecimalField(max_digits=6, decimal_places=2, null=True, blank=True)
def __str__(self):
return self.product.name
index.html
{% for order in all_orders %}
<tr>
<td>{{ order}}</td>
<td>{{ order.created_at}}</td>
<td>{{ order.items}}</td>
</tr>
{% endfor %}
Ok, I have found to solution. Apparently you have to add .all
{% for order in all_orders %}
<tr>
<td>{{ order}}</td>
<td>{{ order.created_at}}</td>
<td>
{% for items in order.items.all %}
<td>{{ items.item_name}}</td>
{% endfor %}
</td>
</tr>
{% endfor %}