I have two apps related in a Many-To-Many relationship, Recipes and Tags, and I'm having trouble at retrieving a query of Tags having image != null and the Recipes that are currently PUBLISHED.
Recipe app: recipes/models.py
from django.db import models
from django.contrib.auth.models import User
from tags.models import Tag
DRAFT = 'D'
PUBLISHED = 'P'
RECIPE_STATES = (
(DRAFT, 'Draft'),
(PUBLISHED, 'Published')
)
class Recipe(models.Model):
owner = models.ForeignKey(User, on_delete=models.CASCADE)
title = models.CharField(max_length=100, unique=True)
date_created = models.DateField(auto_now_add=True)
date_modified = models.DateField(auto_now=True)
state = models.CharField(max_length=1, choices=RECIPE_STATES)
ingredients = models.TextField(blank=True)
introduction = models.TextField(blank=True)
preparation = models.TextField(blank=True)
tip = models.TextField(blank=True)
rating = models.IntegerField(blank=True)
diners = models.IntegerField(blank=True)
tags = models.ManyToManyField(Tag, blank=True)
def __str__(self):
return self.title
And the Tag app: tags/models.py
from django.db import models
class Tag(models.Model):
name = models.CharField(max_length=50, unique=True)
image = models.ImageField(blank=True, null=True, upload_to='categories')
def __str__(self):
return self.name
recipes/views.py:
class HomeView(View):
def get(self, request):
queryset = Recipe.objects.filter(state=PUBLISHED)
last_recipes = queryset.order_by('-date_created')
top_recipes = queryset.order_by('-rating')
categories = Tag.objects.filter(image__isnull=False, recipe__state=PUBLISHED)
context = {
'last_recipes': last_recipes[:4],
'top_recipes': top_recipes[:4],
'categories': categories
}
return render(request, 'recipes/home.html', context)
When I try to retrieve that query from the views.py in home.html:
<div class="row">
<div class="col-xs-12 col-sm-12 col-md-12">
{% for category in categories %}
<a href="{% url 'category_recipes' category.name %}">
<div class="col-xs-6 col-sm-4 col-md-3 text-center">
<h3>{{ category.name }}</h3>
<img src="{{ category.image.url }}" alt="{{ category.name }}" height="100">
</div>
</a>
{% endfor %}
</div>
</div>
I'm getting this error:
ValueError at /
The 'image' attribute has no file associated with it.
I also have the tags populated with data:
Check, that Tag with id=20 not have '' (empty string) as value. You exclude only null values, but empty string is not checked.
I finally get it working using:
categories = Tag.objects.filter(image__isnull=False, recipe__state=PUBLISHED).distinct()
Now, categories in home.html is provided with data, and I'm not having trouble using category.image.url.
Related
I'd appreciate your help. I have two models. In the Bids model you will find current_bid_cmp. I would like from the ListingAuctions model to be able to access the corresponding current_bid_cmp of the Bids model. I only have found information to do querys from the model which contains the foreingKey.
My view: I use get_context_data because I have been trying anothers querys. perhaps its not the more aproppiate
class index(ListView):
model = ListingAuctions
template_name = "auctions/index.html"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['object'] = ListingAuctions.objects.all()
return context
My Models:
class ListingAuctions(BaseModel):
title_auction = models.CharField('Title of the auction',max_length = 150, unique = True)
description = models.TextField('Description')
user = models.ForeignKey(User, on_delete = models.CASCADE)
category = models.ForeignKey(Category, on_delete = models.CASCADE)
initial_bid = models.FloatField(default=False)
content = models.TextField('Content of auction')
image = models.ImageField('Referential Image', null=True,
upload_to = 'images_auctions', max_length = 255, default= 'noimage.png')
class Bids(BaseModel):
user = models.ForeignKey(User, on_delete = models.CASCADE, related_name='offer_user')
listing_auctions = models.ForeignKey(ListingAuctions,null=True, on_delete= models.CASCADE, related_name='l_auctions')
initialized_bid = models.BooleanField(default=False)
current_bid_cmp = models.FloatField('Current Bid Cmp',blank=True, null=True )
offer = models.FloatField(default=0 ,null=True, blank=True)
My HTML Current bid: $ {{post.l_auctions.current_bid_cmp}} its my attemp l_auctions is the relate name from listing_auctions in Bids model. Post is a ListingAuction object:
{% for post in object_list %}
<div class=" col-md-4 mt-4 ">
<div class="card " style="width: 18rem;">
<a href="{% url 'auctions_detail' post.pk %}">
<img class="card-img-top img-fluid" src="{{ post.image.url }}" alt="Card image cap" >
</a>
<div class="card-body">
<a class="darklink" href="{% url 'auctions_detail' post.pk %}"> <h5 class="card-title">{{post.title_auction}}</h5></a>
<h5>Starting bid: $ {{post.initial_bid}}</h5>
<h5>Current bid: $ {{post.l_auctions.current_bid_cmp}}</h5>
<p class="card-text">{{post.content | truncatechars:700 }}</p>
Show Auction
</div>
</div>
</div>
{% endfor %}
Try this in your template:
{{ post.l_auctions.get.current_bid_cmp }}
Update
I modified your models a bit so they make more sense to me. You might need your BaseModel for a good reason so feel free to modify to your needs. I also changed some names. There's still things I see that don't make a lot of sense in them but I'll leave that to you.
models.py
from django.db import models
from django.conf import settings
class BaseModel(models.Model):
pass
class Category(models.Model):
name = models.CharField(max_length=20)
class Listing(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
category = models.ForeignKey(Category, on_delete=models.CASCADE)
title = models.CharField('Title of the auction', max_length=150, unique=True)
description = models.TextField('Description')
starting_bid = models.FloatField(default=False)
content = models.TextField('Content of auction')
image = models.ImageField('Referential Image', null=True,
upload_to='images_auctions', max_length=255, default='noimage.png')
def __str__(self):
return self.title
class Bid(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='offer_user')
listing = models.ForeignKey(Listing, null=True, on_delete=models.CASCADE, related_name='bids')
initialized_bid = models.BooleanField(default=False)
amount = models.FloatField('Current Bid', blank=True, null=True)
offer = models.FloatField(default=0, null=True, blank=True)
def __str__(self):
return str(self.amount)
class Meta:
get_latest_by = 'amount'
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{% for listing in object_list %}
<div class=" col-md-4 mt-4 ">
<div class="card " style="width: 18rem;">
<a href="#">
<img class="card-img-top img-fluid" src="{{ listing.image.url }}" alt="Card image cap">
</a>
<div class="card-body">
<a class="darklink" href="#">
<h5 class="card-title">{{ listing.title }}</h5></a>
<h5>Starting bid: $ {{ listing.starting_bid }}</h5>
<h5>Current bid: $ {{ listing.bids.latest }}</h5>
<p class="card-text">{{ listing.content | truncatechars:700 }}</p>
Show Auction
</div>
</div>
</div>
{% endfor %}
</body>
</html>
Here's an interactive session from a shell:
from django.contrib.auth import get_user_model
User = get_user_model()
admin = User.objects.get_or_create(username='admin')[0]
steve = User.objects.get_or_create(username='steve')[0]
jenny = User.objects.get_or_create(username='jenny')[0]
almond = User.objects.get_or_create(username='almond')[0]
from auctions.models import Category, Listing, Bid
c = Category.objects.get_or_create(name='General')[0]
l1 = Listing.objects.get_or_create(user=admin, category=c, title='Some title', description='description', starting_bid=1.00, content='content')[0]
b1 = Bid.objects.get_or_create(user=steve, listing=l1, amount=1.00)[0]
b2 = Bid.objects.get_or_create(user=jenny, listing=l1, amount=1.01)[0]
b3 = Bid.objects.get_or_create(user=almond, listing=l1, amount=1.02)[0]
>>> l1.bids.all()
<QuerySet [<Bid: 1.0>, <Bid: 1.01>, <Bid: 1.02>]>
You could get the max by:
Adding this to your class:
class Meta:
get_latest_by = 'amount'
and using listing.bids.latest()...
Or using aggregate:
from django.db.models import Max
>>> l1.bids.aggregate(max=Max('amount'))
{'max': 1.02}
The key thing to note is, listing.bids returns a "RelatedManager". This just means you can use familiar queryset methods like .all(), .get(), .filter(), .last(), .latest(), etc. Many more.
In your case, you should first review this article on how to get the max of a queryset. Then decide how you want to proceed. In the example above, I put a class Meta on the Bid model which lets you get the latest object back based on the amount. This assumes the latest amount is always the highest, which might not be true for your situation.
One other thing you could do is add a #property to your Listing model.
class Listing(models.Model):
...
#property
def max_bid(self):
from django.db.models import Max
max_bid = self.bids.aggregate(max=Max('amount'))
if max_bid.get('max'):
return max_bid['max']
return ""
Use in your template like this:
<h5>Current bid: $ {{ listing.max_bid }}</h5>
Use in your Jinja Template
{{object_list.0.l_auctions.current_bid_cmp}}
I am attempting to display a list of items for auction. For each item, I am wanting to also display the current bid price. The current bid price should be the max value or last added to the Bids class for each individual listing.
How do I render in my HTML the max Bid.bid_price for each item in my Listing.objects.all() collection?
Below are my models, views, and HTML.
Models:
class Listing(models.Model):
title = models.CharField(max_length=65, default="")
description = models.CharField(max_length=200, default="")
category = models.CharField(max_length=65, default="")
image = models.ImageField(blank=True, null=True, upload_to='images/')
listed_by = models.ForeignKey(User, on_delete=models.CASCADE, default="")
created_dt_tm = models.DateTimeField(auto_now_add=False, default=timezone.now())
class Bids(models.Model):
bidder = models.ForeignKey(User, on_delete=models.CASCADE, default="")
listing = models.ForeignKey(Listing, on_delete=models.CASCADE, default="", related_name="bids")
bid_price = models.IntegerField(default=0)
created_dt_tm = models.DateTimeField(auto_now_add=False, default=timezone.now())
Views:
def index(request):
return render(request, "auctions/index.html", {
"listings": Listing.objects.all()
})
HTML:
{% for listing in listings %}
<div style=display:flex;margin:30px;border:lightseagreen;border-style:solid;height:150px;border-width:1px;width:40%>
<div style=width:25%;display:flex;>
{% if listing.image %}
<img src="{{listing.image.url}}" alt="Cannot display image" height="100px" style="margin-left:50px;">
{% endif %}
</div>
<div style=width:15%></div>
<div style=width:30%>
<div>{{listing.title}}</div>
<div style=font-size:10pt;>Description: {{listing.description}}</div>
<div style=font-size:10pt;>Category: {{listing.category}}</div>
<div style=font-size:10pt;>Current Price: ${{ listing.bids_object.bid_price }}</div>
<div style=font-size:10pt;>Created by:<br>{{listing.listed_by}}</div>
</div>
<div style=width:30%>
<div style=margin:10px;>
</div>
</div>
</div>
{% endfor %}
{% endblock %}
what you need is django's annotate functionality to find the max of each Listing.
from django.db.models import Max
def index(request):
return render(request, "auctions/index.html", {
"listings": Listing.objects.all().values().annotate(
max_bid_amount = Max('bids__bid_price')
)
})
in your html you can then add following line for max_bid.
<div style=font-size:10pt;>Max Bid Amount:<br>{{listing.max_bid_amount}}</div>
I have a model Log and another model Solutions and I am using DetailView to display details of each log
Each log can have many solutions.
There is a log field in the Solutions model that is Foreign Key to Log model..
Now how do I access both Log model and Solutions of that particular log in the same html template if I want to display all the solutions of that particular log below the details of the log
models.py:
class Log(models.Model):
title = models.CharField(blank=False, max_length=500)
content = models.TextField(blank=False)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
slug = models.SlugField(max_length=50, null=False, unique=True)
author = models.ForeignKey(User, on_delete=models.CASCADE,null=True, blank=True)
image = models.ImageField(
upload_to='images', blank=True)
def save(self, *args, **kwargs):
super().save()
self.slug = self.slug or slugify(self.title + '-' + str(self.id))
super().save(*args, **kwargs)
class Meta:
verbose_name = ("Log")
verbose_name_plural = ("Logs")
def __str__(self):
return f"{self.title}"
def get_absolute_url(self):
return reverse("log-detail", kwargs={"question": self.slug})
class Solutions(models.Model):
log = models.ForeignKey(
Log, on_delete=models.CASCADE, blank=True, null=True)
author = models.ForeignKey(User, on_delete=models.CASCADE,null=True, blank=True)
solution = models.TextField(null=True)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
slug = models.SlugField(max_length=50, null=False, blank=True)
image = models.ImageField(
upload_to='images', blank=True)
def save(self, *args, **kwargs):
self.slug = self.slug or slugify(self.solution)
super().save(*args, **kwargs)
class Meta:
verbose_name = ("Solution")
verbose_name_plural = ("Solutions")
def __str__(self):
return f" {self.solution} "
views.py:
class LogDetailView(DetailView):
model = Log
slug_url_kwarg = 'question'
slug_field = 'slug'
log_detail.html:
{% extends 'log/base.html' %}
{%load crispy_forms_tags %}
{% block content %}
<title>Error Logger - {{object.title}}</title>
<div class="main container mt-4 p-3 mb-4">
<img style='display:inline;' class='rounded-circle account-img' src="{{ object.author.profile.avatar.url }}" alt="">
<h1 style='display:inline;'>
{{ object.title }}
</h1>
<p>Author: {{ object.author }}</p>
<p>Date and time of creation: {{ object.created }}</p>
<span> Details </span>:
<p class="big ml-4">{{ object.content }} <br />
{% if object.image %}
<img style="width: 20vw" class="mt-4" src="{{ object.image.url }}" alt="image" />
{% else %}
{% endif %}
</p>
</div>
<br />
<a
class="btn btn-outline btn-info button-solution"
href="#"
>Add solution</a
>
You can enumerate over these in the template by accessing the relation in reverse, this is normally modelname_set, unless you set a related_name=…. So in this case it is solutions_set:
{% for solution in object.solutions_set.all %}
{{ solution }}
{% endfor %}
If the ForeignKey has a related_name=… [Django-doc], for example with:
class Solutions(models.Model):
log = models.ForeignKey(
Log,
on_delete=models.CASCADE,
blank=True,
null=True,
related_name='solutions'
)
# …
Then we access this with:
{% for solution in object.solutions.all %}
{{ solution }}
{% endfor %}
Note: normally a Django model is given a singular name, so Solution instead of Solutions.
i am trying to show data from multiple models in one single view and one single template and i succeed with that but i have problem , the problem is posts from android model keep show at first because i have added android first in html page but what i want to do is show posts by date published what should i do
models.py :
class android(models.Model):
name = models.CharField(max_length=50,default="")
slug = models.SlugField(max_length=250,default="")
post_date = models.DateTimeField(auto_now_add=True, null=True, blank=True)
def get_image(self):
if self.app_image and hasattr(self.app_image, 'url'):
return self.app_image.url
else:
return '/path/to/default/image'
def __str__(self):
return self.name
class Meta:
ordering = ('-post_date',)
class PCgames(models.Model):
name = models.CharField(max_length=50,default="")
slug = models.SlugField(max_length=250,default="")
post_date = models.DateTimeField(auto_now_add=True, null=True, blank=True)
def get_image(self):
if self.app_image and hasattr(self.app_image, 'url'):
return self.app_image.url
else:
return '/path/to/default/image'
def __str__(self):
return self.name
class Meta:
ordering = ('-post_date',)
views.py :
def home_page(request):
pcgamesforhome = PCgames.objects.all()
androidforhome = Android.objects.all()
context = {'pcgamesforhome' : pcgamesforhome,'androidforhome' : androidforhome}
return render(request,'html_file/home.html',context=context)
home.html :
<div class="container">
<div class='row'>
{% for android in androidforhome %}
<div class='col-xs-12 col-sm-6 col-md-4 website-thumb'>
<a href="{{ android.slug }}">
<img src="{{ android.get_image }}" class='image_control_for_home_page_pc_games' alt=''> </a>
<h3>{{ android.name }}</h3> </div>
{% endfor %}
</div>
<div class="container">
<div class='row'>
{% for home_page in pcgamesforhome %}
<div class='col-xs-12 col-sm-6 col-md-4 website-thumb'>
<a href="{{ home_page.slug }}">
<img src="{{ home_page.get_image }}" class='image_control_for_home_page_pc_games' alt=''> </a>
<h3>{{ home_page.name }}</h3> </div>
{% endfor %}
</div>
so now what should i do to show posts from all models order by date ?
your database structure is wrong. instead of having two model for android and PC, you can have one model and a field specifying object type with choices
class Foo(models.Model):
Type = (
('android', 'android'),
('pc', 'pc'),
)
name = models.CharField(max_length=50,default="")
slug = models.SlugField(max_length=250,default="")
post_date = models.DateTimeField(auto_now_add=True, null=True, blank=True)
type = models.CharField(max_length=10, choices=Type)
if you like to have a special field for each android or pc, you can create fields with blank and null true attr.
views.py:
# get all of them and order them by creation date
Foo.obejcts.all().order_by('-post_date')
# get android type objects
Foo.objects.filter(type='android')
# get pc type objects
Foo.objects.filter(type='pc')
a basic example would be
class Category(models.Model):
name = models.CharField(max_length=30)
slug = models.SlugField(max_length=50)
def __str__(self):
return self.name
class Post(models.Model):
title = models.CharField(max_length=100)
content = models.TextField(blank=True)
post_date = models.DateTimeField(auto_now_add=True, null=True, blank=True)
slug = models.SlugField(max_length=50)
category = models.ForeignKey(Category, on_delete=models.CASCADE)
def __str__(self):
return self.title
class Meta:
#recent post in top
ordering = ['-post_date']
in views to filter based on category:
pc_games = Post.objects.select_related("category_set").filter(category__name='pc_games')
android = Post.objects.select_related("category_set").filter(category__name='android')
I try to make a simple illustration of my question click to view
I have a task to make a quiz.
I try to solve a problem :
Taking items in cycle by "Metrix" model there I get Questions for Quiz
It is no way to get data from "User_metrix" model while using {% for item in metrix_list %} cycle by "Metrix" model.
My models:
from django.db import models
from django.conf import settings
class Metrix(models.Model):
title = models.CharField(max_length=256, verbose_name='Question')
metrix_category = models.ForeignKey(
'category',
related_name='Question_category',
on_delete=models.CASCADE,
verbose_name='Category',
)
is_published = models.BooleanField(default=False)
def __str__(self):
return self.title
class Category(models.Model):
title = models.CharField(max_length=256,
verbose_name='Question_category')
is_published = models.BooleanField(default=False)
def __str__(self):
return self.title
class User_metrix(models.Model):
user = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
related_name="user_metrix",
verbose_name='User')
metrix = models.ForeignKey('Metrix', on_delete=models.CASCADE,
verbose_name='Question')
value = models.DecimalField(max_digits=12, decimal_places=2,
verbose_name='Value')
My view:
from django.shortcuts import render
from django.contrib.auth.decorators import login_required
from metrix.models import Metrix, User_metrix
#login_required
def metrix_view(request, pk=None):
metrix_category = {
'pk': 4
}
#Get questions by category
metrix_list = Metrix.objects.filter(is_published=True,
metrix_category__pk=pk)
context = {
'metrix_list': metrix_list
}
return render(request, 'metrix/metrix.html', context)
Template:
I list the questions in template, by cycle "metrix_list"
How to save answers to values and if answers exists return values to template?
<!--cycle for metrix-->
{% for item in metrix_list %}
<div class="row metrix_quiestion_line justify-content-center">
<div class="metrix_quiestion">
<h2>
{{ item }}
</h2>
</div>
<div class="metrix_value">
<input type="number" name="{{ item.id }}" value=" ">
</div>
</div>
{% endfor %}
<!--END cycle -->