Bad for-loop in django with Groups model, ManyToMany field - python

I want to display 1 button in the for-loop, but i get as many buttons as many i have created groups. So.. when i created 3 groups where i'm one of the members, i got 3 buttons under every group i have. The problem is with this first loop in my code, but i don't know how to solve this.
Problem is in loop:
{% for z in mem %}
When i create any memberships it's like:
m = Membership.objects.create(person="damian", group="name_group", leader=True) / or False
Thanks for any help!
groups.html:
{% for g in gr %}
<div class="jumbotron">
<div class="jumbo2">
<form method="POST" class="post-form"> {% csrf_token %}
<p id="name"><b>Group's name:</b> {{g.name}}</p><br>
{% for member in g.members.all %}
<p><b>Member:</b> {{member.name}} </p>
{% endfor %}
<br>
<span class="desc2">Group's description:</span>
<p id="desc">{{g.description}}</p><br>
{% for z in mem %}
{% if z.leader == False %}
<button style="float: right" type="submit" name = "leave" value = "{{g.name}}" class="save btn btn-default">Leave</button>
{% elif z.leader == True %}
<button style="float: right" type="submit" name = "delete" value = "{{g.name}}" class="save btn btn-default">Delete</button>
{% endif %}
{% endfor %}
</form>
<br><br>
<p>
{% if messages %}
{% for message in messages %}
<p>{{ message }}</p>
{% endfor %}
{% endif %}
</p>
</div>
</div>
{% endfor %}
views.py:
cvs = Cv.objects.all()
cv = Cv.objects.filter(author = request.user)
per = Person.objects.all()
gr = Group.objects.filter(members__name=request.user)
perr = Person.objects.filter(name=request.user)
mem = Membership.objects.filter(group = gr, person = perr)
form = GroupForm()
context = {
'gr': gr,
'per':per,
'mem':mem,
'form': form,
'cvs':cvs,
'cv':cv,
}
return render(request, 'groups.html', context)
models.py:
class Person(models.Model):
name = models.CharField(max_length=128)
def __str__(self): # __unicode__ on Python 2
return self.name
class Group(models.Model):
name = models.CharField(max_length=128)
members = models.ManyToManyField(Person, through='Membership')
description = models.TextField(max_length=350)
def __str__(self): # __unicode__ on Python 2
return self.name
class Membership(models.Model):
person = models.ForeignKey(Person)
leader = models.BooleanField(default=False)
group = models.ForeignKey(Group)

Ok, i replace my groups and used only membership objects. Here's my working code:
{% for z in mem %}
<div class="jumbotron">
<div class="jumbo2">
<form method="POST" class="post-form"> {% csrf_token %}
<p id="name"><b>Group's name:</b> {{z.group}}</p><br>
{% for member in z.group.members.all %}
<p><b>Member:</b> {{member.name}} </p>
{% endfor %}
<br>
<span class="desc2">Group's description:</span>
<p id="desc">{{z.group.description}}</p><br>
{% if z.leader == False %}
<button style="float: right" type="submit" name = "leave" value = "{{z.group}}" class="save btn btn-default">Leave</button>
{% elif z.leader == True %}
<button style="float: right" type="submit" name = "delete" value = "{{z.group}}" class="save btn btn-default">Delete</button>
{% endif %}
</form>
<br><br>
<p>
</p>
</div>
</div>
{% endfor %}

Related

How to display multiple items under 1 category name?

views.py :
def gerechten(request):
template = loader.get_template('café/gerechten.html')
mydata = gerecht_info.objects.all()
mydata2 = gerechten_Categorie.objects.all()
context = {
'mygerecht': mydata,
'mycategories': mydata2
}
return HttpResponse(template.render(context, request))
models.py :
class gerechten_Categorie(models.Model):
categorie = models.CharField(max_length=200)
def __str__(self):
return self.categorie
class gerecht_info(models.Model):
categorie = models.ForeignKey(gerechten_Categorie, on_delete=models.CASCADE)
gerecht_name = models.CharField(max_length=200)
gerecht_description = models.CharField(max_length=500, blank=True, null=True)
gerecht_price = models.CharField(max_length=50)
def __str__(self):
return self.gerecht_name
def drinkdesc(self):
return self.gerecht_description
def drinkprice(self):
return self.gerecht_price
gerechten.html :
{% if mygerecht %}
{% for cat in mygerecht %}
<div class="flex">
<div class="menu-head center">
<h2>{{cat.categorie}}</h2>
</div>
<div class="menu-item">
<ul class="price">
<li>{{cat.gerecht_name}}</li>
<li>€{{cat.gerecht_price}}</li>
</ul>
{% if cat.gerecht_description %}
<p>{{cat.gerecht_description}}</p>
{% else %}
<p></p>
{% endif %}
</div>
</div>
{% endfor %}
{% else %}
<div class="menu-head center">
<h2>no items avaible</h2>
</div>
{% endif %}
Looks like this but I want all info from 'Hapjes' into 1 'Hapjes' category, not separated.
I think what you are trying to achieve can be done with regroup template tag.
{% regroup mygerecht by categorie as article_categories %}
{% for categorie in article_categories %}
<div class="flex">
<div class="menu-head center">
<h2>{{categorie.grouper}}</h2>
</div>
{% for article in categorie.list %}
<div class="menu-item">
<ul class="price">
<li>{{article.gerecht_name}}</li>
<li>€{{article.gerecht_price}}</li>
</ul>
<p>{% if article.gerecht_description %}{{article.gerecht_description}}{% endif %}</p>
</div>
{% endfor %}
</div>
{% endfor %}

