I am using Cryptocompare.com api to load news from cryptocurrencies world. In the template I am looping through it show it on the home-page. I would like to add feature that if you click send button it will send an email to you with the link for the news you just clicked. What is the best way to do it? I tried that, but I dont know how to link the clicked element with the url in views.
def home(request):
# Grab Crypto News
api_request = requests.get('https://min-api.cryptocompare.com/data/v2/news/?lang=EN')
api = json.loads(api_request.content)
return render(request, 'crypto/crypto_home.html', {'api': api})
def SendLink(request):
if request.method == 'POST':
subject = 'Link to crypto news'
from_email = 'test#gmail.com'
message = 'Hello {}, here is your link:'.format(request.user)
to_email = [request.user.email]
send_mail(
subject,
message,
from_email,
to_email
)
return HttpResponseRedirect(reverse('crypto-home'))
Template:
{% for x in api.Data %}
<div class='col-sm'>
<div class="card">
<img class="card-img-top" src="{{ x.imageurl }}" alt="{{ x.source }}">
<div class="card-body">
<h5 class="card-title">{{x.title}}</h5>
<p class="card-text">{{ x.body|safe }}.</p>
<div class="btn-group btn-group-sm" role='group'>
Read More
<form method="post" action="{% url 'send_link' %}">
{% csrf_token %}
<button id="{{x.id}}" target="_blank" class="btn btn-primary">Send to e-mail</button>
</form>
</div>
</div>
</div>
</div>
{% endfor %}
I would like to add link from template 'x.url' to views to be able to add the link to the message variable. I also tried to link it via ID of the news but I am not able to pass it to the views. Any idea how I can do that? Thanks
It looks like you need to add a hidden field to your form for the URL you'd like to pass to your view:
<input type="hidden" id="URL" name="URL" value="{{x.url}}">
Once you have that variable in your view you should be able to add it to your email template.
Related
I have a Django form that receives a text (that I copy from Google Classroom: a bunch of student comments). I use these comments to make student's attendance. What I want to achieve is:
Accessing /insertion/ url via GET user receive the page form as a response, to choose the class (class01, class02, etc) and to past the text
When the user clicks on submit in this form (post method), it is redirect to the same /insertion/ url, but now the form is bound to the data submited, and the page shows a preview page (based on a boolean variable I'm passing through context), showing what students are present and what are absent based on the text informed. At that page, a new submit button will be shown below a text like "if everything's ok, hit the ok button".
After click this ok button, a pdf will be generated and the user will be redirected to /files/ url, to see the generated pdf and previous generated pdf.
views.py
def insertion(request):
context = {}
if request.method == 'GET':
form = AttendanceDataForm()
context.update({"form": form})
if request.method == 'POST':
form = AttendanceDataForm(request.POST)
context.update({"form": form})
if form.is_valid():
lesson = form.cleaned_data['lesson']
raw_text = form.cleaned_data['raw_text']
# Get course students
course_students = md.Student.objects.filter(course_id=lesson.course_id)
# Get present students based on raw text informed
present_students = [s for s in course_students if s.full_name in raw_text]
# Get absent students based on raw text informed
absent_students = [s for s in course_students if s.full_name not in raw_text]
context.update({
"present_students": present_students,
"absent_students": absent_students,
"render_preview": True
})
context.update({"active_freq": True})
return render(request, 'core/insertion.html', context)
def files(request):
context = {}
if request.method == 'POST':
# How can I access all expensive calculation I did in the previous view?
context.update({"active_gen": True})
return render(request, "core/files.html", context)
insertion.html
<div class="row">
<div class="col-12 col-md-6">
<h3>Informar Frequência</h3>
{% crispy form %}
</div>
<div class="col-12 col-md-6">
{% if render_preview %}
<div class="container">
<div class="row p-4 bg-white rounded mt-4">
<div class="col-12 col-sm-6">
<h5>Alunos presentes</h5>
<ul class="previewer-list">
{% for student in present_students %}
<li>{{ student.id }} - {{ student.full_name }}</li>
{% endfor %}
</ul>
</div>
<div class="col-12 col-sm-6">
<h5>Alunos ausentes</h5>
<ul class="previewer-list">
{% for student in absent_students %}
<li>{{ student.id }} - {{ student.full_name }}</li>
{% endfor %}
</ul>
</div>
</div>
<p class="mt-3">If everything's ok, hit the OK button</p>
<form method="post" action="{% url "core:files" %}">
{% csrf_token %}
<button type="submit" class="btn btn-primary">OK</button>
</form>
</div>
{% endif %}
</div>
</div>
I could get to implement 1 and 2, but 3 is a mistery right now. What I couldn't get is how I can access the expensive calculations I did in insertion view in the files view. How can I do that?
Here's a solution using session framework.
We'll save the calculations in the session and access those values in another view later.
For starters, we'll just save the ids (pk) of the students instead of the student instances because they are not JSON serializable [See note below].
def insertion(request):
# do expensive calucations ...
present_ids = [s.pk for s in present_students]
absent_ids = [s.pk for s in absent_students]
request.session['attendance_data'] = {
'present_ids': present_ids,
'absent_ids': absent_ids
}
def files(request):
attendance_data = request.session.get('attendance_data')
if not attendance_data:
# show error or something else ...
pass
present_students = md.Student.objects.filter(
pk__in=attendance_data['present_ids']
)
absent_students = md.Student.objects.filter(
pk__in=attendance_data['absent_ids']
)
# generate the pdf ...
Note: If you wish, you can also save the student instances in the session but you'll have to change the SESSION_SERIALIZER setting to use the PickleSerializer. See notes about session serialization.
You could submit the primary keys as form data in hidden fields. Just choose an appropriate delimiter based on your primary key (for example, don't delimit with a hyphen if you use a GUID primary key).
<form method="post" action="{% url "core:files" %}">
{% csrf_token %}
<input type="hidden"
name="present"
value="{% for s in present_students %}{{ s.pk }},{% endfor %}"
>
<input type="hidden"
name="absent"
value="{% for s in absent_students %}{{ s.pk }},{% endfor %}"
>
<button type="submit" class="btn btn-primary">OK</button>
</form>
Then in the view you can pick up the PKs in the view from the form data then request.
def files(request):
context = {}
if request.method == 'POST':
present_pks = request.POST.pop('present').split(',')[:-1]
absent_pks = request.POST.pop('absent').split(',')[:-1]
# do type conversions if needed
...
# Because we already have the pks separated, we can combine them
# for the query in order to do just 1 query
course_students = md.Student.objects.filter(pk__in=present_pks + absent_pks).all()
absent_students = []
present_students = []
for student in course_students:
if student.pk in absent_pks:
absent_students.append(student)
else:
present_students.append(student)
I have been trying to create a to do list app and there has been no problems until when i was adding an edit button, when i press the edit button, it shows the edit page with the text that has to be edited but the submit button that is suposed to change the database is not working, I think I need to add something to the views.py file but I dont know what.
viws.py
def edit(request, id):
created_items = Create.objects.get(id=id)
return render(request, 'my_app/edit.html', {"created_items": created_items})
urls.py
urlpatterns = [
path('edit/<int:id>/', views.edit, name='edit'),
]
models.py
class Create(models.Model):
added_date = models.DateTimeField()
text = models.CharField(max_length=200)
edit.html
{% extends 'index.html' %}
{% block body %}
<div align="center">
<h1>Edit your post!</h1>
<div class="container form-group">
<h1>↓</h1>
<form method="POST">{% csrf_token %}
<textarea class="form-control" name="content" id="id" rows="3" style="text-align: center;">{{ created_items.text }}</textarea>
<button type="submit" class="btn btn-outline-success" style="margin-top: 5px;">Submit</button>
</form>
</div>
</div>
{% endblock %}
You will send POST request when you click submit and need to catch that request in some function like:
if request.method == 'POST':
edited_text = request.POST.get('text') ## 'text' might be changed. I don't know how you handle the request.
related_id = request.POST.get('id') ## You need to take updated id. (somehow?)
Create.objects.filter(id=related_id).update(text=edited_text) ## That will do the job.
Hope it helps,
i want to add search in my website and i want search from my pages (html)
** note : i want grab the label tag , i mean for example :
i have label tag called ' test ' and when user write in search bar 'test' i want view the label to user in new page
my label like this :
<label id="label_main_app">
<img id="img_main_app_first_screen" src="{% static " images/android_studio.jpg " %}" alt=""> test
<br>
<br>
<p id="p_size_first_page">this is an test app
<br>
<br>
<big> See More & Download </big>
</p>
</label>
always i got this message in result page : not found
my code : * this form in home html page
<form class="" action="{% url 'test_search_page'%}" method="get">
<div class="md-form mt-0 search-bar" id="search_form">
<input id="search_box" autocomplete="off" onkeyup="searchFunction()" class="form-control" type="text" placeholder="Write Here to Search ..." aria-label="Search" name="search">
</div>
</form>
and this is my view.py code :
def search(request):
input= 'search'
my_template_keyword = ['label']
if 'search' in request.GET and request.GET['search'] and input == my_template_keyword:
return render(request, 'home_page/testforsearch.html', {'search:':search})`
finally this is my code in html result page :
<div class="container">
{% if search %}
{{ search }}
{% else %}
<h2>not found</h2>
{% endif %}
</div>
any help please ?
I couldn't see the query for database search. Use generic display views like this:
from django.views.generic.list import ListView
from .models import Videos
class Search(ListView):
model = Videos
template_name = "/search.html"
paginate_by = 30
def get_queryset(self):
query = self.request.GET.get('search')
if query:
object_list = self.model.objects.filter(title__icontains=query)
else:
object_list = self.model.objects.none()
return object_list
My problem is that when the user creates a new record on the database in my webpage (Mysql) and the system redirects the user to the list of elements created, the new element won't show up until I click again the link option on a section. In other words I want django to show the new results when I redirect the user to the list, here's some fragments of code I'm using:
This is the link where the user clicks to show the list after creating a new object:
<div class="modal-footer">
<div class="col-lg-12 text-right">
Regresar a Listado
</div>
</div>
This is the list where I show the elements from the database:
{% for portal in portal_list %}
<section class="search-result-item">
<a class="image-link" href="/microsite/myportal/view/{{portal.portal_id}}">
<img class="image" src="{% static 'img/template-icon.png' %}">
</a>
<div class="search-result-item-body">
<div class="row">
<div class="col-sm-9">
<h4 class="search-result-item-heading">
No. de Plantilla : {{portal.portal_id}}
</h4>
<p class="description">
ID Terminos: {{portal.terms_id}}
</p>
</div>
<div class="col-sm-3 text-align-center">
<p class="value3 text-gray-dark mt-sm">
{{ randomNumber|random }} visitas
</p>
<p class="fs-mini text-muted">
Por Semana
</p>
<br>
Ver Detalles
</div>
</div>
</div>
</section>
{% endfor %}
Here's my function in views: (The object that comes from MySQL is called myportal_list)
from django.shortcuts import render
from django.http import HttpResponseRedirect
def myportal_list(request, device_serial):
logger.debug("views - myportal_create")
deviceObject = CaptivePortalService.CaptivePortalService().getNetwork(device_serial)
captive_portal_list=""
context = {'device_object': deviceObject}
myportal_list = my_portal.objects.all()
context['portal_list'] = myportal_list
number = []
for i in myportal_list:
number.append(randint(0, 25))
context['randomNumber'] = number
return render(request, URL_MYPORTAL_LIST, context)
And finally there's my list of options, that is actually the only way to show the new data from the database: (even if i press F5 the new data wont show)
<ul id="network-option" class="panel-collapse collapse ">
<li class="">Mi Portal</li>
<!-- <li class="">Configuraciones de Accceso</li> -->
<li class="">Configuraciones de Accceso</li>
<li class="">Promociones</li>
<li class="">Términos de Uso</li>
</ul>
The view function where I create a new record: (Im handling the response with AJAX to be able to handle messages if there's an error or if the form was submitted correctly, in this case the messages are listed in the modal footer that I posted first)
def myportal_create(request, device_serial):
if request.method == "GET":
logger.debug("views - myportal_create")
deviceObject = CaptivePortalService.CaptivePortalService().getNetwork(device_serial)
captive_portal_list=""
context = {'device_object': deviceObject}
promotion_list = promotions.objects.all()
context['promo_list'] = promotion_list
terms_list = use_terms.objects.all()
context['terms_list'] = terms_list
return render(request, URL_MYPORTAL_CREATE, context)
if request.method == "POST":
form = PortalForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect("/microsite/myportal/list/"+ device_serial)
else:
print(form.errors)
Also I have the correct configuration to use MySQL on settings so I don't think that being the problem.
Thanks for the time.
I got a problem displaying photos from my uploads folder.
I have a form where user can enter title, description and upload a image, then insert it into database. I can display all the data I just added on my template except the image, there just a X instead of image.
ps. image is successfully downloaded to uploads folder and it filename successfully added to database. It just doesnt display on the page.
app.py
#route to content page
#app.route('/dashboard', methods = ['GET', 'POST'])
def dashboard():
error = None
form = MessageForm()
if form.validate_on_submit():
filename = secure_filename(form.photo.data.filename)
form.photo.data.save(os.path.join('uploads/', filename))
new_message = BlogPost(
form.title.data,
form.description.data,
form.photo.data.filename,
current_user.id
)
db.session.add(new_message)
db.session.commit()
flash("Your recipe was successfully posted. Thanks!")
posts = db.session.query(BlogPost).all()
return render_template('dashboard.html', posts = posts, form = form,
error = error)
else:
posts = db.session.query(BlogPost).all()
return render_template('dashboard.html', posts = posts, form = form,
error = error)
template
{% for post in posts %}
<div class="col-xs-12 col-sm-6 col-md-4 col-lg-5 masonry-item">
<div class="box-masonry"><a href="#" title="" class="box-masonry
image with-hover-overlay">
<img src="uploads/{{ post.photo }}" alt="" class="img-responsive"
</a>
<div class="box-masonry-hover-text-header">
<h4> {{ post.title }}</h4>
<div class="box-masonry-desription">
<p>{{ post.description }}</p>
<p><strong>{{ post.author.name }}</strong></p>
</div>
</div>
</div>
</div>
{% endfor %}
From the Flask Doc :
To generate URLs for static files, use the special 'static' endpoint
name:
url_for('static', filename='style.css')
The file has to be stored on the filesystem as static/style.css.
And in your case you should use:
{{ url_for('static', filename='uploads/' + post.photo) }}