wWay to find id in tag - html

I am creating a followers list to the sidebar.
How can I get author_id in my custom tag?
#register.inclusion_tag('list_followers.html', takes_context=True)
def show_followers(context, author_id):
request = context['request']
if request.user.is_authenticated:
followers = Profile.objects.filter(name=author_id)
return {'followers': followers}
_sidebar.html
Thanks...
I tried to get author_id from views.py to posts_tags.py
def author_info(request, author_id):
"""return following users"""
current_user = request.user.id
author = User.objects.get(id=author_id)
..............
or get author_id in _sidebar.html somehow
{% load posts_tags %}
...........
<div class="media">
<div class="p-3 border bg-light">
<div class="container">
{% show_followers author_id=here %}
</div>
</div>
</div>
but I couldn't...

In your author_info view, pass the author_id to the show_followers tag using the context dictionary:
from django.shortcuts import render
def author_info(request, author_id):
current_user = request.user.id
author = User.objects.get(id=author_id)
context = {
'author_id': author_id,
}
return render(request, 'your_template.html', context)
In case you decide to use class based view the views.py will look like:
from django.views import View
from django.shortcuts import render
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth.models import User
class AuthorInfoView(LoginRequiredMixin, View):
login_url = '/login/'
def get(self, request, author_id):
current_user = request.user.id
author = User.objects.get(id=author_id)
context = {
'author_id': author_id,
}
return render(request, 'your_template.html', context)
In your template (_sidebar.html), pass the author_id to the show_followers tag:
{% load posts_tags %}
...........
<div class="media">
<div class="p-3 border bg-light">
<div class="container">
{% show_followers author_id=author_id %}
</div>
</div>
</div>

Related

Preserve and display Django form inputs on POST submission

--PROBLEM--
I have created a basic calculator using Django.
The app takes some basic form inputs before executing some calculations and returning the outcomes to the user, however I want the user's inputs to remain visible in the form on submission.
At present the followin experience occurs.
User enters values into form and submits using 'Calculate' button.
Results are returned as expected but form and values are no longer present.
User can press 'Calculate' button to return to start of process and blank form.
--DESIRED OUTCOME--
--CODE--
forms.py
from django import forms
class InvestmentForm(forms.Form):
starting_amount = forms.FloatField()
number_of_years = forms.FloatField()
return_rate = forms.FloatField()
annual_additional_contribution = forms.FloatField()
views.py
from django.shortcuts import render
from django.views import View
from .forms import InvestmentForm
class Index(View):
def get(self, request):
form = InvestmentForm()
return render(request, 'loancalculator/index.html', {'form': form})
def post(self, request):
form = InvestmentForm(request.POST)
if form.is_valid():
total_result = form.cleaned_data['starting_amount']
total_interest = 0
yearly_results = {}
for i in range(1, int(form.cleaned_data['number_of_years'] +1)):
yearly_results[i] = {}
# CALCULATE THE INTEREST
interest = total_result * (form.cleaned_data['return_rate'] / 100)
total_result += interest
total_interest += interest
# ADDITIONAL CONTRIBUTION
total_result += form.cleaned_data['annual_additional_contribution']
# SET YEARLY RESULTS
yearly_results[i]['interest'] = round(total_interest, 2)
yearly_results[i]['total'] = round(total_result,2)
# CREATE CONTEXT
context = {
'total_result': round(total_result,2),
'yearly_results': yearly_results,
'number_of_years': int(form.cleaned_data['number_of_years'])
}
# RENDER THE TEMPLATE
return render(request, 'loancalculator/index.html', context)
else:
form = InvestmentForm()
return render(request, 'loancalculator/index.html', {'form':form})
index.html
{% extends 'loancalculator/base.html' %}
{% load crispy_forms_tags %}
{% block content %}
<div class="row justify-content-center">
<div class="col-4 border bg-light">
<div class="row t-5">
<div class="col-12 col-md-6 mx-md-auto">
<h1> Investment Calculator</h1>
<h5> Enter the details below to see your estimate</h5>
<form action="" method="POST">
{% csrf_token %}
{{ form|crispy }}
<button class="btn btn-primary" type="submit">Calculate</button>
</form>
<br>
</div>
</div>
</div>
<div class="col-4 border">
<div class="row t-5">
<div class="col-12 col-md-6 mx-md-auto">
<h1>Investment Results</h1>
<h3> After {{ number_of_years }} years, your investment is worth ${{ total_result }}</h3>
<div class="mt-5">
<table class="table">
<thead>
<tr>
<th scope="col">Year</th>
<th scope="col">Interest</th>
<th scope="col">Total</th>
</tr>
</thead>
<tbody>
{% for key, value in yearly_results.items %}
<tr>
<th scope="row">{{ key }}</th>
<td>{{ value.interest }}</td>
<td>{{ value.total }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock content %}
Two ways you can go about doing what you want as I see it:
Method 1
Use sessions to hold the data and then refeed it to the form using initial form values. This is probably the easiest since it most closely matches what you already have.
class Index(View):
def get(self, request):
# Fill in the initial values on the unbound form:
initial = {
'starting_amount': request.session.get('starting_amount'),
'number_of_years': request.session.get('number_of_years'),
'return_rate': request.session.get('return_rate'),
'annual_additional_contribution': request.session.get('annual_additional_contribution'),
}
form = InvestmentForm(initial=initial)
return render(request, 'home/index.html', {'form': form})
def post(self, request):
form = InvestmentForm(request.POST)
if form.is_valid():
# After getting the cleaned_data, set a session variable to hold it
total_result = form.cleaned_data['starting_amount']
request.session['starting_amount'] = total_result
number_of_years = int(form.cleaned_data['number_of_years'])
request.session['number_of_years'] = number_of_years
return_rate = form.cleaned_data['return_rate']
request.session['return_rate'] = return_rate
annual_additional_contribution = form.cleaned_data['annual_additional_contribution']
request.session['annual_additional_contribution'] = annual_additional_contribution
total_interest = 0
yearly_results = {}
for i in range(1, number_of_years +1):
yearly_results[i] = {}
# CALCULATE THE INTEREST
interest = total_result * (return_rate / 100)
total_result += interest
total_interest += interest
# ADDITIONAL CONTRIBUTION
total_result += annual_additional_contribution
# SET YEARLY RESULTS
yearly_results[i]['interest'] = round(total_interest, 2)
yearly_results[i]['total'] = round(total_result,2)
# CREATE CONTEXT
context = {
# CHANGED: pass the 'form' to the context!
'form': form,
'total_result': round(total_result,2),
'yearly_results': yearly_results,
'number_of_years': number_of_years
}
# RENDER THE TEMPLATE
return render(request, 'home/index.html', context)
else:
form = InvestmentForm()
return render(request, 'home/index.html', {'form':form})
Method 2
From what you show here, anyway, you could just use JavaScript to do the calculations by grabbing the values directly from the DOM after they are entered, doing the calculations on the front end with JavaScript, and then fill in the values by targeting the locations where you want the results displayed in the DOM. No need for forms, no reloading of pages.
When you create the context, the value 'form' doesn't get set (views.py, under get())

