Looping in django template with variable parameter - python

I want to get all the details of class Material where user=user_id
Here is the models.py:
class Material(models.Model):
subject = models.CharField(max_length=10)
topic = models.CharField(max_length=50)
user = models.IntegerField()
and my views.py:
def add_material(request):
c = {}
c.update(csrf(request))
if 'user_session' in request.session:
user_id = request.session['user_session']
material_array = Material.objects.filter(user=user_id).values()
materials_len = len(material_array)
c['m_len'] = materials_len
for i in range(0, materials_len):
c['material_id_'+str(i)] = material_array[i]
return render_to_response('add_material.html',c)
else:
return HttpResponseRedirect('/user')
and my add_material.html is:
{% for i in range(m_len) %}
<tr>
{% for j in material_id_+str(i) %}
{{j.subject}}
{{j.topic}}
{% endfor %}
</tr>
{%endfor%}
So I am getting error in template, how to insert variable in for loop?

This how I would do it.
views.py
def add_material(request):
c = {}
c.update(csrf(request))
if 'user_session' in request.session:
user_id = request.session['user_session']
material_array = Material.objects.filter(user=user_id)
c.update({'materials': material_array})
return render_to_response('add_material.html', c)
else:
return HttpResponseRedirect('/user')
template
{% for material in materials %}
<tr>
<td>{{ material.subject }}</td>
<td>{{ material.topic }}</td>
<td>{{ material.user.username }}</td>
</tr>
{% endfor %}
You can include any user field you like.

Related

Django: Show data from current user

I'm having trouble displaying data from current user. It shows all the shifts that was given to other users also. I don't have any idea how to do this. Below is my code.
models.py
class User(models.Model):
user_name = models.CharField(max_length=32, unique=True)
pass_word = models.CharField(max_length=150)
is_active = models.BooleanField(default=True)
class Rostering(models.Model):
name = models.CharField(max_length=64)
begin_time = models.TimeField(default="")
end_time = models.TimeField(default="")
is_active = models.BooleanField(default=True)
class RosteringUser(models.Model):
rostering_user = models.ForeignKey(Rostering, on_delete=models.CASCADE)
user = models.ForeignKey(User, on_delete=models.CASCADE)
views.py
def my_shift(request):
if request.method == 'GET':
queryset = RosteringUser.objects.all()
if queryset:
for obj in queryset:
id = Rostering.objects.get(rosteringuser=obj.id)
obj.id = id
return render(request, 'my_shift.html', {'queryset': queryset})
my_shift.html
{% for obj in queryset %}
<tr>
<td>{{ obj.user.user_name }}</td>
<td>{{ obj.id.name }}-{{ obj.id.begin_time }}</td>
<td>{{ obj.id.name }}-{{ obj.id.end_time }}</td>
</tr>
{% endfor %}
Thank you in advance!
Simply you can try like this:
if queryset:
for obj in queryset:
id = Rostering.objects.get(rosteringuser=obj.id)
obj.id = id
querysets = obj
return render(request, 'my_shift.html', {'querysets': querysets})
And in templates:
{% for object in querysets %}
<tr>
<td>{{ object.user.user_name }}</td>
<td>{{ object.id.name }}-{{ object.id.begin_time }}</td>
<td>{{ object.id.name }}-{{ object.id.end_time }}</td>
</tr>
{% endfor %}
def my_shift(request):
if request.method == 'GET':
rost_id = RosteringUser.objects.filter(user_id=request.user.id).values("rostering_user_id").first()
if rost_id :
data = Rostering.objects.get(id=rost_id['rostering_user_id'])
return render(request, 'my_shift.html', {'queryset': data })
in template you can directly display logged in username {{ request.user.first_name }}

How to add Django Object Models to A Separate List

