I have a todo website that allows users to put a remind in a certain list, such as work, school, groceries, etc. However, I'm a bit lost on how to get the list name and their items to display.
Models.py:
class RemindList(models.Model):
parent_user = models.ForeignKey(User, on_delete=models.CASCADE, null=True)
title = models.CharField(max_length=50)
class Reminder(models.Model):
remind_types = [('Regular', 'Regular'), ('Long Term', 'Long Term')]
title = models.CharField(max_length=100)
description = models.TextField()
remind_time = models.DateTimeField(blank=True)
parent_user = models.ForeignKey(User, on_delete=models.CASCADE, null=True)
parent_list = models.ForeignKey(RemindList, on_delete=models.CASCADE, null=True)
type_of_remind = models.CharField(max_length=12, choices=remind_types, default='Regular')
complete = models.BooleanField(default=False)
Views.py:
#login_required(login_url='/login')
def home(request):
user = get_object_or_404(User, username=request.user.username)
context = {
'events': ToDoItem.objects.filter(parent_user=user),
'reminders': Reminder.objects.filter(parent_user=user, type_of_remind='Regular'),
'long_term_reminders': Reminder.objects.filter(parent_user=user, type_of_remind='Long Term'),
'remind_list_items': RemindList.objects.filter(parent_user=user),
}
return render(request, 'main/home.html', context)
I can pass through the list names, and I planned to just loop through them and add Reminder.objects.filter(parent_user=user, type_of_remind='Regular', parent_list=list_name) to context. However, theres no way to loop through them on the html side (can't do for loop because there are other context types), and you can't filter them on the html side (correct me if I'm wrong). Is there another way to do this?
Ok, it took me a few readings, but if what I understand is correct you want to be able to iterate over the ReminderList objects and also list out the Reminder items under each one.
My suggestion would be to add a method to ReminderList that returns the items in that list, you could then do something like this in your template
{% for list in reminder_lists %}
... List header stuff goes here ...
{% for item in list.get_reminder_items %}
... Print the item ...
{% endfor %}
{% endfor %}
(The Django templating language can be a little interesting in that object.identifier can map to either an attribute or an object method - this can be useful for cases like these).
Related
I am using .values() and .annotate()to sum up 2 models fields based on matching criteria.
I wrapped this in a forloop in my template to iterate.
Problem: I cannot call the model fields anymore. The forloop returns the venue_id instead of the name and the usual approach to call the logo does not work anymore.
(these were rendering fine before I used .values() and .annotate(). Makes me think I am missing something in the logic here. Any ideas?
Models
class Venue(models.Model, HitCountMixin):
id = models.AutoField(primary_key=True)
name = models.CharField(verbose_name="Name",max_length=100, blank=True)
logo = models.URLField('Logo', null=True, blank=True)
class Itemised_Loyatly_Card(models.Model):
user = models.ForeignKey(UserProfile, blank=True, null=True, on_delete=models.CASCADE)
venue = models.ForeignKey(Venue, blank=True, null=True, on_delete=models.CASCADE)
add_points = models.IntegerField(name = 'add_points', null = True, blank=True, default=0)
use_points = models.IntegerField(name= 'use_points', null = True, blank=True, default=0)
Views
from django.db.models import Sum, F
def user_loyalty_card(request):
itemised_loyalty_cards = Itemised_Loyatly_Card.objects.filter(user=request.user.id).values('venue').annotate(add_points=Sum('add_points')).annotate(use_points=Sum('use_points')).annotate(total=F('add_points')-F('use_points'))
return render(request,"main/account/user_loyalty_card.html", {'itemised_loyalty_cards':itemised_loyalty_cards})
Templates
{%for itemised_loyatly_card in itemised_loyalty_cards %}
<img"src="{{itemised_loyatly_card.venue.logo}}">
{{itemised_loyatly_card.venue}}
{{itemised_loyatly_card.total}}
{%endfor%}
Renders
It returns only the value ID because that is the only field you passed in as an argument to .values('venue'). Whereas if you want another attribute you have to use field lookups, like so:
.values('venue__name'. 'venue__logo')
Also, .values() returns a QuerySet that returns dictionaries and not object instances, so if you pass that data into the template you can not access related data, meaning
{{itemised_loyatly_card.venue.logo}} will not work, but taking the first codeblock as an example {{itemised_loyatly_card.venue__logo}} works.
Another "mistake" is at these two annotations, annotations are a per object aggregation, these two lines are redundant, your model already has these fields.
.annotate(add_points=Sum('add_points'))
.annotate(use_points=Sum('use_points'))
That being said, if you want objects instead of values, that leaves you with:
views.py
itemised_loyalty_cards = (
Itemised_Loyatly_Card.objects.filter(user=request.user.id)
.annotate(total=F('add_points')-F('use_points'))
)
template.html
{%for itemised_loyatly_card in itemised_loyalty_cards %}
<p>
{{itemised_loyatly_card.venue.name}}
{{itemised_loyatly_card.add_points}}-
{{itemised_loyatly_card.use_points}}=
{{itemised_loyatly_card.total}}
</p>
<img src="{{itemised_loyatly_card.venue.logo}}" alt="" >
{%endfor%}
I have two models interrelated items and broken :
class Items(models.Model):
id = models.AutoField(primary_key=True)
item_name = models.CharField(max_length=50, blank=False)
item_price = models.IntegerField(blank=True)
item_quantity_received = models.IntegerField(blank=False)
item_quantity_available = models.IntegerField(blank=True)
item_purchased_date = models.DateField(auto_now_add=True, blank=False)
item_units = models.CharField(max_length=50, blank=False)
def __str__(self):
return self.item_name
class Broken(models.Model):
item = models.ForeignKey(Items, default=1, on_delete=models.CASCADE)
item_quantity_broken = models.IntegerField(blank=True)
item_broken_date = models.DateField(auto_now_add=True, blank=False)
item_is_broken = models.BooleanField(default=True)
date_repaired = models.DateField(auto_now=True, blank=True)
def __str__(self):
return self.item.item_name
I wrote this view function to retrieve data to a table into a template:
def broken_items(request):
br = Broken.objects.select_related('item').all()
print(br.values_list())
context = {
'title': 'broken',
'items': br,
}
return render(request, 'store/broken.html', context)
this is the executing query:
SELECT "store_broken"."id",
"store_broken"."item_id",
"store_broken"."item_quantity_broken",
"store_broken"."item_broken_date",
"store_broken"."item_is_broken",
"store_broken"."date_repaired",
"store_items"."id",
"store_items"."item_name",
"store_items"."item_price",
"store_items"."item_quantity_received",
"store_items"."item_quantity_available",
"store_items"."item_purchased_date",
"store_items"."item_units"
FROM "store_broken"
INNER JOIN "store_items"
ON ("store_broken"."item_id" = "store_items"."id")
looks like it gives me all the fields I want. In debugger it shows data from both tables,
so I wrote for loop in template,
{% for item in items %}
<tr>
<td>{{item.id}}</td>
<td>{{item.item_id}}</td>
<td>{{item.item_quantity_broken}}</td>
<td>{{item.item_broken_date}}</td>
<td>{{item.item_is_broken}}</td>
<td>{{item.date_repaired}}</td>
<td>{{item.item_name }}</td>
<td>{{item.item_item_quantity_received}}</td>
<td>{{item.item_quantity_available}}</td>
<td>{{item.item_purchased_date}}</td>
<td>{{item.items_item_units}}</td>
</tr>
{% endfor %}
The thing is this loop only gives me data from broken table only. I can't see data from Items table.
can someone help me to find the reason why other details are not showing?
Your items query is of Broken objects. So in order to access the Items values you need to change your table. For better understanding change your view like this:
brokens = Broken.objects.select_related('item').all()
context = {
'title': 'broken',
'brokens ': brokens,
}
and then your table:
{% for broken in brokens %}
<tr>
<td>{{broken.id}}</td>
<td>{{broken.item.pk}}</td> # This is the item id
<td>{{broken.item_quantity_broken}}</td>
<td>{{broken.item_broken_date}}</td>
<td>{{broken.item_is_broken}}</td>
<td>{{broken.date_repaired}}</td>
<td>{{broken.item.item_name}}</td>
<td>{{broken.item.item_quantity_received }}</td>
<td>{{broken.item.item_quantity_available}}</td>
<td>{{broken.item.item_purchased_date}}</td>
<td>{{broken.item.items_item_units}}</td>
</tr>
{% endfor %}
you loop over a List of Broken objects
to access the related item objects
item.item.item_name
I'm trying create a table with 2 columns:
1) Collections and 2) Qualified Sales.
Like the image above.
Each book count the own qualified_sales.
The Qualified sales(column in the table) must sum all qualified_sales of all books of each collection.
models.py
class Publishing_company(models.Model):
title = models.CharField(max_length=50)
class Collection(models.Model):
publishing_company = models.ForeignKey(Publishing_company, on_delete=models.CASCADE)
class Book(models.Model):
publishing_company = models.ForeignKey(Publishing_company, on_delete=models.CASCADE)
class Sale(models.Model):
book = models.ForeignKey(Book, on_delete=models.CASCADE)
qualified_sale = models.IntegerField(default=0)
views.py
def qlf_sales(request):
book = Collection.objects.filter(user=request.user)
qualified_sum = Sale.objects.filter(user=request.user, book__publishing_company__collection__in=book).aggregate(Sum('qualified_sale'))['qualified_sale__sum'] or 0
context = {'qualified_sum': qualified_sum}
return render(request, 'template.html', context)
template.html
{% for collection in collections %}
<tr>
<td>{{collection}}</td>
<td>{{qualified_sum}}%</td>
</tr>
{% endfor %}
But this code not work. Dont appear any debug error, but in the all fields in the Qualified Sales' column appear the same value: the sum of all qualified_sales of all sales of all book.
why didn't separate by collection?
If anyone can help me. Please i go a lot grateful.
I have 2 ArrayField lists and I want to join them using the zip method so I can Iterate through two lists in Django my django templates. But the output is treating each as array as seperate lists.
my model
class programas(models.Model):
title = models.CharField(unique=True, max_length=250)
script = ArrayField(models.CharField(max_length=8000, blank=True))
created_on = models.DateTimeField()
show_date = models.CharField(max_length=300, blank=True, null=True)
script_eng = ArrayField(models.CharField(max_length=8000, blank=True))
description = models.CharField(max_length=2000, blank=True, null=True)
description_eng = models.CharField(max_length=2000, blank=True, null=True)
url = models.CharField(max_length=200, blank=True, null=True)
show_id = models.IntegerField(primary_key=True)
id = models.IntegerField(null=True)
my view where I try to join the lists
def pages(request, id):
obj = programas.objects.get(id=id)
script = programas.objects.values_list('script')
script_eng = programas.objects.values_list('script_eng')
zip_scripts = list(zip(script , script_eng))
context = {'title': obj.title,
'show_date': obj.show_date,
'script' : obj.script,
'script_eng': obj.script_eng,
'description': obj.description,
'description_eng': obj.description_eng,
'show_id':obj.show_id,
'url': obj.url,
'zip_scripts' : zip_scripts,
}
return render(request, 'rtves/pages.html', context)
my code on the template page
{% if script %}
{% for text1, text2 in zip_scripts %}
<p> {{ text1 }} </p>
<p> {{ text2 }} </p>
{% endfor %}
{% else %}
<p>Nothing here</p>
{% endif %}
Have I got to make changes in the database?
programas.objects.values_list('script') gives you a list of the script fields of all the programas objects in the database. So, you effectively have a list of lists.
What you probably want is just the fields from the object you already have. So there's no need to use values_list there.
obj = programas.objects.get(id=id)
script = obj.script
script_eng = obj.script_eng
or, just pass them straight to the zip (note, there's no need for list anyway):
obj = programas.objects.get(id=id)
zip_scripts = zip(obj.script, obj.script_eng)
The reason it "doesn't" work on your perspective is that because when you cast querysets to built-in iterables, you don't get, an an iterable of the values but an iterable of one item tuples like
[('bill',), ('while',), ('participant',), ('you',)]
which, when you cast zip and list upon becomes even weirder, but you can simply flatter this with something like
list(map(o.itemgetter(0), qs))
In your case the whole code would be roughly
flatten = lambda qs: list(map(operator.itemgetter(0), qs))
script = flatten(programas.objects.values_list('script'))
script_eng = flatten(programas.objects.values_list('script_eng'))
# Then you can just zip them together and have what you wanted to begin with
zip_scripts = list(zip(script , script_eng))
I have two querysets. My first Queryset (services) has all of my service objects. My second Queryset (rating_values) has all of my rating values, where each index corresponds to the index in the services Queryset. For example services[1] corresponds with rating_values[1].
How do I loop through these two queries in an html page in django so so that I can display the service name along with the corresponding rating value?
To be clear, services contains service objects and rating_values contains decimal values. I pass the variables like this:
return render_to_response('services/display_services.html', {'user': request.user, 'services':services, 'rating_values': rating_values })
I would like to do something like this:
{% for service in services %}
<p> {{service.service_name}} : {{ corresponding rating_value}} </p>
Edit
Here is my Service model:
class Service(models.Model):
user_id= models.IntegerField(default=1)
service_name = models.CharField(max_length=100)
address = models.CharField(max_length=200)
def __str__(self): # __unicode__ on Python 2
return self.service_name
Here is my Rating Model:
class Rating(models.Model):
service_id= models.IntegerField(default=1)
service_name= models.CharField(max_length=200)
number_of_ratings = models.IntegerField()
total_rating_value = models.IntegerField()
rating_average = models.FloatField()
def __str__(self): # __unicode__ on Python 2
return self.service_name
Just to answer the original question as well.
If you for some reason don't want a database relation between the models, you could convert the querysets to lists and zip them in the view, turning the querysets to a list of tuples.
view:
return render_to_response(
'services/display_services.html',
context_instance={
'user': request.user,
'services_and_ratings': zip(
services.all(),
rating_values.all()
)
}
)
template:
{% for service, rating in services_and_ratings %}
<p> {{ service.service_name }} : {{ rating.rating_average }} </p>
You can establish the relationship right in the model.
class Rating(models.Model):
service= models.OneToOneField(Service, primary_key=True)
service_name= models.CharField(max_length=200)
number_of_ratings = models.IntegerField()
total_rating_value = models.IntegerField()
rating_average = models.FloatField()
....
You can then pass services and get the corresponding ratings..
{% for service in services %}
<p> {{service.service_name}} : {{ service.rating.rating_average }} </p>