How to access other model fields from new View

I'm trying to build a Wish list, I have a model for the listings, and a model for the wish list,
I have succeeded in making it work but..
I have to loop over all the listings first and match with the product id in my wish list so i can access the fields such as title and image..
is there any easier way to do this than looping over all the listings until finding the matched ones ?
views.py
def add_to_wishlist(request, product_id):
product = WishList.objects.filter(listing_id=product_id, user=request.user.username)
if product:
product.delete()
else:
product = WishList()
product.listing_id = product_id
product.user = request.user.username
product.save()
return HttpResponseRedirect(request.META['HTTP_REFERER'])
def wishlist(request):
product = WishList.objects.filter(user=request.user)
all_listings = AuctionListing.objects.all()
return render(request, "auctions/wishlist.html", {
'wishlist': product,
'all_listings': all_listings
})
models.py
class AuctionListing(models.Model):
title = models.CharField(max_length=100)
description = models.TextField()
start_bid = models.IntegerField(null=True)
image = models.CharField(max_length=1000, blank=True)
category = models.CharField(max_length=100)
seller = models.CharField(max_length=100, default="Default_Value")
class WishList(models.Model):
user = models.CharField(max_length=64)
listing_id = models.IntegerField()
wishlist.html
{% extends "auctions/layout.html" %}
{% block title %}Users Wishlist {% endblock %}
{% block body %}
<div class="col-12 mx-auto">
<h1 class="h3">My Wishlist</h1>
<div>Manage your wishlist</div>
{% if wishlist %}
{% for listing in all_listings %}
{% for product in wishlist %}
{% if listing.id == product.listing_id%}
<div class="card-mb-3">
<div class="row g-0">
<div class="col-md-4">
<img src="{{ listing.image }}" class="img-responsive" >
</div>
<div class="col-md-8">
<div class="card-body">
<h5 class="card-title">{{listing.title}}</h5>
<p class="card-text"> {{listing.description}}</p>
<p class="card-text"><small class="text-muted">{{listing.start_bid}}</small></p>
</div>
</div>
</div>
</div>
{% endif %}
{% endfor %}
{% endfor %}
{% else %}
<p class="card-text">No products have been added to your wishlist yet</p>
{% endif %}
</div>
{% endblock %}
Because you're getting all the WishList objects for the user, you don't need to just gather all AuctionListing objects and iterate over them. You can query them using the IDs on the WishLists you get back.
I'd do something like;
views.py
def wishlist(request):
wishlists = WishList.objects.filter(user=request.user)
listing_ids = wishlists.values_list('listing_id', flat=True)
listings = AuctionListing.objects.filter(pk__in=listing_ids)
return render(request, "auctions/wishlist.html", {
'wishlists': wishlists,
'listings': listings
})
wishlist.html
{% extends "auctions/layout.html" %}
{% block title %}Users Wishlist {% endblock %}
{% block body %}
<div class="col-12 mx-auto">
<h1 class="h3">My Wishlist</h1>
<div>Manage your wishlist</div>
{% if wishlists and listings %}
{% for listing in listings %}
<div class="card-mb-3">
<div class="row g-0">
<div class="col-md-4">
<img src="{{ listing.image }}" class="img-responsive" >
</div>
<div class="col-md-8">
<div class="card-body">
<h5 class="card-title">{{listing.title}}</h5>
<p class="card-text"> {{listing.description}}</p>
<p class="card-text"><small class="text-muted">{{listing.start_bid}}</small></p>
</div>
</div>
</div>
</div>
{% endfor %}
{% else %}
<p class="card-text">No products have been added to your wishlist yet</p>
{% endif %}
</div>
{% endblock %}