I can submit data but won't go to new page -or- go to new page and data doesn't get saved in Django

So the title kind of says it all. I have a form based on a model. The goal is to have the specific data entered, user presses submit, data gets saved to a Postgresql DB, user sees complete.html. However this is not the case. I can either get the data to save without changing pages, or the page will change but the data will not submit. I have put details on the specifics of I tried below.
urls.py
from django.urls import path, include
from . import views
urlpatterns = [
path('', views.index, name='index-page'),
path('feedback/', views.feedback_view, name = 'feedback'),
path('complete/', views.complete, name = 'complete')
]
models.py
from django.db import models
from django.utils import timezone
from django.core.validators import RegexValidator
class feedback(models.Model):
RECENT_GROUND = [
('PVT','Private'),
('INS','Instrument'),
('COM','Commercial'),
('MEL','Multi-Engine'),
]
RATING = [
(1,'Poor'),
(2,'Below Average'),
(3,'Average'),
(4,'Above Average'),
(5,'Excellent'),
]
id_field = models.AutoField(primary_key = True, serialize = True)
added = models.DateTimeField(default = timezone.now)
spid = models.CharField(primary_key = False, max_length=5, verbose_name = 'Enter the students FSA ID number:')
recent_ground = models.CharField(max_length = 3, choices = RECENT_GROUND, verbose_name = 'Most recently completed ground school:')
question1 = models.IntegerField(choices = RATING, verbose_name = 'This is question 1')
question2 = models.IntegerField(choices = RATING, verbose_name = 'This is question 2')
question3 = models.IntegerField(choices = RATING, verbose_name = 'This is question 3')
question4 = models.IntegerField(choices = RATING, verbose_name = 'This is question 4')
question5 = models.IntegerField(choices = RATING, verbose_name = 'This is question 5')
question6 = models.IntegerField(choices = RATING, verbose_name = 'This is question 6')
question7 = models.IntegerField(choices = RATING, verbose_name = 'This is question 7')
comments = models.TextField(max_length = 500, verbose_name = 'Please leave any additional comments below. If you do not wish to leave comments, type "none".')
def __str__(self):
return self.title
forms.py
#imports forms class from django
from django import forms
#imports the feedback class from ipfeedbackdb/models.py
from ipfeedbackdb.models import feedback
class feedbackForm(forms.ModelForm):
class Meta:
model = feedback
fields = "__all__"
exclude = ['recID','added']
views.py
from django.shortcuts import render
from .forms import feedbackForm as feedform
def index(request):
return render(request, 'index/index.html', {'title':' Home'})
# def feedback(request):
# return render(request, 'index/feedback.html', {'title':' Collection'})
def feedback_view(request):
context = {}
form = feedform(request.POST or None, request.FILES or None)
if form.is_valid():
form.save()
context['form'] = form
return render(request, "index/feedback.html", context)
def complete(request):
return render(request, 'index/complete.html', {'title':' Submitted'})
base.html (removed most of the styling to reduce length)
{% load static %}
<!doctype html>
<html lang="en">
<head>
<link rel="stylesheet" href="{% static 'index/override.css' %}">
{% if title %}
<title>Feedback{{ title }}</title>
{% else %}
<title>Feedback Site</title>
{% endif %}
<script type="text/javascript">
window.history.forward();
function noBack() { window.history.forward(); }
</script>
</head>
<body onload="noBack();" onpageshow="if (event.persisted) noBack();" onunload="">
<div class = 'jumbotron jumbotron-fluid'>
<div class = 'container'>
<h2 class = 'display-4' style = 'color:#fff;margin-left: -100px'>FSA</h2>
<p class = 'lead' style = 'color:#fff;;margin-left: -97px'>Feedback</p>
</div>
</div>
<div>
{% block content %}
{% endblock content %}
</div>
</body>
</html>
index.html
{% extends 'index/base.html' %}
{% block content %}
<div>
<h2>Index Page</h2>
<p>This is some more added text.</p>
</div>
<div>
Next ->
</div>
{% endblock content %}
feedback.html (action = "" saves data without changing pages or clearing form, action ="/feedback/" will save but not clear the form or go to another page. action = "/complete/" took me to complete.html but it did not submit the data to the database.)
{% extends 'index/base.html' %}
{% load crispy_forms_tags %}
{% block content %}
<div>
<h2>Feedback Form Page</h1>
</div>
<div>
<form action = "" method = "post">
{% csrf_token %}
{{ form| crispy }}
<input type="submit" name="Submit">
</form>
</div>
{% endblock content %}
complete.html
{% extends 'index/base.html' %}
{% block content %}
<h2>Your feedback has been submitted. Thank you!</h2>
<div>
Return to start
</div>
{% endblock content %}
In your feedback view, once forms is valid it doesn't go to complete.
def feedback_view(request):
context = {}
form = feedform(request.POST or None, request.FILES or None)
if form.is_valid():
form.save()
return render(request, "index/complete.html", context)
else:
context['form'] = form
return render(request, "index/feedback.html", context)
use button tag!
replace:
<button type="submit">submit</button>
with:
<input type="submit" name="Submit">
change your view like below
views.py:
from django.contrib import messages
from django.shortcuts import redirect
def feedback_view(request):
context = {}
form = feedform(request.POST or None, request.FILES or None)
if request.method == 'POST':
if form.is_valid():
form.save()
return redirect('app_name:url_name') # change to where you want to redirect after a successful from submition
messages.success(request, "Form submitted successfully")
else:
messages.warning(request, form.errors)
context['form'] = form
return render(request, "index/feedback.html", context)