I am creating an app for a school schedule using Django. Admin users can currently add classes to a list. Student users can view that list but I want to create a button/link that will add that class object to a separate list that will act as their applied classes.
Models.py
class Class(models.Model):
def __str__(self):
return self.name
name = models.CharField(max_length=50)
crn = models.CharField(max_length=5, validators=[RegexValidator(r'^\d{1,10}$')])
grade_mode = models.CharField(max_length=50)
subject = models.CharField(max_length=3)
course_num = models.CharField(max_length=4, validators=[RegexValidator(r'^\d{1,10}$')])
section_num = models.CharField(max_length=3, validators=[RegexValidator(r'^\d{1,10}$')])
credit_hours = models.FloatField(validators=[MinValueValidator(0.0), MaxValueValidator(5.000)])
teacher = models.CharField(max_length=50)
Views.py
#login_required
#dec.student_required
def index(request):
class_list = Class.objects.all().order_by("-name")
# Allow for Posting of New Classes to Schedule.
if request.method == "POST":
form = ClassesForm(request.POST)
if form.is_valid():
form.save()
form = ClassesForm()
messages.success(request, "Class Added to Registry!")
else:
form = ClassesForm()
context_dict = {'classes': class_list,
'form': form}
return render(request, 'index.html', context=context_dict)
Index.HTML Add Button
<table>
<tbody>
{% if classes %}
{% for class in classes %}
<tr>
<td>Class Name: </td>
<td>Subject: </td>
<td>CRN: </td>
<td>Course Number: </td>
<td>Section Number: </td>
<td>Credit Hours: </td>
<td>Teacher: </td>
<td>Grade Mode: </td>
<td>Add Class</td>
</tr>
<tr>
<td>{{ class.name }}</td>
<td>{{ class.subject }}</td>
<td>{{ class.crn }}</td>
<td>{{ class.course_num }}</td>
<td>{{ class.section_num }}</td>
<td>{{ class.credit_hours }}</td>
<td>{{ class.teacher }}</td>
<td>{{ class.grade_mode }}</td>
<td>
<form method="GET">
{% csrf_token %}
<button class="addToSchedule" type="submit" value="add" name="Add Class">
Add Class
</button>
</form>
</td>
</tr>
{% endfor %}
</tbody>
{% else %}
<strong>There are no classes added.</strong>
{% endif %}
</table>
Image on Website.
So far I can print out the models on their own separate list as shown above but I don't know where to go in regards to the button or if a button is even the correct way of doing it. I want to click on a button and that model will be added and saved to the Added Classes section above.

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 %}

How to use outer loopcounter to access an array in the inner loop

In the code below the inner forloop is not working
<tbody>
{% for rec in medrec %}
<tr>
<td>{{ forloop.counter }}</td>
<td>{{ rec.date }}</td>
<td>{{ rec.disease }}</td>
<td>{{ rec.treatment }}</td>
<td> {% for n in medicine.forloop.parentforloop.counter0 %}
{{ n.medicine }}
{% endfor %}
</td>
</tr>
{% endfor %}
</tbody>
The code above generates a table. Each rec has a array of medicines.
Like for the rec.forloop.counter where forloop.counter == 1 there will objects in the medicine array index [0].
How do i print it?
def profile(request,rid):
patient = Patient.objects.get(pk=rid)
medic = MedicalRec.objects.filter(patient=patient)
i=0
a=[]
for n in medic:
a.append(medicine.objects.filter(Rec= n))
print(a)
if patient:
return render(request,'patient.html',{
'medrec' : medic,
'pat' : patient,
'medicine' : a
})
else:
return 'patient not found'
Models
from django.db import models
# Create your models here.
class Patient(models.Model):
name = models.CharField(max_length=100)
age = models.IntegerField()
address = models.TextField()
contact = models.CharField(max_length=15)
def __str__(self):
return self.name
class Stock(models.Model):
name = models.CharField(max_length=100)
quantity = models.IntegerField()
expiry = models.DateField()
price = models.IntegerField()
def __str__(self):
return self.name
class MedicalRec(models.Model):
patient = models.ForeignKey(Patient)
date = models.DateField()
disease = models.TextField()
treatment = models.TextField()
medicine = models.ForeignKey(Stock)
def __str__(self):
return str(self.date)
class medicine(models.Model):
Rec = models.ForeignKey(MedicalRec,related_name='med_set')
medicine = models.ForeignKey(Stock)
def __str__(self):
return str(self.Rec.date)
class Billing(models.Model):
name = models.ForeignKey(Stock)
rate = models.IntegerField()
Date = models.DateField()
def __str__(self):
return self.id
You don't have to create the list yourself. Django creates a reverse relation for you. It will be named medicine_set, but now that you're showing your models you have overridden it to be med_set. So you do not have to create a list in your view. You can use the related manager in your template:
view:
def profile(request, rid):
patient = get_object_or_404(Patient, pk=rid)
medic = MedicalRec.objects.filter(patient=patient)
return render(request, 'patient.html', {
'pat': patient,
'medrec': medic,
})
Template:
<tbody>
{% for rec in medrec %}
<tr>
<td>{{ forloop.counter }}</td>
<td>{{ rec.date }}</td>
<td>{{ rec.disease }}</td>
<td>{{ rec.treatment }}</td>
<td>
{% for medicine in medrec.med_set.all %}
{{ medicine }}
{% endfor %}
</td>
</tr>
{% endfor %}
</tbody>
I modified melvyn's answer and it worked
<tbody>
{% for rec in medrec %}
<tr>
<td>{{ forloop.counter }}</td>
<td>{{ rec.date }}</td>
<td>{{ rec.disease }}</td>
<td>{{ rec.treatment }}</td>
<td>
{% for medicine in rec.med_set.all %}
{{ medicine.medicine }},
{% endfor %}
</td>
</tr>
{% endfor %}
</tbody>

