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>
Related
I have a list of elements. There is a 'status' value here. I need a code that in an HTML page will show the total number of items for each 'status'. How to do it?
For intance, there is the list in the page:
appnumber status
№54534534 accepted
%46342322 in process
%55745232 accepted
%67456452 denied
%76454534 accepted
%52864525 denied
%86752525 accepted
The result should be:
accepted - 4
denied - 2
in process - 1
My code:
home.html
<div class="headtext">
<form method="GET" action="{% url 'search' %}">
<input type="search" type="text" name="q" prequired placeholder="Put appnumber">
<button type="submit">Find</button>
</form>
</div>
<div>
{% for application in object_list %}
<div>
<p>Application: {{ application.appnumber }}, status: {{ application.status }}</p>
</div>
{% endfor %}
</div>
views.py
class HomeView(ListView):
model = Application
template_name = 'home.html'
class Search(ListView):
template_name = 'home.html'
def get_queryset(self):
return Application.objects.filter(appnumber__icontains=self.request.GET.get("q"))
def get_context_data(self, *args, **kwargs):
context = super().get_context_data(*args, **kwargs)
context["q"] = self.request.GET.get("q")
return context
You can use Count with annotate() so:
from django.db.models import Count
class HomeView(ListView):
model = Application
template_name = 'home.html'
def get_context_data(self, *args, **kwargs):
context = super().get_context_data(*args, **kwargs)
status_counts = Application.objects.values('status').annotate(total=Count('status'))
context['status_counts'] = status_counts
return context
Then you can use status_counts in Template so:
<div class="headtext">
<form method="GET" action="{% url 'search' %}">
<input type="search" type="text" name="q" required placeholder="Put appnumber">
<button type="submit">Find</button>
</form>
</div>
<div>
{% for application in object_list %}
<div>
<p>Application: {{ application.appnumber }}, status: {{ application.status }}</p>
</div>
{% endfor %}
<h2>Status Counts</h2>
<ul>
{% for status_count in status_counts %}
<li>{{ status_count.status }} - {{ status_count.total }}</li>
{% endfor %}
</ul>
</div>
I'm trying to check if the user is logged in or not to change nav elements and to do more stuff and here is my code
And when I do this
print(attempted_account.is_authenticated) result => True
I think that the problem will be in base.html file so I hope you can help me.
routs.py:
#app.route('/login',methods=['GET','POST'])
def login():
form = LoginForm()
if form.validate_on_submit():
attempted_account = Account.query.filter_by(email=form.email.data).first()
print(attempted_account.is_authenticated)
if attempted_account and attempted_account.check_password(attempted_password=form.password.data):
login_user(attempted_account)
flash('Success login ',category='success')
return redirect(url_for('page',id=1))
elif not attempted_account:
flash("The E-mail doesn't exist",category='danger')
else:
flash('Tha password is incorrect',category='danger')
return render_template('login.html',form=form)
base.html
<nav>
<ul>
<li><a class="home" href="{{ url_for('home') }}">Market</a></li>
<li>Go shopping</li>
</ul>
{% if current_user.is_authenticated %}
<ul>
<li>Logout</li>
</ul>
{% else %}
<ul>
<li>Sign up</li>
<li>Login</li>
</ul>
{% endif %}
</nav>
login.html
{% extends 'base.html' %}
{% block title %}
Login
{% endblock %}
{% block content %}
<div class="container">
<form method="POST" class="form-register" style="text-align: center;">
{{ form.hidden_tag() }}
{{ form.csrf_token }}
{{ form.email.label() }}
{{ form.email(class='form-control',placeholder='example#example.com') }}
<br>
{{ form.password.label() }}
{{ form.password(class='form-control',placeholder='Password') }}
<br>
{{ form.submit(class='btn btn-lg btn-block btn-primary') }}
</form>
</div>
{% endblock %}
Please note that I called my model Account not User
Edit:
Here is models.py:
from market import db
from market import bcrypt,login_manager
from flask_login import UserMixin
#login_manager.user_loader
def load_user(user_id):
return Account.query.filter_by(id=user_id)
class Account(db.Model,UserMixin):
id = db.Column(db.Integer,primary_key = True)
first_name = db.Column(db.String(length = 50),nullable = False)
last_name = db.Column(db.String(length = 50),nullable =False)
email = db.Column(db.String(length = 100),nullable =False,unique = True)
password_hashed = db.Column(db.String(length = 25),nullable = False)
#country = db.Column(db.String,nullable = False)
items = db.relationship('Item',backref = 'owner',lazy = True)
#property
def password(self):
return self.password
#password.setter
def password(self,plain_text_password):
self.password_hashed = bcrypt.generate_password_hash(plain_text_password).decode('utf-8')
def check_password(self,attempted_password):
return bcrypt.check_password_hash(self.password_hashed,attempted_password)
The issue is probably because you're returning a query result in the user_loader callback instead of an Account object.
Instead of returning Account.query.filter_by(id=user_id) try returning Account.query.filter_by(id=user_id).first().
Hope it works.
I am working with the Django form wizard and i am trying to emulate the typical
render_to_response('index.html',{'name', name})
but without redirect and only in the steps.
So the idea would be i have a form wizard like this
TEMPLATES = {"0": "MyApp/checkout_template1.html",
"1": "MyApp/checkout_template2.html",
"2": "MyApp/checkout_template3.html",
}
class MyWizard(SessionWizardView):
def get_template_names(self):
return [TEMPLATES[self.steps.current]]
def get_context_data(self, form, **kwargs):
context = super(MyWizard, self).get_context_data(form=form, **kwargs)
if self.steps.current == '3':
data_1 = self.get_cleaned_data_for_step('1')
((HERE I NEED TO PASS THE data_1["first_name"] TO SHOW ON NEXT TEMPLATE))
print(data_1["first_name"])
return context
def done(self, form_list, **kwargs):
if self.request.method == 'POST':
process_form_data(form_list)
return render(self.request,'MyApp/congratulations.html')
then in templates id have something like this
{% extends "MyApp/base.html" %}
{% load staticfiles %}
{% load humanize %}
{% block head %}{{ wizard.form.media }}{% endblock %}
{% endblock %}
{% block body_block%}
<div class="confirmation-body">
<div class="confirmation-body-container">
<div class="form-title-container">
<h1>Information</h1>
<p>Step {{ wizard.steps.step1 }} of {{ wizard.steps.count }}</p>
<form action="/checkout/" method="post">{% csrf_token %}
<table>
{{ wizard.management_form }}
{% if wizard.form.forms %}
{{ wizard.form.management_form }}
{% for form in wizard.form.forms %}
{{form}}
{% endfor %}
{% else %}
<div class="checkout-title">Information</div>
//////////////////////
{{ name }} #something like this that prints in the next step
//////////////////////
{{wizard.form.name_on_card}}
{% endif %}
</table>
<hr />
<div class="checkout-nav-controls">
<div>
{% if wizard.steps.prev %}
<button id="prev-step-button" name="wizard_goto_step" type="submit" value="{{ wizard.steps.prev }}">back</button>
{% endif %}
</div>
<input id="my-submit-button" type="submit" value="Next"/>
</div>
</form>
</div>
</div>
{% endblock %}
So just to reiterate the question for clairity. I want to:
get the data from the previous step (lets say first step and name)
in the second step pass that data to the corresponding html
template {{name}}
render that last step so i can see the name on
the front end
thanks in advance for your help
Maybe something like this whould do the trick, using get_form method:
def get_form(self, step=None, data=None, files=None):
form = super(MyWizard, self).get_form(step, data, files)
if step is None:
step = self.steps.current
if step == '3':
data_1 = self.get_cleaned_data_for_step('1')['first_name']
form.fields['first_form_field'].label = data1
return form
So in this way, you will have the field first_name from the first steps' form, as a label to the third step's form's first field
You can supply additional context variables by using the get_context_data() method of your WizardView subclass.
def get_context_data(self, form, **kwargs):
context = super(MyWizard, self).get_context_data(form=form, **kwargs)
if self.steps.current == 'my_step_name':
category=self.get_cleaned_data_for_step('category')['name']
context.update({'another_var': 'category'})
return context
get_context_data() docs
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 %}
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>