compare two model instances for equality - python

I know this might sound stupid, but I have looked across the documentation as well as the similar questions and tried everything to no avail. I am missing out on something very fundamental in django I guess.
Here are my model definition
class myModel(models.Model):
CLIENT_ID=models.CharField(max_length=5, blank=True)
PROFILE_PICTURE = ImageField()
other fields...
class myNewModel(models.Model):
CLIENT_ID=models.CharField(max_length=5, blank=True)
more fields.. etc
The CLIENT_ID is supposed to hold a numeric value mostly.
Now in my templates I have to pull out the PROFILE_PICTURE from objects of myModel when the CLIENT_IDs of the two objects match.
What I am trying to do is similar to
{% for users in top %}
{% for client in clients %}
{% if users.instance.CLIENT_ID == client.instance.CLIENT_ID %}
<tr>
<th>{{users.CLIENT_ID}}</th>
<th><img src="{{ users.PROFILE_PICTURE.url }}" style="width:auto;height:25px" /></th>
{% endif %}{% endfor %}
{% endfor %}
Where top is an array of objects of myModel, and clients is an array of objects of myNewModel.
In my views.py I have extracted all objects of the models and I am getting other details fine.
Is that a right way of comparing ?
Please help.

The general syntax for optional/conditional elements in Django templates:
{% if condition %}
<element />
{% endif %}
where my_model_instance.CLIENT_ID == my_new_model_instance.CLIENT_ID should be a valid condition.

Related

Django display table in templates