Django. DRY. Same context in get request

I am trying to make a voting app in django.
Here the view that display a vote.
class DetailVoteView(View):
"""
Displays the vote
If vote is active allows to vote
If vote is completed shows winners and top 5
"""
vote = None
vote_for_chars = None
page_title = ''
def dispatch(self, request, *args, **kwargs):
self.vote = Vote.objects.get(id=kwargs['id'])
self.vote_for_chars = self.vote.voteforcharacter_set.all()
self.page_title = self.vote.title
return super(DetailVoteView, self).dispatch(request, *args, **kwargs)
def get(self, request, id):
if is_active_vote(self.vote):
nominates = self.vote_for_chars
return render(request, 'vote_detail/active_vote_detail.html', context={
'page_title': self.page_title,
'vote': self.vote,
'votes_name': self.page_title,
'nominates': nominates,
})
else:
winners = []
top_fives = []
if self.vote.voteforcharacter_set.count() != 0:
sorted = self.vote.voteforcharacter_set.order_by('-votes_number')
winner_number_votes = sorted[0].votes_number
winners = self.vote_for_chars.filter(votes_number__exact=winner_number_votes)
top_fives = sorted[winners.count():5 + winners.count()]
return render(request, 'vote_detail/completed_vote_detail.html', context={
'page_title': self.page_title,
'vote': self.vote,
'votes_name': self.page_title,
'winners': winners,
'top_fives': top_fives
})
def post(self, request, id):
vote_for_chars = self.vote_for_chars
id_to_vote = request.POST.get("id_to_vote")
char_to_vote = vote_for_chars.get(character__id=id_to_vote)
char_to_vote.votes_number += 1
char_to_vote.save()
return HttpResponseRedirect('/')
The code is not DRY as I suppose. Because, there is the same context in get reuqest.
I need to use a mixins feature?
How can I improve it? Thanks.
EDITED.
Added code for templates.
acvtive_vite_detail.html
{% extends 'base/base.html' %}
{% block content %}
<form action="." method="POST">{% csrf_token %}
<p>Vote: {{ vote }}.</p>
<p>Choose:</p>
<div>
{% for item in nominates %}
{% include "base/listOutput.html" %}
<input type="radio" id="{{ item.id }}"
name="id_to_vote" value="{{ item.character.id }}" checked>
<label for="{{ item.character.name }}">{{ item.character.name }}
</label>
{% endfor %}
</div>
<div>
<button type="submit">Vote!</button>
</div>
</form>
{% endblock content %}
completed_vote_detail.html
{% extends 'base/base.html' %}
{% block content %}
<p>Vote: {{ vote }}.</p>
<p>Winners: </p>
{% for item in winners %}
<p>{% include "base/listOutput.html" %}</p>
{% endfor %}
<p>Top5: </p>
{% for item in topFives %}
<p>{% include "base/listOutput.html" %}</p>
{% endfor %}
{% endblock content %}
listOfOutput.html
<div style="border-style: solid; width: 25%">
<img src="{{ item.character.image.url }}" alt="img" class="img-responsive img-rounded" width="100%" height=auto>
<p>Name: {{ item.character.name }}</p>
<p>Age: {{ item.character.age }}</p>
<p>Votes number: {{ item.votes_number }}</p>
</div>

Django pagination filtered results CBV

