I'd like to filter an object in Django, and return it along with any objects for which the results are a ForeignKey. I'm not sure if annotation is what I need here, or something else.
This is my model:
class Dress(models.Model):
name = models.CharField(...)
price = models.FloatField(...)
class ClothingSize(models.Model):
code = models.CharField(...)
class DressSizeAvailable(models.Model):
dress = models.ForeignKey(Dress)
size = models.ForeignKey(ClothingSize)
Say I want to filter all dresses under $50, and then display them with the available sizes. What is the best way to do this?
I've got as far as this:
# In view
results = Dress.objects.filter(price__lt=50)
# How to annotate with available sizes?
# In template
{% for result in results %}
{{ result.name }}, ${{ result.price }}
Sizes: {{ ??? }}
{% endfor %}
### 1st solution (similar to Daniel Rosenthal's answer but with performances concern)
results = DressSizeAvailable.objects.filter(dress__price__lt=50).select_related('dress', 'size')
# then you can browse your DressSizeAvailables as you wish in your template. The select related allows you NOT TO query the database again when you generate your template
### 2nd solution
results = Dress.objects.filter(price__lt=50).prefetch_related('dresssizeavailable_set__dress')
{% for dress in results %}
{{ dress.name }}, ${{ dress }}
Sizes: <ul>
{% for dsa in dress.dresssizeavailable_set %}
<!-- Thanks to the prefetch_related, we do not query the base again here -->
<li>{{ dsa.size.code }}</li>
{% endfor %}
</ul>
{% endfor %}
You'll need to give your template a queryset (or something similar) of DressSizeAvailable objects. So first you'll need to get all the Dress objects you're interested, and then filter DressSizeAvailable based on those Dresses
so in your view:
dresses = Dress.objects.filter(price__lt=50)
dress_size_available = []
for dress in dresses:
available = DressSizeAvailable.objects.filter(dress=dress)
dress_size_available.append(available)
Then render your template, passing it the variable dress_size_available
Your template can then be rather simple.
{% for dsa in dress_size_available %}
{{ dsa.dress.name }}, ${{ dsa.dress.price }}
Size: {{ dsa.size }}
{% endfor %}
Related
Models:
class House(Model)
class Flat(Model):
house = ForeignKey(House, related_name="houses")
owner = ForeignKey(User)
class User(Model)
queryset:
queryset = User.objects.prefetch_related(
Prefetch("flats", queryset=Flat.objects.select_related("houses"))
And then flats:
{% for flat in user.flats.all %}
<p>№ {{ flat.number }}, {{ flat.house.name }}</p>
{% endfor %}
It's fine. But for houses I need only unique ones
{% for flat in user.flats.all %}
<p>House {{ flat.house.name }}</p>
{% endfor %}
But this template gives me ALL houses, with duplicates.
How can I avoid duplicates, any ideas? I tried .distinct() but it's dosen't work, looks like I using distinct() wrong or etc.
It seems you may end up with duplicate houses if a user is the owner of multiple flats, which are all in the same house. To get all houses that the user is related to via Flats, you can use a different query, starting with House so that you can use distinct:
distinct_houses = House.objects.filter(flats__owner=user).distinct()
The above returns one House object for each flat where the user is an owner, and makes sure you don't have duplicates. (Note that the above assumes the related_name is changed to flats for house = ForeignKey(House, related_name="flats"), since "houses" as the related_name seems like a typo to relate back to the Flat model.)
Alternatively, you could do something in-memory in Python, if you still also need to know all Flats via your original queryset = User.objects.prefetch_related(...) and don't want an additional query. Like:
distinct_houses = {flat.house for flat in user.flats.all()}
Side note: it looks like you have a typo in needing to use Flat.objects.select_related('house') rather than Flat.objects.select_related('houses') based on the Foreign Key field name being house.
Only found solution with template filters.
Queryset:
queryset = User.objects.filter(status="ACTIVE").prefetch_related(
Prefetch("flats", queryset=Flat.objects.select_related("house"))
)
With this I can get all flats for each user:
{% for user in object_list %}
{% for flat in user.flats.all %}
{{ flat.number }}, {{ flat.house.name }}
{% endfor %}
{% endfor %}
And I am using template filter to get unique houses.
{% for user in object_list %}
{% for flat in user.flats.all|get_unique_houses %}
{{ flat.house.name }}
{% endfor %}
{% endfor %}
# extra_tags.py
#register.filter(name="get_unique_houses")
def get_unique_houses(value):
return value.distinct('house')
I have 3 models what create a data hierarchy: Brand, Family, Car. In displaying the DetailView for the Brand, I have a table with a Brand's families (foreignkey) and in that table, I then have a property for num_cars to display the number of cars with a foreignkey back to that family.
Example:
Brand:Ford
Families:
Taurus 150
F150 100
F250 0
This is displayed in my template as:
{% for family in brand.families.all %}
{{ family }} {{ family.num_cars }}
{% endfor %}
Is there a way to filter the families by the number of cars so I don't see results where there are 0 cars? I can do this in the template with:
{% for family in brand.families.all %}
{% if family.num_cars > 0 %}
{{ family }} {{ family.num_cars }}
{% endif %}
{% endfor %}
However that doesn't seem like the ideal solution. I'd like to have this in my models (if possible). Any ideas?
You can achieve this kind of behavour with custom managers in Django.
https://docs.djangoproject.com/en/1.10/topics/db/managers/
for example
class FamilyWithCarManager(models.Manager):
def get_query_set(self):
return super(FamilyWithCarManager, self).get_query_set().filter(num_cars__gte=0)
and then in your Family model:
class Family(models.Model):
name = models.CharField(max_length=50)
with_cars = FamilyWithCarManager()
then you should be able to write a query like this:
Family.with_cars.all()
You can add a method get_families to your model Brand
class Brand(models.Model):
title = models.CharField()
def get_families(self):
return self.families.filter(num_cars__gt = 0)
And then do something like this in your views.
{% for family in brand.get_families %}
{{ family }} {{ family.num_cars }}
{% endfor %}
I am trying to get access to the instances of a ModelChoiceField to render them the way I want in a template by displaying several fields of the instances.
class MyForm(forms.Form):
mychoices = forms.ModelChoiceField(
queryset=ObjectA.objects.all(), widget=forms.RadioSelect(), empty_label=None
)
This does not work:
{% for choice in form.mychoices %}
{{ choice.pk}}
{% endfor %}
I also tried to use the queryset but it does not render anything
{% for choice in form.mychoices.queryset %}
{{ choice.pk}}
{% endfor %}
Any idea?
Thanks
{% for choice in form.mychoices.field.queryset %}
{{ choice.pk }}
{% endfor %}
Notice the extra .field. It's a bit strange the first time you come across it, but it gives you what you want. You can also access the choices attribute of that object, instead of accessing queryset directly, but you'll need to access the first element of the choice to get the PK of the instance, like this:
{% for choice in form.mychoices.field.choices %}
{{ choice.0 }}
{% endfor %}
I have a model like
class Document(models.Model):
comment = models.TextField(null=True,blank=True)
upload_date = models.DateTimeField(blank=False)
Document objects are listed in a template as
{% for doc in doc_list %}
{{ doc.comment }}
{{ doc.upload_date }}
{% endfor %}
However, I'd like to reach the properties of doc dynamically like
{{ doc."comment" }}
or
{{ doc|getField:"comment" }}
How can I do that?
Thanks
I assume you mean you want to access fields on a model by using another variable, which you don't necessarily know at the time. So you might have some_var be passed into the template, and this is the field in the model that you'd like to display, such as comment or upload_date.
You could build a template tag to do this:
#register.simple_tag
def get_model_attr(instance, key):
return getattr(instance, key)
Now in your template you can do stuff like:
{% for doc in doc_list %}
{% get_model_attr doc "comment" %}
{% get_model_attr doc some_var %}
{% endfor %}
in my views.py i obtain 5 dicts, which all are something like {date:value}
all 5 dicts have the same length and in my template i want to obtain some urls based on these dicts, with the common field being the date - as you would do in an sql query when joining 5 tables based on a common column
in python you would do something like:
for key, value in loc.items():
print key, loc[key], ctg[key], sctg[key], title[key], id[key]
but in django templates all i could come up with is this:
{% for lock, locv in loc.items %}
{% for ctgk, ctgv in ctg.items %}
{% for subctgk, subctgv in subctg.items %}
{% for titlek, titlev in titlu.items %}
{% for idk, idv in id.items %}
{% ifequal lock ctgk %}
{% ifequal ctgk subctgk %}
{% ifequal subctgk titlek %}
{% ifequal titlek idk %}
<br />{{ lock|date:"d b H:i" }} - {{ locv }} - {{ ctgv }} - {{ subctgv }} - {{ titlev }} - {{idv }}
.... {% endifequals & endfors %}
which of course is ugly and takes a lot of time to be rendered
right now i am looking into building a custom tag, but i was wondering if you guys have any feedback on this topic?
Sounds to me like you need to use something other than aligned dicts. How about a dict of a small class, which contains the things you want:
class MyThing:
def __init__(self, loc, ctg, sctg, title, id):
self.loc = loc
self.ctg = ctg
self.sctg = sctg
self.title = title
self.id = id
Would that make your template code a bit less painful? (Apologies if I've misunderstood the problem - I'm having a hard time following your nested ifs!).
Django templates should try to resolve variables with dot as a dictionary lookup (if varaible is an dictionary). So ctg.key equals to ctg[key]. Did you try this:
{% for key, value in loc.items %}
{{ key|date:"d b H:i" }} - {{ value }} - {{ ctg.key }} - {{ subctg.key }} - {{ title.key }} - {{ id.key }}