Django How to Post comment on only one List item

I am trying to create django commerce app I am little bit stuck on a thing
When I post comment via form I created
<form action="{% url 'comment' list_id.id %}" method="POST">
{% csrf_token %}
<textarea name="comment" class="inp-cmt" rows="3"></textarea>
<input type="submit">
</form>
the comment is posted but it post on all of my list page I wanted only on the page where comment is posted
my comment section
{% if allcomments %}
<h1>Comments</h1>
<div class="card-cmt">
{%for com in allcomments%}
<li style="list-style: none;">
<footer class="post-info">
<span>{{com.user}}</span>
<p>{{com.text}}</p>
</footer>
</li>
{% endfor %}
</div>
{% endif %}
my urls
urlpatterns = [
path("", views.index, name="index"),
path("login", views.login_view, name="login"),
path("logout", views.logout_view, name="logout"),
path("register", views.register, name="register"),
path("newlist", views.create_listing, name="new_list"),
path("item", views.add_item, name="new_item"),
path("listing/<int:list_id>", views.listing, name="listing"),
path("delete/<int:item_id>", views.delete_list, name="delete"),
path("comment/<int:list_id>", views.comments, name="comment")
]
my views for comment and listing
def comments(request, list_id):
coms = Comments()
if request.method == 'POST':
coms.user = request.user.username
coms.text = request.POST.get('comment')
coms.listid = list_id
coms.save()
return redirect('listing', list_id)
else :
return redirect('index')
def listing(request, list_id):
list_item = Listing.objects.get(id=list_id)
return render(request, "auctions/listing.html",{
"list_id" : list_item,
"allcomments" : Comments.objects.all()
})
models
class Listing(models.Model):
owner = models.CharField(max_length =64,default="N/A")
productname = models.CharField(max_length=100)
price = models.DecimalField(max_digits=10, decimal_places=2)
description = models.CharField(max_length=999, default="test")
date = models.DateField(auto_now_add=True)
link = models.CharField(max_length=200, default="test1")
def __str__(self):
return f"{self.owner} {self.productname} {self.price} {self.date} {self.description} {self.link}"
class Comments(models.Model):
user = models.CharField(max_length=64)
text = models.TextField()
date = models.DateTimeField(auto_now_add=True)
listid = models.IntegerField(default=0)
def __str__(self):
return f"{self.user} {self.text} {self.date} {self.listid}"
You're returning all comments on every listing when you do "allcomments" : Comments.objects.all()
The problem is in your listing function. Try this instead:
def listing(request, list_id):
list_item = Listing.objects.get(id=list_id)
return render(request, "auctions/listing.html",{
"list_id" : list_item,
"allcomments" : Comments.objects.filter(listid=list_id)
})
Notice the change - from "allcomments" : Comments.objects.all() to "allcomments" : Comments.objects.filter(listid=list_id)
Also, your implementation for class Comments and class Listing could be a bit better. Have you ever come across something called a ForeignKey? It will be a lot more efficient to use that. https://docs.djangoproject.com/en/3.1/ref/models/fields/#django.db.models.ForeignKey