Django - get model object attributes from ModelForm

I have a ModelFormSet:
TransactionFormSet = modelformset_factory(Transaction, exclude=("",))
With this model:
class Transaction(models.Model):
account = models.ForeignKey(Account)
date = models.DateField()
payee = models.CharField(max_length = 100)
categories = models.ManyToManyField(Category)
comment = models.CharField(max_length = 1000)
outflow = models.DecimalField(max_digits=10, decimal_places=3)
inflow = models.DecimalField(max_digits=10, decimal_places=3)
cleared = models.BooleanField()
And this is the template:
{% for transaction in transactions %}
<ul>
{% for field in transaction %}
{% ifnotequal field.label 'Id' %}
{% ifnotequal field.value None %}
{% ifequal field.label 'Categories' %}
// what do i do here?
{% endifequal %}
<li>{{ field.label}}: {{ field.value }}</li>
{% endifnotequal %}
{% endifnotequal %}
{% endfor %}
</ul>
{% endfor %}
The view:
def transactions_on_account_view(request, account_id):
if request.method == "GET":
transactions = TransactionFormSet(queryset=Transaction.objects.for_account(account_id))
context = {"transactions":transactions}
return render(request, "transactions/transactions_for_account.html", context)
I want to list all the Transaction information on a page.
How can I list the "account" property of Transaction and the "categories"?
Currently the template shows only their id, I want to get a nice representation for the user (preferrably from their str() method).
The only way I can see that would work is to iterate over the FormSet, get the Ids of the Account and Category objects, get the objects by their Id and store the information I want in a list and then pull it from there in the template, but that seems rather horrible to me.
Is there a nicer way to do this?
Thanks to the comments, I figured it out that what I was doing was pretty dumb and pointless.
This works:
1) Get all Transaction objects
transactions = Transaction.objects.for_account(account_id)
2) Pass to template
context = {"transactions":transactions,}
return render(request, "transactions/transactions_for_account.html", context)
3) Access attributes, done
{% for transaction in transactions %}
<tr>
<td class="tg-6k2t">{{ transaction.account }}</td>
<td class="tg-6k2t">{{ transaction.categories }}</td>
<td class="tg-6k2t">{{ transaction.date }}</td>
<td class="tg-6k2t">{{ transaction.payee }}</td>
<td class="tg-6k2t">{{ transaction.comment }}</td>
<td class="tg-6k2t">{{ transaction.outflow }}</td>
<td class="tg-6k2t">{{ transaction.inflow }}</td>
<td class="tg-6k2t">{{ transaction.cleared }}</td>
</tr>
{% endfor %}

Categories