Django 'ifequal' with string comparisons - python

I currently am trying to compare two strings with an ifequal tag in Django. The current issue is that although the two strings are equal, Django does not run everything inside the if statement.
html
{% for group in groups %}
<h1 class="inverted-popout">{{ group.name }}</h2>
<div class="sheets">
{% for sheet in sheets %}
{% ifequal sheet.sheetGroupValue group.sheetGroupName %} <!-- This is the issue -->
<div class="sheet popout">
<h2><a href="{% url 'sheets:detail' slug='sheet.slug' slug=sheet.slug %}">
{{ sheet.name }} {{ sheet.hitPoints }} / {{ sheet.maxHitPoints }}
</a></h2>
<h3>{{ sheet.sheetGroupValue }}</h3>
<p><i>Lvl {{ sheet.level }} ({{ sheet.xp }})</i></p>
<p>{{ sheet.Class }}</p>
<p>{{ sheet.background }}</p>
<p>{{ sheet.race }}</p>
</div>
{% endifequal %}
{% endfor %}
</div>
{% endfor %}
views.py
def sheetList(request):
sheets = Sheet.objects.all().order_by('name')
groups = SheetGroup.objects.all().order_by('name')
return render(request, 'sheets/sheetList.html', { 'sheets': sheets, 'groups': groups })
models.py
class SheetGroup(models.Model):
name = models.CharField(max_length=50)
def __str__(self):
return self.name
def sheetGroupName(self):
return str(self.name)
class Sheet(models.Model):
author = models.ForeignKey(User, on_delete=models.CASCADE, blank=True, null=True)
name = models.CharField(max_length=100)
sheetGroup = models.ManyToManyField(SheetGroup)
slug = models.SlugField(default="")
# there's a bunch of fields but they do not contribute to the error
def __str__(self):
return self.name
def sheetGroupValue(self):
groups = ''
for group in self.sheetGroup.all():
groups += group.name + " "
return groups
Here is a sheet
Here is a group
And in the end Django says they are not equal (the <div class="sheet popout"> does not appear.
Any and all help would be greatly appreciated.

sheetGroupValue() is currently returning a space at the end, so the two strings aren't equal.
def sheetGroupValue(self):
groups = ''
for group in self.sheetGroup.all():
groups += group.name + " "
return groups[0:len(groups)-1]

Related

Using fields from a aggregated QuerySet in a django template

So I got a QuerySet result from an aggregate function to display in a low-spec eBay clone of mine. But my problem is displaying certain fields in the Django template as I want, for example, I want to display the highest bidder's username and bid. When I call the whole object itself like so {{winner}}, then it displays. But when I try to access its fields like so {{winner.user_id.username}}, I get no output although the QuerySet does execute.
When I try to get a field like so (winner.user_id.username):
When I only call winner:
models.py
from django.contrib.auth.models import AbstractUser
from django.db import models
CATEGORIES = [
('Appliances', 'Appliances'),
('Tech', 'Tech'),
('Gaming', 'Gaming'),
('Fashion', 'Fashion'),
('Sports and Fitness','Sports and Fitness'),
('Other','Other'),
("Hygiene and Medicine","Hygiene and Medicine"),
("Stationery","Stationery"),
('Decor', 'Decor'),
('Furniture','Furniture'),
('Cars and Mechanical Things','Cars and Mechanical Things'),
("Tools","Tools")
]
# Create models here
class User(AbstractUser):
pass
class Auction_Listing(models.Model):
user_id = models.IntegerField(default=1)
list_title = models.CharField(max_length=64)
desc = models.TextField(max_length=600)
img_url = models.URLField(max_length=200, null=True, blank=True)
start_bid = models.IntegerField()
category = models.CharField(choices=CATEGORIES, max_length=35, null=True, blank=True)
active = models.BooleanField(default=True)
def __str__(self):
return f"ID:{self.id}, {self.list_title}: {self.desc}, {self.start_bid} posted by user:{self.user_id} in Category:{self.category}, url:{self.img_url}"
class Bids(models.Model):
user_id = models.ForeignKey('User', on_delete=models.CASCADE)
auctions = models.ForeignKey('Auction_Listing', on_delete=models.CASCADE, default=1,related_name='bidauc')
bid = models.IntegerField()
def __str__(self):
return f"ID:{self.id}, Bid {self.bid} posted by user:{self.user_id} on auction {self.auctions}"
class Auction_Comments(models.Model):
user_id = models.ForeignKey('User', on_delete=models.CASCADE)
comment = models.TextField(max_length=324, default='N/A')
auctions = models.ForeignKey('Auction_Listing', on_delete=models.CASCADE, default=1,related_name='comauc')
def __str__(self):
return f"ID:{self.id}, Comment: {self.comment} posted by user:{self.user_id} on auction {self.auctions}"
class Watchlist(models.Model):
user_id = models.ForeignKey('User', on_delete=models.CASCADE)
auctions = models.ForeignKey('Auction_Listing', on_delete=models.CASCADE, default=1, related_name='watchauc')
def __str__(self):
return f"ID:{self.id}, user:{self.user_id} on auction {self.auctions}"
views.py
def render_listing(request, title):
if request.method == "POST":
form = BidForm(request.POST)
bid = int(request.POST['new_bid'])
listing = Auction_Listing.objects.get(list_title=title)
comments = Auction_Comments.objects.filter(auctions=listing)
if bid <= listing.start_bid:
error = True
else:
error = False
listing.start_bid = bid
listing.save()
new_bid = Bids(user_id=request.user, auctions=listing, bid=bid)
new_bid.save()
return render(request, 'auctions/listing.html', {
"listing": listing,
"form": form,
"comments": comments,
"error": error,
"comform": CommentForm()
})
else:
form = BidForm()
comform = CommentForm()
listing = Auction_Listing.objects.get(list_title=title)
comments = Auction_Comments.objects.filter(auctions=listing)
high_bid = Bids.objects.filter(auctions=listing).aggregate(maximum=Max("bid"))
winner = Bids.objects.filter(auctions=listing, bid=high_bid['maximum'])
print(winner)
return render(request, 'auctions/listing.html', {
"listing": listing,
"form": form,
"comments": comments,
"error": False,
"comform": comform,
"winner": winner
})
template's code:
{% extends "auctions/layout.html" %}
{% load static %}
{% block title %} Listing: {{listing.list_title}} {% endblock %}
{% block body %}
{% if listing.active %}
<h2>{{ listing.list_title }}</h2>
<div class='listing'>
{% if listing.img_url == "" or listing.img_url == None %}
<a href='#'><img src="{% static 'auctions/img404.png' %}" class='img-fluid'></a>
{% else %}
<a href='#'><img src="{{ listing.img_url }}" class="img-fluid" alt='image of {{ listing.list_title }}'></a>
{% endif %}
<p>
{{ listing.desc }}
</p>
<p>
Current Bid: ${{ listing.start_bid }}
</p>
<p>Category: {{ listing.category }}</p>
<p></p>
{% if user.is_authenticated %}
<div class="bid">
<a href='{% url "watch" listing.list_title %}' class='btn btn-primary'>Add to/Remove from Watchlist</a>
{% if listing.user_id == user.id %}
<a href='{% url "close" listing.list_title %}' class='btn btn-primary'>Close Auction</a>
{% endif %}
</div>
<div class="bid">
<h3>Bid:</h3>
<form method="POST" action='{% url "renlist" listing.list_title %}'>
{% csrf_token %}
{{form}}
<button type="submit" class='btn btn-primary'>Make New Bid</button>
{% if error %}
Please enter a bid higher than the current bid.
{% endif %}
</form>
</div>
{% else %}
<p><a href='{% url "register" %}' class='register'>Register</a> to bid on this item and gain access to other features</p>
{% endif %}
</div>
<div class="listing">
<h3>Comments:</h3>
{% if user.is_authenticated %}
<div id='comform'>
<h4>Post a Comment</h4>
<form method="POST" action="{% url 'commentadd' %}">
{% csrf_token %}
{{comform}}
<button type="submit" class="btn btn-primary">Post Comment</a>
</form>
</div>
{% endif %}
<p>
{% for comment in comments %}
<div class="comment">
<h4>{{comment.user_id.username}} posted:</h4>
<p>{{comment.comment}}</p>
</div>
{% empty %}
<h4>No comments as of yet</h4>
{% endfor %}
</p>
</div>
{% else %}
<h2>This auction has been closed</h2>
<div>
<a href='{% url "watch" listing.list_title %}' class='btn btn-primary'>Add to/Remove from Watchlist</a>
</div>
<p>{{winner.user_id.username}}</p>
{% endif %}
{% endblock %}
Thanks in advance for the help!
Kind Regards
PrimeBeat
This will give a QuerySet. You can see in your second image.
A QuerySet represents a collection of objects from your database.
winner = Bids.objects.filter(auctions=listing, bid=high_bid['maximum'])
You need to iterate over that QuerySet, get whatever data you want and show it in your template.
{% for win in winner %}
<p>{{ win.user_id.username }}</p>
{% endfor %}

How do i work with 3 django models linked by a foreign field?

I've been able to display all offices in an election, but have been unable to display all candidates in an office on the same page
models.py
class Election(models.Model):
name = models.CharField(max_length = 30)
slug = models.SlugField(max_length = 250, null = False, unique = True)
class Office(models.Model):
election = models.ForeignKey(Election, on_delete=models.CASCADE, default=None)
name = models.CharField(max_length = 30)
class Candidate(models.Model):
office = models.ForeignKey(Office, on_delete=models.CASCADE, default=None)
name = models.CharField(max_length = 30)
views.py
def poll(request, id):
context = {
'election' : Election.objects.get(pk=id),
'off' : Office.objects.all()
}
return render(request, 'poll.html', context)
poll.html
{% for office in election.office_set.all %}
<div class="text-center">
<h3>{{ office.name }}</h3>
{% for candidate in off.candidate_set.all %}
<h5>{{ candidate.name }}</h5>
{% endfor %}
</div>
{% endfor %}
In your first line of poll.html, you call "office" from the queryset "election.office_set.all"
Therefore, when you call a subquery of that QS, you have to reference the original name, ie: office, rather than off.
Your final code should look like this:
poll.html
{% for office in election.office_set.all %}
<div class="text-center">
<h3>{{ office.name }}</h3>
{% for candidate in office.candidate_set.all %}
<h5>{{ candidate.name }}</h5>
{% endfor %}
</div>
{% endfor %}
You also don't need the line
'off' : Office.objects.all()
in your Views.py.

display contents of manytomany and foreignjey fields in Django

I'm new to Django and I'ma building a basic blog application.
I cant show manytomany field (in tags) and a foreignkey field (comments) in my details page.
models.py
class BlogContent(models.Model):
title = models.CharField(max_length=200)
author = models.CharField(max_length=200)
content = models.TextField()
date_published = models.DateField(auto_now=True)
image = models.ImageField(upload_to='media/')
def __str__(self):
return self.title
class TagName(models.Model):
tag = models.ManyToManyField(BlogContent, null=True)
name = models.CharField(max_length=100, blank=True, null=True)
def __str__(self):
return self.name
class Comment(models.Model):
comt_text = models.TextField()
comments = models.ForeignKey(BlogContent, on_delete=models.CASCADE)
date_published = models.DateField(auto_now=True)
name = models.CharField(max_length=200, blank=True, null=True)
def __str__(self):
return self.name
views.py
def details(request, blogcontent_id):
data_blog = get_object_or_404(BlogContent, pk=blogcontent_id)
data_tag = get_object_or_404(TagName, pk=blogcontent_id)
data_comment = Comment.objects.select_related()
return render(request, 'details.html',
{'data_blog': data_blog, 'data_tag':data_tag, 'data_comment':data_comment})
details.html
{% extends 'base.html' %}
{% block body_base %}
<img class="card-img-top img-responsive" src={{ data_blog.image.url }} alt="Card image cap">
<h2 class="blog-post-title">{{ data_blog.title }}</h2>
<p class="blog-post-meta">{{ data_blog.date_published }} {{ data_blog.author }}</p>
<p>{{ data_blog.content }}</p>
{% endblock %}
how do i show foreignkey and manaytomany fieds after this?
TBH this is much easier if you use class based views.
The view would simply be:
class BlogContentDetail (DetailView):
model = BlogContent
The url call would be url(r'^blog-detail/(?P<pk>\d+)/$, BlogContentDetail.as_view(), name="blog_detail")
Your html file should be called blogcontent_detail.html and held within the app subfolder in the templates folder
The template would then be:
{% extends 'base.html' %}
{% block body_base %}
<img class="card-img-top img-responsive" src={{ object.image.url }} alt="Card image cap">
<h2 class="blog-post-title">{{ object.title }}</h2>
<p class="blog-post-meta">{{ object.date_published }} {{ object.author }}</p>
<p>{{ object.content }}</p>
{% for tag in object.tags_set.all %}{{ tag }}{% endfor %}
{% endblock %}
You can iterate the ManyToMany Field in this way
{% for tags in data_tag.tag.all %}
<p > {{tags}} </ p>
{% endfor %}
For foreign key
{{data_comment.comments}}

Django - Sum of different Currencies

we are currently building a cryptocurrency market (university project)
Each user has different cryptocurrencies in his "Wallet"
The wallet should show the sum (+ and - transactions) for each of the different cryptocurrencies.
For the moment we are only able to render a list which doesn't group the different currencies (those who have the same name)
We tried the sum and annotate functions. By doing so we aren't able to display the currency name. We get only the currency id
Here is our models file
class Currency(models.Model):
currency_name = models.CharField(max_length=40, unique=True)
symbol = models.ImageField(blank=True)
ticker = models.CharField(max_length=10)
created_at = models.DateTimeField(auto_now_add = True, null=True)
class Transaction(models.Model):
listing_id = models.ForeignKey(Listing, on_delete=models.CASCADE, null=True, blank=True)
created_at = models.DateTimeField(auto_now_add = True)
exchange_amount = models.IntegerField(null=True)
user_debit = models.ForeignKey(User, on_delete=models.CASCADE, related_name='user_id_debit', null=True)
user_credit = models.ForeignKey(User, on_delete=models.CASCADE, related_name='user_id_credit', null=True)
currency_id = models.ForeignKey(Currency, on_delete=models.CASCADE, null=True)
And our views.py
#profile page
#login_required
def profile(request):
wallet = Transaction.objects.filter(Q(user_credit=request.user) | Q(user_debit=request.user)).order_by('-created_at')
transactions = Transaction.objects.filter(Q(user_credit=request.user) | Q(user_debit=request.user)).order_by('-created_at')[:10]
listings = Listing.objects.filter(user=request.user).order_by('-created_at')[:10]
args = {'wallets': wallet, 'transactions': transactions, 'listings': listings}
return render(request, 'profile.html', args)
<!--This is our custom head title for the different urls. The base.html is loaded after this.-->
<head>
<title>SolvayCoin - Profile</title>
</head>
{% extends 'base.html' %}
{% block content %}
{% if user.is_authenticated %}
<!-- Main jumbotron for a primary marketing message or call to action -->
<div class="jumbotron">
<div class="container">
<h1 class="display-4">{{ user.first_name }} {{ user.last_name }}'s profile</h1>
<p>Username is <pan style="font-style: italic">{{ user.username }}</pan> and joined SolvayCoin {{ user.date_joined|timesince }} ago</p>
</div>
</div>
<div class="container extra-padding">
<hr>
<div class="row">
<div class="col-md-4">
<h2>My wallet</h2>
<ul class=list-unstyled >
{% for wallet in wallets %}
<li>{{ wallet.currency_id }}: {{ wallet.exchange_amount__sum|floatformat:"2" }}</li>
{% endfor %}
</ul>
</div>
<div class="col-md-4">
<h2>My transactions</h2>
{% if transactions %}
<ul class=list-unstyled >
{% for transactions in transactions %}
<li>
{% if user == transactions.user_credit %}
(+)
{% elif user == transactions.user_debit %}
(-)
{% endif %}
{{ transactions.currency_name_fixed }}{{ transactions.exchange_amount|floatformat:"2" }}
with {% if user == transactions.user_credit %}{{ transactions.user_debit }}{% elif user == transactions.user_debit %}{{ transactions.user_credit }}{% endif%}
</li>
{% endfor %}
</ul>
{% else %}
<p>No transactions are available.</p>
{% endif %}
</div>
<div class="col-md-4">
<h2>My listings</h2>
{% if listings %}
<ul class=list-unstyled >
{% for listings in listings %}
<li>Listing <!--{{ listings.id }}--> created {{ listings.created_at|date:'d/m/Y' }} at {{ listings.created_at|date:'H:i' }}</li>
{% endfor %}
</ul>
{% else %}
<p>No listings are available.</p>
{% endif %}
</div>
</div>
{% endif %}
<hr>
</div> <!-- /container -->
{% endblock %}
A django queryset solution seems tricky; since debit/credit resolution is also required here.
If performance and doing it in DB are not a major concern; I would do it in python as follows:
wallet_transactions = Transaction.objects.filter(Q(user_credit=request.user) | Q(user_debit=request.user)).order_by('-created_at').select_related('currency_id')
wallet = get_wallet(request.user, wallet_transactions)
def get_wallet(user, wallet_transactions):
wallet = defaultdict(int)
for txn in wallet_transactions:
if user == txn.user_credit:
wallet[txn.crrency_id.currency_name] += txn.exchange_amount
elif user == txn.user_debit:
wallet[txn.crrency_id.currency_name] -= txn.exchange_amount
else:
# Error; invalid transaction
pass
return wallet
# This will return something like this: {'SBS': 300, 'BTC': 121000}
I'd also think that there will be more business logic that gets added to get_wallet which definitely makes sense to be kept in the business layer of your application (python).
In your html; you can iterate over the wallet contents and print as follows:
<ul>
{% for currency_name, amount in wallet.items %}
<li>{{currency_name}} - {{amount}}</li>
{% endfor %}
</ul>
In your specific case; change this snippet:
<ul class=list-unstyled >
{% for currency_name, amount in wallet.items %}
<li>{{ currency_name }}: {{ amount|floatformat:"2" }}</li>
{% endfor %}
</ul>

Django: Showing "featured" items?

I'm having a little conundrum with sorting some items. I have a field called featured thats a boolean. I'm trying to display the featured coins first and then the remaining will be sorted by a different metric. In this code im using pub_date.
However, when I put an if statement in my template for the featured items it's still showing those that are set to false as well. I'll post code below.
index.html loops and if's
{% if featured_coins_list %}
{% for coin in featured_coins_list %}
<div class="large-6 medium-6 cell">
<h2>{{ coin.name }}</h2>
<p>Ticker: {{ coin.ticker }}</p>
<p>{{ coin.summary }}</p>
More Info</strong>
</div>
{% endfor %}
{% endif %}
{% if latest_coins_list %}
{% for coin in latest_coins_list %}
<div class="large-6 medium-6 cell">
<h2>{{ coin.name }}</h2>
<p>Ticker: {{ coin.ticker }}</p>
<p>{{ coin.summary }}</p>
More Info</strong>
</div>
{% endfor %}
</div>
{% else %}
<p>No coins are available.</p>
{% endif %}
views.py for index
def index(request):
featured_coins_list = Coin.objects.order_by('-featured')[:4]
latest_coins_list = Coin.objects.order_by('-pub_date')[:8]
context = {'featured_coins_list': featured_coins_list,
'latest_coins_list': latest_coins_list}
return render(request, 'coins/index.html', context)
models.py
class Coin(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=100)
ticker = models.CharField(max_length=5)
featured = models.BooleanField(default=False)
logo = models.ImageField(upload_to='uploads/', verbose_name='image')
website = models.URLField(max_length=200, default="https://example.com/")
reddit = models.URLField(max_length=200, default="https://reddit.com/r/")
twitter = models.URLField(max_length=200, default="https://twitter.com/")
summary = models.CharField(max_length=500, blank=True)
description = models.TextField()
pub_date = models.DateTimeField('date published')
def __str__(self):
return self.ticker
def is_featured(self):
return self.featured
def was_published_recently(self):
return self.pub_date >= timezone.now() - datetime.timedelta(days=1)
How should I go about listing the featured coins that are set to true first and then display the remaining items after?
You need to filter for featured=True in your queryset.
def index(request):
featured_coins_list = Coin.objects.filter(featured=True).order_by('-featured')[:4]
latest_coins_list = Coin.objects.order_by('-pub_date')[:8]
context = {'featured_coins_list': featured_coins_list,
'latest_coins_list': latest_coins_list}
return render(request, 'coins/index.html', context)

Categories

Resources