Django image upload form not working

I am having trouble uploading the image in Django Form.
The following form fails to validate due to some issue in the image uploading
Here is the code :
forms.py
from django import forms
from .models import Description, Bill
class DForm(forms.ModelForm):
class Meta:
model = Description
fields = ('desc', 'billing', 'length', 'quality', 'rate')
class BForm(forms.ModelForm):
party = forms.CharField(widget=forms.TextInput(attrs={'class':'form-control','placeholder':'Party'}))
inovice = forms.FloatField(widget=forms.TextInput(attrs={'class':'form-control','placeholder':'Invoice#'}))
amount = forms.FloatField(widget=forms.TextInput(attrs={'class':'form-control','placeholder':'Bill-Amount'}))
image = forms.ImageField()
image_caption = forms.CharField(widget=forms.TextInput(attrs={'class':'form-control','placeholder':'Description for bill'}))
class Meta:
model = Bill
fields = ('party', 'inovice', 'amount','image','image_caption')
models.py
from __future__ import unicode_literals
#from django.utils.encoding import python_2_unicode_compatible
from django.db import models
##python_2_unicode_compatible
class Description(models.Model):
desc = models.CharField(max_length = 200,default = "Suits")
billing = models.FloatField(max_length = 200)
length = models.FloatField(max_length = 200)
quality = models.CharField( max_length=200,default = "custom")
rate = models.FloatField(max_length = 200)
def __str__(self):
return self.desc
class Bill(models.Model):
party = models.CharField(max_length = 200)
inovice = models.FloatField(max_length = 200)
amount = models.FloatField(max_length = 200)
image = models.ImageField(upload_to='images/products/main',null=True, blank=True)
image_caption = models.CharField(max_length=200,default = "null")
def __str__(self):
return self.party+','+str(self.inovice)+','+str(self.amount)
def bill_id(self):
return self.id;
index.html
{% load staticfiles %}
<!-- test -->
<html>
<head>
<title></title>
<link href="{%static "./styles/bootstrap.min.css" %}" rel="stylesheet" />
</head>
<body>
<h1 style="text-align: center;">Rahul's Shop</h1>
<h2 style="text-align: center;">Inventory</h2>
<form enctype="multipart/form-data" id="bill" action ="{% url 'front:commitbill' %}" method = "post" class="form-horizontal">
{% csrf_token %}
{% for field in form %}
<div class="form-group">
<label for="party" class="control-label col-md-3">{{ field.name }}</label>
<div class="col-md-4">
{{ field }}
</div>
<div class="col-md-5">
<span id="one" style="position:relative; top:5px; color:red "></span>
</div>
</div>
{% endfor %}
<div class="container">
<div class="row">
<input type="button" id="add_items" class="col-md-offset-5 col-md-2 btn btn-success" value="Add items" \>
</div>
</div>
</form>
and views.py
from django.shortcuts import render
from django.http import HttpResponse
from .models import Description, Bill
from django.http import Http404
from .forms import DForm
from .forms import BForm
import pprint
def bill(request):
try:
billinfo = Description.objects.all()
context = {'billinfo': billinfo}
except Description.DoesNotExist:
raise Http404("No Bills")
return render(request, 'front/bill.html', context)
def commitvalues(request):
if request.method == "POST":
form = DForm(request.POST)
if form.is_valid():
Description = form.save()
print Description
return HttpResponse("Hello;You're at the front index.Commit's done!")
print form.errors
return HttpResponse("Fail")
def commitbill(request):
form = BForm()
if request.method == "POST":
form = BForm(request.POST,request.FILES)
if form.is_valid():
Bill = form.save()
return HttpResponse(str(Bill.bill_id()))
else:
print form.errors
form = BForm()
return render(request, 'front/index.html', {
'form': form
})
The print form.errrs returns the following two errors :
<ul class="errorlist"><li>image<ul class="errorlist"><li>This field is required.</li></ul></li></ul>
The forms starts working fine when i remove the image = forms.ImageField() from my forms.py, just the image doesn't uploads, otherwise when i include image = forms.ImageField(), the form never saves due to the above Error