How can I paginate using multiple filters in Django CBV? I have some filters in my view and form and I don't know how to paginate it. Everything that I've tried has failed.
Here my code.
models.py
class Lei(models.Model):
CHOICE_TIPO_LEI = (
('complementar', 'Lei complementar'),
('ordinaria', 'Lei ordinária'),
('decreto', 'Decreto'),
('portaria', 'Portaria'),
('convenio', 'Convênios Municipais'),
)
numero = models.CharField(max_length=6)
tipo_lei = models.CharField(u'Tipo do documento', max_length=15, choices=CHOICE_TIPO_LEI)
ano = models.CharField(max_length=4)
titulo = models.TextField()
arquivo = FileBrowseField("Arquivo PDF", max_length=200, extensions=[".pdf",".doc", ".xls", ".docx", ".xlsx"], directory="leis/", blank=True, null=True)
publicacao = models.DateTimeField(u'publicação', auto_now=True, blank=True)
class Meta:
db_table = "tb_lei"
verbose_name = "Lei"
verbose_name_plural = "Leis"
def __str__(self):
return self.titulo
views.py
class LeisListView(ComunsNoticiasMixin, ListView):
model = Lei
template_name = 'leis/leis.html'
context_object_name = 'leis'
def get_context_data(self, **kwargs):
context = super(LeisListView, self).get_context_data(**kwargs)
context["an"] = Lei.objects.values('ano').distinct().order_by('-ano')
context["tl"] = Lei.objects.values('tipo_lei').distinct().order_by('tipo_lei')
return context
class BuscaLeiListView(ComunsNoticiasMixin, ListView):
model = Lei
template_name = 'leis/busca-leis.html'
context_object_name = 'busca_leis'
paginate_by = 1
def get_queryset(self, **kwargs):
numero = self.request.GET.get('n')
ano = self.request.GET.get('a')
tipo_lei = self.request.GET.get('t')
palavra = self.request.GET.get('p')
leis = Lei.objects.all().order_by('-ano', '-numero')
if numero:
leis = leis.filter(numero=numero)
if ano:
leis = leis.filter(ano=ano)
if tipo_lei:
leis = leis.filter(tipo_lei=tipo_lei)
if palavra:
leis = leis.filter(titulo__icontains=palavra)
return leis
form.html
<form method="get" action="{% url 'leis:busca_lei_view' %}">
<div class="form-group">
<select name="t" class="form-control">
<option value="">Tipo do documento</option>
{% for l in tl %}
<option value="{{ l.tipo_lei }}">
{% if l.tipo_lei == "complementar" %} Leis complementares
{% elif l.tipo_lei == "ordinaria" %} Leis ordinárias
{% elif l.tipo_lei == "decreto" %} Decretos
{% elif l.tipo_lei == "convenio" %} Convênios municipais
{% elif l.tipo_lei == "portaria" %} Portarias
{% endif %}
</option>
{% endfor %}
</select>
</div>
<div class="form-group">
<input name="n" type="text" class="form-control" placeholder="numero da lei, portaria ou decreto" size="10" maxlength="30">
</div>
<div class="form-group">
<select name="a" class="form-control">
<option value="">ano</option>
{% for l2 in an %}
<option value="{{ l2.ano }}">{{ l2.ano }}</option>
{% endfor %}
</select>
</div>
<div class="form-group">
<button value="{{ search_term }}" class="btn btn-info">pesquisar</button>
</div>
<hr />
<div class="form-group">
<label for="t"><strong>Ou digite um termo a ser pesquisado</strong></label>
<input name="p" class="form-control" type="text" placeholder="digite um termo a ser pesquisado" size="20" maxlength="30">
</div>
<button value="{{ search_term }}" class="btn btn-info">Pesquisar</button>
result.html
<div class="row">
<div class="col-xs-12">
{% if busca_leis %}
{% for lb in busca_leis %}
<h4 ><a href="{{ lb.arquivo.url }}" class="text-primary">
{% if lb.tipo_lei == "complementar" %}Lei complementar n° {% elif lb.tipo_lei == "ordinaria" %} Lei ordinária nº {% elif lb.tipo_lei == "decreto" %} Decreto nº {% elif lb.tipo_lei == "convenio" %} Convênio municipal {% else %} Portaria nº{% endif %} {{ lb.numero }} de {{ lb.ano }}</a>
</h4>
<p class="post-content">{{ lb.titulo|safe }}</p>
<br />
{% endfor %}
<br />
{% else %}
<br /><br />
<div class="alert alert-warning" role="alert">
<h5>
O termo pesquisado não foi encontrado. Utilize os filtros para realizar a pesquisar novamente.
</h5>
voltar
</div>
{% endif %}
</div>
{% if is_paginated %}
<ul class="pagination">
{% if page_obj.has_previous %}
<li>«</li>
{% else %}
<li class="disabled"><span>«</span></li>
{% endif %}
{% for i in paginator.page_range %}
{% if page_obj.number == i %}
<li class="active"><span>{{ i }} <span class="sr-only">(current)</span></span></li>
{% else %}
<li>{{ i }}</li>
{% endif %}
{% endfor %}
{% if page_obj.has_next %}
<li>»</li>
{% else %}
<li class="disabled"><span>»</span></li>
{% endif %}
</ul>
{% endif %}
The existing querystring is being dropped when you click on the pagination, so you need to have a way to carry that information through.
The best option would be to bring that information through.
Start by adding the "django.core.context_processors.request" to settings.py
## settings.py
TEMPLATE_CONTEXT_PROCESSORS = (
'django.core.context_processors.request',
)
Now, you have access to https://docs.djangoproject.com/en/1.8/ref/request-response/#querydict-objects.
In the template change the line:
<a href="?page={{ page_obj.next_page_number }}">
to
<a href="?page={{ page_obj.next_page_number }}{% for key, value in request.GET.items %}{% if key != page %}&{{key}}={{value}}{% endif %}{% endfor %}"
This will loop through the keys in the querystring and ignore the pa

