I want to rewrite the vote form of the django tutorial polls application. But I can't figure out how to make a radio list for all choices of a question:
{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}
<form action="{% url 'polls:vote' question.id %}" method="post">
{% csrf_token %}
{% for choice in question.choice_set.all %}
<input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}" />
<label for="choice{{ forloop.counter }}">{{ choice.choice_text }}</label><br />
{% endfor %}
<input type="submit" value="Vote" />
</form>
After a lot of experimenting this was the solution:
#forms.py
class VoteForm(forms.ModelForm):
choice = forms.ModelChoiceField(queryset=None, widget=forms.RadioSelect)
class Meta:
model = Question
exclude = ('question_text', 'pub_date')
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['choice'].error_messages = {
'required': 'No choice selected.',
'invalid_choice': 'Invalid choice selected.'
}
instance = getattr(self, 'instance', None)
if instance:
self.fields['choice'].queryset = instance.choice_set
#vote.html
{% load static %}
<link rel="stylesheet" type="text/css" href="{% static 'polls/css/style.css' %}" />
<h2>{{ question.question_text }}</h2>
{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}
{% if voted %}
<p><strong>Already voted on this question.</strong><p>
{% else %}
<form action="{% url 'polls:vote' question.id %}" method="post">
{% csrf_token %}
{{ form.non_field_errors }}
<div class="fieldWrapper">
{{ form.choice.errors }}
{{ form.choice }}
</div>
<input type="submit" value="Vote" />
</form>
{% endif %}
<p>View results?</p>
#views.py
class VoteView(generic.UpdateView):
template_name = 'polls/vote.html'
model = Question
form_class = VoteForm
def get_queryset(self):
return Question.objects.filter(pub_date__lte=timezone.now()).exclude(choice__isnull=True)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
# Check duplicate vote cookie
cookie = self.request.COOKIES.get(cookie_name)
if has_voted(cookie, self.object.id):
context['voted'] = True
return context
def get_success_url(self):
return reverse('polls:results', args=(self.object.id,))
def form_valid(self, form):
choice = form.cleaned_data['choice']
choice.votes = F('votes') + 1
choice.save()
redirect = super().form_valid(form)
# Set duplicate vote cookie.
cookie = self.request.COOKIES.get(cookie_name)
half_year = timedelta(weeks=26)
expires = datetime.utcnow() + half_year
if cookie and re.match(cookie_pattern, cookie):
redirect.set_cookie(cookie_name, "{}-{}".format(cookie, self.object.id), expires=expires)
else:
redirect.set_cookie(cookie_name, self.object.id, expires=expires)
return redirect
Related
I have designed my search box in my django app but the search only returns the extended html page, not the search results.
#View
class SearchListProject(ListView):
paginate_by = 4
template_name = 'website/search_project.html'
def get_queryset(self):
search_project = self.request.GET.get('q')
return Project.objects.filter(description__icontains=search_project)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['search_project'] = self.request.GET.get('q')
return context
#url
path('search_project/', SearchListProject.as_view(), name='search_project'),
path('search_project/page/<int:page>', SearchListProject.as_view(), name='search_project')
#html
{% extends 'website/project_list.html' %}
<h3 class="alert alert-primary text-center">Search: {{ search_project }}</h3>
{% block previous_page_url %}
{% url 'website:search_project' page_obj.previous_page_number %}?q={{ search_project }}
{% endblock %}
{% block next_page_url %}
{% url 'website:search_project' page_obj.next_page_number%}?q={{ search_project }}
{% endblock %}
#my form
<form action="{% url 'website:search_project' %}">
<input type="text" name="q">
<button type="submit"><i class="icofont-search"></i></button>
</form>
I try to add follow button in django with Getstream.io app.
Following the getstream tutorial, django twitter, I managed to create a list of users with a functioning follow button as well as active activity feed. But when i try add follow button on user profile page, form send POST but nothing happends later.
I spend lot of time trying resolve this, but i'm still begginer in Django.
Code:
Follow model:
class Follow(models.Model):
user = models.ForeignKey('auth.User', related_name = 'follow', on_delete = models.CASCADE)
target = models.ForeignKey('auth.User', related_name ='followers', on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add = True)
class Meta:
unique_together = ('user', 'target')
def unfollow_feed(sender, instance, **kwargs):
feed_manager.unfollow_user(instance.user_id, instance.target_id)
def follow_feed(sender, instance, **kwargs):
feed_manager.follow_user(instance.user_id, instance.target_id)
signals.post_delete.connect(unfollow_feed, sender=Follow)
signals.post_save.connect(follow_feed, sender=Follow)
Views:
def user(request, username):
user = get_object_or_404(User, username=username)
feeds = feed_manager.get_user_feed(user.id)
activities = feeds.get()['results']
activities = enricher.enrich_activities(activities)
context = {
'user': user,
'form': FollowForm(),
'login_user': request.user,
'activities': activities,
}
return render(request, 'profile/user.html', context)
def follow(request):
form = FollowForm(request.POST)
if form.is_valid():
follow = form.instance
follow.user = request.user
follow.save()
return redirect("/timeline/")
def unfollow(request, target_id):
follow = Follow.objects.filter(user=request.user, target_id=target_id).first()
if follow is not None:
follow.delete()
return redirect("/timeline/")
Forms:
class FollowForm(ModelForm):
class Meta:
exclude = set()
model = Follow
Urls:
path('follow/', login_required(views.follow), name='follow'),
path('unfollow/<target_id>/', login_required(views.unfollow), name='unfollow'),
And user.html
<form action="{% if request.user in User.followers.all %}{% url 'unfollow' target.id %}{% else %}{% url 'follow' %}{% endif %}" method="post">
{% csrf_token %}
<input type="hidden" id="id_target" name="target" value="{{target.id}}">
<input type="hidden" id="id_user" name="user" value="{{user.id}}">
<button type="submit" class="btn btn-primary btn-sm" value="Create" />
{% if request.user in User.followers.all %}
Unfollow
{% else %}
Follow
{% endif %}
</button>
</form>
This form work in list user page:
{% for one, followed in following %}
<div class="col-md-3 col-sm-6 col-xs-12">
<div class="card">
<div class="card-body">
{% include "profile/_user.html" with user=one %}
<form action="{% if followed %}{% url 'unfollow' one.id %}{% else %}{% url 'follow' %}{% endif %}" method="post">
{% csrf_token %}
<input type="hidden" id="id_target" name="target" value="{{one.id}}">
<input type="hidden" id="id_user" name="user" value="{{user.id}}">
<button type="submit" class="btn btn-primary btn-sm" value="Create" />
{% if followed %}
Przestań obserwować
{% else %}
Obserwuj
{% endif %}
</button>
</form>
</div>
</div>
</div>
{% if forloop.counter|divisibleby:'4' %}
<div class="clearfix visible-sm-block visible-md-block visible-lg-block"></div>
{% elif forloop.counter|divisibleby:'2' %}
<div class="clearfix visible-sm-block"></div>
{% endif %}
{% endfor %}
</div>
And user list Views.py
def discover(request):
users = User.objects.order_by('date_joined')[:50]
login_user = User.objects.get(username=request.user)
following = []
for i in users:
if len(i.followers.filter(user=login_user.id)) == 0:
following.append((i, False))
else:
following.append((i, True))
login_user = User.objects.get(username=request.user)
context = {
'users': users,
'form': FollowForm(),
'login_user': request.user,
'following': following
}
return render(request, 'uzytkownicy.html', context)
I am using django-allauth and whenever I input a wrong password in login form,the page just reloads and doesn't show any error.This is my html code:
<form class="login" method="POST" action="{% url 'account_login' %}">
{% if form.errors %}
{% for field in form %}
{% for error in field.errors %}
<div class="alert alert-error">
<span><b> {{error}} </b><span>
</div>
{% endfor %}
{% endfor %}
{% endif %}
{% csrf_token %}
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">
{{ form.login }}
<label class="mdl-textfield__label" for="id_login">Username/Email:</label>
</div>
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">
{{ form.password }}
<label class="mdl-textfield__label" for="id_password">Password</label>
</div>
<label class="mdl-checkbox mdl-js-checkbox mdl-js-ripple-effect" for="id_remember">
{{form.remember}}<span class='mdl-checkbox__label 'align='left'>Remember me</span>
</label></br>
{% if redirect_field_value %}
<input type="hidden" name="{{ redirect_field_name }}" value="{{ redirect_field_value }}" />
{% endif %}
<a class="button secondaryAction" href="{% url 'account_reset_password' %}">{% trans "Forgot Password?" %}</a><br/></br>
<button class="mdl-button mdl-js-button mdl-js-ripple-effect mdl-button--raised mdl-button--colored" type="submit">{% trans "Sign In" %}</button>
<br/>
<br/>
</form>
The form displays properly normally and submits normally,if the info input are correct.For sign-up form,the error messages show but it gives a weird one like '%(model_name)s with this %(field_label)s already exists.' if i try to input an email that already exists but for username it gives a normal A user with that username already exists.
This is the signup.html
<form class="signup" id="signup_form" method="post" action="{% url 'account_signup' %}">
{% if form.errors %}
{% for field in form %}
{% for error in field.errors %}
<div class="alert alert-error">
<span><b> {{error}} </b><span>
</div>
{% endfor %}
{% endfor %}
{% endif %}
{% csrf_token %}
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">
{{ form.username }}
<label class="mdl-textfield__label" for="id_username">Username</label>
</div>
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">
{{form.email}}
<label class="mdl-textfield__label" for="id_email">Email</label>
</div>
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">
{{form.password1}}
<label class="mdl-textfield__label" for="id_password1">Password</label>
</div>
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">
{{form.password2}}
<label class="mdl-textfield__label" for="id_password2">Password(again)</label>
</div>
{% if redirect_field_value %}
<input type="hidden" name="{{ redirect_field_name }}" value="{{ redirect_field_value }}" />
{% endif %}<br/>
<button class="mdl-button mdl-js-button mdl-js-ripple-effect mdl-button--raised mdl-button--colored" type="submit">{% trans "Sign Up" %}</button>
</form>
Signup View
class SignupView(RedirectAuthenticatedUserMixin, CloseableSignupMixin,
AjaxCapableProcessFormViewMixin, FormView):
template_name = "account/signup." + app_settings.TEMPLATE_EXTENSION
form_class = SignupForm
redirect_field_name = "next"
success_url = None
#sensitive_post_parameters_m
def dispatch(self, request, *args, **kwargs):
return super(SignupView, self).dispatch(request, *args, **kwargs)
def get_form_class(self):
return get_form_class(app_settings.FORMS, 'signup', self.form_class)
def get_success_url(self):
# Explicitly passed ?next= URL takes precedence
ret = (
get_next_redirect_url(
self.request,
self.redirect_field_name) or self.success_url)
return ret
def form_valid(self, form):
# By assigning the User to a property on the view, we allow subclasses
# of SignupView to access the newly created User instance
self.user = form.save(self.request)
return complete_signup(self.request, self.user,
app_settings.EMAIL_VERIFICATION,
self.get_success_url())
def get_context_data(self, **kwargs):
ret = super(SignupView, self).get_context_data(**kwargs)
form = ret['form']
email = self.request.session.get('account_verified_email')
if app_settings.SIGNUP_EMAIL_ENTER_TWICE:
email_keys = ['email1', 'email2']
else:
email_keys = ['email']
for email_key in email_keys:
form.fields[email_key].initial = email
login_url = passthrough_next_redirect_url(self.request,
reverse("account_login"),
self.redirect_field_name)
redirect_field_name = self.redirect_field_name
redirect_field_value = get_request_param(self.request,
redirect_field_name)
ret.update({"login_url": login_url,
"redirect_field_name": redirect_field_name,
"redirect_field_value": redirect_field_value})
return ret
signup = SignupView.as_view()
Login View
class LoginView(RedirectAuthenticatedUserMixin,
AjaxCapableProcessFormViewMixin,
FormView):
form_class = LoginForm
template_name = "account/login." + app_settings.TEMPLATE_EXTENSION
success_url = None
redirect_field_name = "next"
#sensitive_post_parameters_m
def dispatch(self, request, *args, **kwargs):
return super(LoginView, self).dispatch(request, *args, **kwargs)
def get_form_kwargs(self):
kwargs = super(LoginView, self).get_form_kwargs()
kwargs['request'] = self.request
return kwargs
def get_form_class(self):
return get_form_class(app_settings.FORMS, 'login', self.form_class)
def form_valid(self, form):
success_url = self.get_success_url()
try:
return form.login(self.request, redirect_url=success_url)
except ImmediateHttpResponse as e:
return e.response
def get_success_url(self):
# Explicitly passed ?next= URL takes precedence
ret = (get_next_redirect_url(
self.request,
self.redirect_field_name) or self.success_url)
return ret
def get_context_data(self, **kwargs):
ret = super(LoginView, self).get_context_data(**kwargs)
signup_url = passthrough_next_redirect_url(self.request,
reverse("account_signup"),
self.redirect_field_name)
redirect_field_value = get_request_param(self.request,
self.redirect_field_name)
site = get_current_site(self.request)
ret.update({"signup_url": signup_url,
"site": site,
"redirect_field_name": self.redirect_field_name,
"redirect_field_value": redirect_field_value})
return ret
login = LoginView.as_view()
if any one still having problem then you can use this one
{% if form.errors %}
{% for field in form %}
{% for error in field.errors %}
<div class="alert alert-error">
<strong>{{ error|escape }}</strong>
</div>
{% endfor %}
{% endfor %}
{% for error in form.non_field_errors %}
<div class="alert alert-error">
<strong>{{ error|escape }}</strong>
</div>
{% endfor %}
{% endif %}
Make sure to check for {{form.non_field_errors}} in addition to errors attached to specific fields.
for example I have form.email
And I want to modify this field after push button "Change email".
Code looks like below.
Template:
<form action="" method="post">{% csrf_token %}
{{ form.as_p }}
{% if mod_availiable == True %}
<span class="glyphicon glyphicon-ok"</span>
{% else %}
{{ email }}
{% endif %}
<br>
<input type="submit" value="Update" name="profile_update"/>
</form>
<form action="" method="post">
<input type="submit" value="Change Email" name="change_email"/>
</form>
View:
def get_context_data(self, **kwargs):
context = super(UserUpdate, self).get_context_data(**kwargs)
context['mod_availiable'] = False
return context
def post(self, request, *args, **kwargs):
self.object = self.get_object()
if "change_email" in request.POST:
context = get_context()
context['mod_availiable'] = True
return super(ProfileChange, self).post(request, *args, **kwargs)
After hitting Change email button, mod_availiable won't be True according my post() code.
Not 100% if I understand your "question". But is this what you want to do?
{% if mod_availiable %}
<form action="" method="post">{% csrf_token %}
{{ form.as_p }}
</form>
{% else %}
{{ email }}
{% endif %}
def post(self, request, *args, **kwargs):
if "change_email" in request.POST:
form = self.get_form()
return render(request, self.template_name, {'form': form,'mod_availiable': True})
template.html:
<form action="" method="post">{% csrf_token %}
{% for f in form %}
{% if f.name == 'email'%}
{% if mod_availiable == True %}
{{ f }}
{% else %}
{{ f.value }}
<input type="submit" value="Check" name="email_verify"/>
<form action="" method="post">
<input type="submit" value="Change Email" name="change_email"/>
</form>
{% endif %}
{% else %}
{{ f }}
{% endif %}
<br>
{% endfor %}
<input type="submit" value="Update" name="profile_update"/>
</form>
That was the main problem.
But still looks ugly, in case this is UpdateView -> context Won't update after button pushes.
How to implement working SearchView in existing views.py?
I already have CBV, and added in urls.py as /moderate and want to apply search form in it. but always got "Results No results found."
This is my /moderate page with 3 forms, using SearchView and piece of code from tutorial in template.
And this from /search page, with urls(r'^search/$', include('haystack.urls'))
urls.py
urlpatterns= [
url(r'^search/', include('haystack.urls')),
url(r'^moderate/', Moderate.as_view(), name='moderate'),
]
views.py
class Moderate(SearchView):
#method_decorator(staff_member_required)
def dispatch(self, *args, **kwargs):
return super(Moderate, self).dispatch(*args, **kwargs)
#model = Ad
template_name = 'adapp/ad_moderate.html'
#template_name = 'search/search.html'
paginator_class = DiggPaginator
paginate_by = 10
ad_type = None
ad_sub_type = None
def get_queryset(self):
qs = super(Moderate, self).get_queryset().filter(ad_type__isnull=False,
ad_sub_type__isnull=False)
return qs
def get_context_data(self, **kwargs):
context = super(Moderate, self).get_context_data(**kwargs)
context['filter'] = ModerateFilter(self.request.GET)
return context
# define method to recieve fields from form, and change data accordings
def post(self, request, *args, **kwargs):
selected = request.POST['selected']
record = Ad.objects.get(pk=int(selected))
form = ModerateForm(request.POST, instance=record)
if form.is_valid():
form.save(commit=True)
return HttpResponseRedirect('')
template/ad_moderate.html
{% extends 'base.html' %}
{% load i18n url_tags %}
{% block content %}
<div id="casing">
<div id="content">
{# filter form, to show only models with moderated=True #}
<form action="" method="get">
{{ filter.form.as_p }}
<input type="submit">
</form>
<h2>Search</h2>
{# search form right from tutorial #}
<form method="get" action="">
<table>
{{ form.as_table }}
<tr>
<td> </td>
<td>
<input type="submit" value="Search">
</td>
</tr>
</table>
{% if query %}
<h3>Results</h3>
{% for result in page.object_list %}
<p>
{{ result.object.title }}
</p>
{% empty %}
<p>No results found.</p>
{% endfor %}
{% else %}
{# Show some example queries to run, maybe query syntax, something else? #}
{% endif %}
</form>
{% for object in filter %}
{# a lot of template tags and third form to change value of model #}
<form action="" method="POST">
{% csrf_token %}
<input type="radio" name="moderated" value="True">Accept
<br>
<input type="radio" name="moderated" value="False">Decline
<input type="hidden" value="{{ object.id }}"
name="selected">
<input class="btn" type="submit" value="moderate">
</form>
search_indexes.py
from .models import Ad
class AdIndex(indexes.SearchIndex, indexes.Indexable):
text = indexes.CharField(document=True, use_template=True)
def get_model(self):
# my model, with one search should be
return Ad
templates/search/indexes/app/ad_text.txt
{{ object.title }}
{{ object.short_desc }}
{{ object.description }}
{{ object.experience }}
{{ object.skills }}
{{ object.name }}
{{ object.city }}
get_context_data():
context['search'] = SearchForm(self.request.GET).search()
Would solve a problem.
That means, I should create form and send return from .save() method, rather that django-like form instance.