form field not showing (django 1.7)

The form field (text area) is not showing in my django template. I can figure out where the problem is.
Views.py
class Profile(View):
"""User Profile page reachable from /user/<username> URL"""
def get(self, request, username):
params = dict()
user = User.objects.get(username=username)
tweets = Tweet.objects.filter(user=user)
params["tweets"] = tweets
params["user"] = user
return render(request, 'profile.html', params)
class PostTweet(View):
"""Tweet Post form available on page /user/<username> URL"""
def post(self, request, username):
if request.method == 'GET':
form = TweettForm()
else:
form = TweetForm(self.request.POST)
if form.is_valid():
user = User.objects.get(username=username)
tweet = Tweet(text=form.cleaned_data['text'], user=user, country=form.cleaned_data['country'])
tweet.save()
words = form.cleaned_data['text'].split(" ")
for word in words:
if word[0] == "#":
hashtag, created = HashTag.objects.get_or_create(name=word[1:])
hashtag.tweet.add(tweet)
return HttpResponseRedirect('/user/'+username)
return render(request, 'profile.html', {'form': form})
forms.py
from django import forms
class TweetForm(forms.Form):
text = forms.CharField(widget=forms.Textarea(attrs={'rows': 1, 'cols':85}), max_length=160)
country = forms.CharField(widget=forms.HiddenInput())
profile.html
{% extends "base.html" %}
{% block content %}
<div class="row clearfix">
<div class="col-md-12 column">
<form method="post" action="post/">{% csrf_token %}
<div class="col-md-8 col-md-offset-2 fieldWrapper">
{{ form.text.errors }}
{{ form.text }}
</div>
{{ form.country.as_hidden }}
<div>
<input type="submit" value="post">
</div>
</form>
</div>
urls.py
from django.conf.urls import patterns, include, url
from django.contrib import admin
from tweets.views import Index, Profile, PostTweet
admin.autodiscover()
urlpatterns = patterns('',
url(r'^$', Index.as_view()),
url(r'^user/(\w+)/$', Profile.as_view()),
url(r'^admin/', include(admin.site.urls)),
url(r'^user/(\w+)/post/$', PostTweet.as_view())
)
Only the submit (post) button shows on the on when rendered in the browser. The text are is not there
You get nothing since you are not passing the form to the template. Write get function in PostTweet view and include form = TweetForm() in it as a param passed to the template.