How to pass variable from view function to jinja2 template - Flask app

I'm writing a basic messaging function inside my app and it does what it's suppose to do. It sends, receives and sort messages in inbox and outbox, and I wanted it to show the nicknames of those who send (TO: 'nickname') and those who receive the message (FROM: 'nickname')
SOLVED
class Message(db.Model):
id = db.Column(db.Integer, primary_key = True)
body = db.Column(db.String(140))
timestamp = db.Column(db.DateTime)
for_id = db.Column(db.Integer)
**for_nickname = db.Column(db.String(140))**
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
def __repr__(self): # pragma: no cover
return '<Message %r>' % (self.body)
I just added one more field in my table for the nickname, so I can access it from the posted data. I felt that writing 2 more queries and comparing them to get this same result is too much for something like this.
Edited:
the view:
#app.route('/poraki', methods = ['GET', 'POST'])
#login_required
def poraki(page=1):
form = PostMessage()
nick = form.nickname.data
nickname = User.query.filter_by(nickname = nick).first()
if form.validate_on_submit():
m = Message(body = form.post.data,
timestamp = datetime.utcnow(),
author = g.user,
for_id = nickname.id)
db.session.add(m)
db.session.commit()
flash(gettext(u'Вашата порака е пратена!'))
return redirect(url_for('poraki'))
#inbox
sent = User.query.filter_by(nickname = g.user.nickname).first()
all_inbox = Message.query.filter_by(for_id = sent.id).order_by(Message.timestamp.desc()).paginate(page, POSTS_PER_PAGE, False)
#sent
all_sent = Message.query.filter_by(user_id = sent.id).order_by(Message.timestamp.desc()).paginate(page, POSTS_PER_PAGE, False)
return render_template('messages.html', form = form, posts1 = all_sent, posts2 = all_inbox, title = u'Пораки')
PostMessage():
class PostMessage(Form):
nickname = TextField('nickname', validators = [Required()])
post = TextField('post', validators = [Required()])
message.html template:
<td width="70px"><img src="{{post.author.avatar(70)}}" /></td>
<td>
{% autoescape false %}
{% if prateni == 1 %}
<p>{{ _('До: %(nickname)s ', nickname = '%s' % (url_for('user', nickname = post.for_id), post.for_id)) }}</p>
{% else %}
<p>{{ _('Од: %(nickname)s ', nickname = '%s' % (url_for('user', nickname = post.author.nickname), post.author.nickname)) }}</p>
{% endif %}
{% endautoescape %}
<p><strong><span id="post{{post.id}}">{{post.body}}</span></strong></p>
{% autoescape false %}
<p>{{ _('%(when)s', when = momentjs(post.timestamp).fromNow() ) }} </p>
{% endautoescape %}
<!-- {% if post.author.id == g.user.id %}
<div>{{ _('Избриши') }}</div>
{% endif %} -->
</td>
messages.html template:
<div class="well">
<form class="form-horizontal" action="" method="post" name="post">
{{form.hidden_tag()}}
<div class="control-group{% if form.errors.post %} error{% endif %}">
<label class="control-label" for="nickname">{{ _('До:') }}</label>
<div class="controls">
{{ form.nickname(size = 30, maxlength = 140) }}
{% for error in form.errors.nickname %}
<span class="help-inline">[{{error}}]</span><br>
{% endfor %}
</div>
</div>
<div class="control-group{% if form.errors.post %} error{% endif %}">
<label class="control-label" for="post">{{ _('Порака:') }}</label>
<div class="controls">
{{ form.post(cols = 64, rows = 4, class = "span4") }}
{% for error in form.errors.post %}
<span class="help-inline">[{{error}}]</span><br>
{% endfor %}
</div>
</div>
<div class="control-group">
<div class="controls">
<input class="btn btn-primary" type="submit" value="{{ _('Прати!') }}">
</div>
</div>
</form>
</div>
<table class="table">
<tr>
<td width=50%> Пратени пораки {{ proba }}
{% set prateni = 1 %}
{% for post in posts1.items %}
{% include 'message.html' %}
{% endfor %}
</td width=50%>
<td> Примени пораки
{% set prateni = 0 %}
{% for post in posts2.items %}
{% include 'message.html' %}
{% endfor %}
</td>
</tr>
</table>

Categories

Resources