I am using Django 2.0.1, and I have the following code:
Models.py:
class Category(models.Model):
category_name = models.CharField(max_length=50)
class CategoryItems(models.Model):
category_name = = models.ForeignKey(Categories, related_name='categoriesfk', on_delete=models.PROTECT)
item_name = models.CharField(max_length=50)
item_description = models.CharField(max_length=100)
Thereafter my views.py:
def data(request):
categories_query = Categories.objects.all()
category_items_query = CategoriesItems.objects.all()
return render_to_response("data.html",
{'categories_query': categories_query,'category_items_query': category_items_query}
In the template I'm trying to display all items for each category, for example, suppose there are 4 categorizes, e.g. Bicycle, then it display all items belonging to that category only. For example, as follows:
Category 1:
Category_Item 1,
Category_Item 2,
Category_Item 3,
and so on ...
Category 2:
Category_Item 1,
Category_Item 2,
Category_Item 3,
and so on ...
I have tried to write so many different for-loops, but they just display all items, I need it to show items only for that category, then for loop to next category and show items for that.
You don't need your category_items_query variable, just category_query:
{% for category in category_query %}
<b>{{ category.category_name }}</b><br />
{% for item in category.categoriesfk.all %}
{{ item.item_name }}<br />
{% endfor %}
{% endfor %}
Your related_name of categoriesfk is weird, it'd make more sense to be something like items.
What you need is two for loops with an if to check if the second loop should belong to the first.
Try this:
{% for category in categories_query %}
{% for category_item in category_items_query %}
{% if category_item.category_name == category %}
{# do something with category_item #}
{% endif %}
{% endfor %}
{% endfor %}
I believe it would be more clear if you named the ForeignKey in CategoryItems to just "category", instead of "category_name", since this field will have the category itself, not just it's name. Your "if" would then be more readable and make more sense:
{% if category_item.category == category %}
Hope it helps.
A few things,
Since your model name is already Category, your field names should be like name instead of category_name.
Model names must be singular, so it should beCategoryItem instead of CategoryItems
When you do a model_name.objects.all(), you do not get a query but a Queryset, make your variable names such that they describe what they do. Currently, categories_query is wrong. You could instead use category_qs.
Now, coming to your question, you require two for loops. One to loop through the categories and then one to loop through items in a particular category.
Something like,
for category in category_qs:
for item in category:
# Do something with item
You have the basic idea here, now you can convert it to real working code. Good luck!
Grouping data in template is not best idea as template should be logic free,
also good idea would be to use database capabilities and use select_related to query out related set
category_data = Category.objects.select_related('item').all()
afterwards you could do following in template
{% for category in category_data %}
{# print category #}
{% for item in category.items %}
{# print item #}
{% endfor %}
{% endfor %}
Django has a built-in regroup template tag for this functionality.
{% regroup category_items_query by category_name as categoryname_list %}
{% for category in categoryname_list %}
<strong>{{ category.grouper }}</strong><br>
{% for item in category.list %}
{{ item.item_name }}: {{ item.item_description }}<br>
{% endfor %}
{% endfor %}
You have to order your CategoryItems for this functionality to work.
category_items_query = CategoriesItems.objects.all().order_by('category_name')

How to filter BooleanField in template in Django?

I am preparing a image gallery for my website using Django . I have basically a Gallery Model Foreign Key in my Image Model. I have a BooleanField in my Image model to make a cover photo.
What I need is to get True value for the one in between images.
{% for gallery in gallery_list %}
<div class="grid-item {{ choices | random }}">
</div>
{% endfor %}
I checked the documents for custom filters trying to solve but I could not figure out. Can you help me ?
Thanks
Ps Edit: adding my models
class Gallery(models.Model):
title = models.CharField(max_length=200,verbose_name=_("gallery_title"),help_text _("Enter the Gallery title"))
class Image(models.Model):
title = models.CharField(max_length=200,verbose_name=_("image_title"),help_text _("Enter the Image title"))
gallery = models.ManyToManyField(Gallery)
is_cover_photo = models.BooleanField()
You could write a method in Gallery model to return you a cover image:
class Gallery(models.Model):
# other fields
def cover_image(self):
return self.image_set.filter(is_cover_photo=True).first()
Then in template:
{% for gallery in gallery_list %}
{% with cover=gallery.cover_image %}
{% if cover %}
{# do something with cover image #}
{% endif %}
{% endwith %}
{% endfor %}
It's good to keep complex logic like this outside of your templates to avoid them getting too complicated. Save it for the views and/or models!
Sounds like the best bet here would be to have a method on your Gallery model to get the Image that has the cover image. Something like:
class Gallery
...model fields...
def get_cover_image(self):
return self.images_set.filter(cover_photo=True).first()
Then in your template, assuming the Image model has a property like url:
{% for gallery in gallery_list %}
<div class="grid-item {{ choices | random }}">
</div>
{% endfor %}
To save lots of DB queries here you might need/want to use prefetch_related to get all the Image objects you'll need to display the galleries, but that's a different question.

Include tag in Django template language -- what can I pass in to it?

OK, so again there is likely a "simple" solution to this, but I am a beginner and nothing seems simple to me.
I have a view and a template that shows the attributes of an instance of a Car class that I have modeled. This Car class has a ManyToMany relationship with my custom User class. The template that show the attributes of a given instance of Car has many variables. The view for each Car works fine. Here is what I can't get to work:
I have a user profile page for each instance of User. From that page, I want to show the attributes of each Car that a particular User has "favorited." I am unable to figure out how to do this.
I have tried the {% include %} tag to include a snippet of the Car template and then use a for statement to iterate through the favorite set of the User. In theory, this would populate the User page with each Car that they have "favorited" and show its attributes. However, I do not know how to pass the {% include %} tag the proper context so the attributes are populated correctly for each instance of Car. Is this possible?
Is there a simpler way to do it that I am just overlooking?
Any help is appreciated. Thanks!
Use the {% include ... with ... %} syntax:
{% for car in user.favorite_cars.all %}
{% include "car.html" with name=car.name year=car.year %}
{% endfor %}
Another alternative is the {% with %} tag:
{% for car in user.favorite_cars.all %}
{% with name=car.name year=car.year %}
{% with color=car.color %}
{% include "car.html" %}
{% endwith %}
{% endwith %}
{% endfor %}
UPDATE: If data for the template can't be obtained from the Car model then you have to use the custom inclusion tag:
from django import template
register = template.Library()
#register.inclusion_tag('car.html')
def show_car(car):
history = get_history_for_car(car)
return {'name': car.name, 'history': history}
And the in the template:
{% load my_car_tags %}
{% for car in user.favorite_cars.all %}
{% show_car car %}
{% endfor %}

Show image of a Model in views Django Python

I am developing an application with Python Django and I'm new to it, in models.py I have
class SubTypeModel(models.Model):
importance = models.IntegerField()
name = models.CharField(max_length=70)
description = models.CharField(max_length=200)
class SubTypeModelImage(models.Model):
subType = models.ForeignKey(SubTypeModel)
image = models.ImageField(upload_to = "static/images/subtypemodels")
The admin.py is set properly and I can insert SubType with 3 different photos for each in database and photos are stored properly as well
The issue is started when I need to show them in template in the template.html file I have
{% for subType in all_subTypes %}
<li>
{{ subType.name }}
</li>
{% endfor %}
This can show the name of all the subType in database but I really have no idea how to show its photos as well
please help me how to add photos to view
in the views.py my query is like this :
list_models = SubTypeModel.objects.all();
Thanks in advance
{% for subType in all_subTypes %}
<li>
{{ subType.name }}
{% for image in subType.subtypemodelimage_set.all %}
<img src="{{ image.image.url }}" />
{% endfor %}
</li>
{% endfor %}
You can change subtypemodelimage_set to something nicer (like 'images') by setting the related_name argument on the foreign key field.
See https://docs.djangoproject.com/en/dev/ref/models/fields/#django.db.models.ForeignKey.related_name

Django and models with multiple foreign keys

I am new to Django and I've been impressed so far by its capabilities. I am playing with more complex models and I am have problem to use them properly. Using Django 1.3, I am trying to write a summary page which would present the three models below with the following structure. In other words, a list of trips with their destinations and activities.
Trip 1
Destination 1
Destination 2
Activity 1
Trip 2
Destination 1
Activity 2
Models
Trip <-> TripDestination <-> Destination (a trip can have multiple destinations)
Activity -> Trip, Activity -> Destination (an activity is defined for a trip at a specific location/destination)
class Destination(models.Model):
city_name=models.CharField()
class Trip(models.Model):
departing_on=models.DateField()
returning_on=models.DateField()
destinations=models.ManyToManyField(Destination)
class Activity(models.Model):
destination=models.ForeignKey(Destination, null=False)
trip=models.ForeignKey(Trip, null=False)
I am trying to write a view which would generate a page with the structure presented above. The main problem I am having right now is to display the activities for a specific trip and destination. As you can see in the code below, I am building a dictionary and I doubt it is the right thing to do. In addition, the view becomes
View
def list_trip(request, template_name = 'trip-list.html'):
trips = Trip.objects.all()
# Build a dictionary for activities -- Is this the right thing to do?
activities = Activity.objects.filter(trip__in=trips)
activities_by_trips = dict()
for activity in activities:
if activity.trip_id not in activities_by_trips:
activities_by_trips[activity.trip_id] = dict()
if activity.destination_id not in activities_by_trips[activity.trip_id]:
activities_by_trips[activity.trip_id][activity.destination_id] = []
activities_by_trips[activity.trip_id][activity.destination_id].append(activity)
return render_to_response(template_name, {
'page_title': 'List of trips',
'trips': trips,
'activities_by_trips': activities_by_trips,
})
Template
{% block content %}
{% for trip in trips %}
{{ trip.id }} - {{ trip.name }}
{% for destination in trip.destinations.all %}
{{ destination.city_name }}
** This is terrible code -- How to fix that **
{% for key, value in activities_by_trips|dict_lookup:trip.id %}
{% if value %}
{% for key_prime, value_prime in value|dict_lookup:destination.id %}
{{ value_prime.description }}
{% endfor %}
{% endif %}
{% endfor %}
{% endfor %}
{% endfor %}
{% endblock %}
In brief, can someone please help me to get a summary of all the trips and activities? What's the best way to accomplish that? Is the model correct?
Thanks!
There is plenty of room for improvement. By using through on ManyToManyField you can explicitly define the join table, which we can conveniently consider as a single visit to a city during a particular trip. During that visit we had activities, so activity should have a foreignkey to a visit.
For each foreignkey in a table, Django will add API convenience manager for sets of objects on the opposite side of the relationship. Destination will have a visit_set, but so will Trip. Similarly, because of visit foreignkey in Activity each visit will have an activity_set.
First start with the models:
from django.db import models
# Create your models here.
class Destination(models.Model):
city_name=models.CharField(max_length=50)
class Trip(models.Model):
departing_on=models.DateField()
returning_on=models.DateField()
destinations=models.ManyToManyField(Destination, through='Visit')
class Visit(models.Model):
destination=models.ForeignKey(Destination)
trip=models.ForeignKey(Trip)
class Activity(models.Model):
name=models.CharField(max_length=50)
visit=models.ForeignKey(Visit)
Then lets change list_trip a bit, added print_trip for clarity of what is going on in template:
def list_trip(request, template_name = 'trip-list.html'):
return render_to_response(template_name, {
'page_title': 'List of trips',
'trips': Trip.objects.all(),
})
def print_trips():
for trip in Trip.objects.all():
for visit in trip.visit_set.select_related().all():
print trip.id, '-', visit.destination.city_name
for act in visit.activity_set.all():
print act.name
And finally the improved template:
{% block content %}
{% for trip in trips %}
{{ trip.id }} - {{ trip.name }}
{% for visit in trip.visit_set.select_related.all %}
{{ visit.destination.city_name }}
{% for act in visit.activity_set.all %}
{{ act.name }}
{% endfor %}
{% endfor %}
{% endfor %}
{% endblock %}
There is still some more room for improvement performance wise. Notice I used select_related. That will prefetch all destinations at the time visits are fetched, so that visit.destination.city_name will not incur another db call. However this doesn't work for reverse ManyToMany relationships (in our case all members of activity_set). Django 1.4 will come out with new method called prefetch_related which will resolve that as well.
In the mean time, read up on Efficient reverse lookups for an idea how to even further reduce the number of DB hits. In the comments few readily available solutions are mentioned as well.

Categories