I'm begginer in making django projects.
I'm creating easy app which plots earthquakes positions on map with data from api.
One of features of my app is the possibility to paste range of dates to my api query.
I made the form which includes the datepicker and the code in views that i suppose should handle it.
I have problem because my submit button that should grab data from datepicker doesn't work.
Or may be i did something wrong in my views and it cannot take data from post method to variable datebeg and dateend
Any idea?
views.py
def graph(request):
#=========data=========================================================================
datebeg='2021-03-19'
dateend='2021-03-20'
if request.method == 'post':
datebeg=request.POST['datebeg']
dateend = request.POST.get("dateend")
if datebeg=='':
datebeg='2021-03-21'
if dateend=='':
dateend='2021-03-21'
graph.html
<body>
<div class="container my-container">
<form action="{% url 'graph' %}" method="post">
{% csrf_token %}
<div class= "row my-row">
<div class="col-4 my-col">
Trzęsienia ziemi z zakresu dat:
</div>
<div class="col-4 my-col">
od:
<input type="date" placeholder="0" name="datebeg" size="1" />
</div>
<div class="col-4 my-col">
do:
<input type="date" placeholder="0" name="dateend" size="1" />
</div>
<a class="btn btn-primary" type="submit" href="{% url 'graph'%}" >Pokaż na mapie</a>
</div>
</form>
</div>
graph/urls.py
from django.contrib import admin
from django.urls import path,include
from . import views
urlpatterns = [
path('', views.graph,name='graph'),
]
Yours if condition is invalid
You need to use
if request.method == 'POST':
In Django 3>, best practice is to use Class Based Views, you don't need to add that condition in case of:
from django.http import HttpResponse
from django.views import View
class MyView(View):
def post(self, request):
# <view logic>
return HttpResponse('result')
You can read more about it there Django-Class-Based-Views-Intro
Related
I have a search bar where I want to search for perfumes in a MongoDB database. I tried two ways but it never works.
Here is the HTML template for both:
search_similar.html:
{% extends "todo/base.html" %}
{% block content %}
<div class="recommendations">
<!-- <div class="login-page"> -->
<div class="form">
<form action="{% url 'search_results' %}" method="get">
<input name="q" type="text" placeholder="Perfume name...">
<input type ="submit" value="Find Similar Perfumes" />
</form>
<form class="login-form" action = "/predict" method="POST">
<input type="text" placeholder="perfume name"/> <!-- https://www.youtube.com/watch?v=TRODv6UTXpM&ab_channel=ProgrammingKnowledge -->
<input type ="submit" value="Find Similar Perfumes" />
</form>
</div>
</div>
{% endblock %}
views.py:
import pymongo
import todo.config as config
from django.db.models import Q
username = config.username
password = config.password
...
class SearchResultsView(ListView):
model = Perfume
template_name = 'todo/search_similar_results.html'
def get_queryset(self): # new
query = self.request.GET.get('q')
perfume_list = list(collection.find({'q0.Results.0.Name': {"$regex" : query}}, {'item_name': 1, 'brand': 1, 'gender': 1,
'note': 1, 'tags': 1, 'theme': 1, '_id': 0}))
print("perfume_list: ", perfume_list)
return perfume_list
But perfume_list is hopelessly empty.
But even in MongoDB Atlas, I have problems to search in nested dictionaries. Indeed the query in the image below does not give the result that we can see:
Anexo: urls.py
urls.py:
from django.contrib import admin
from django.urls import path
from todo import views
urlpatterns = [
...
# similar
path('similar', views.search_similar, name='similar'),
path('similar_results', views.SearchResultsView.as_view(), name='search_results')
]
i've been wondering about how i could render a template just by passing a made-inside-view string so that i woudn't have the need to create an html file. I read the Django Docs, but i couldn't find an explanation on this, as far as seen all was about giving the template path string, (also i tried a few lines, but got nothing).
Please, have this as an example:
from django.shortcuts import render
def my_view(request):
arbitrary_string_as_template = """
<form action="" method="POST">
{% csrf_token %}
<label for="">Username</label>
<input type="text" name="username">
<label for="">Password</label>
<input type="password" name="password">
<button type="submit">
submit
</button>
</form>
"""
return render(request, arbitrary_string_as_template, {})
So if this can be done... then i think it would have in its way a good potential, since it gains in terms of versatility..and btw..
#I'm New to Django
Thanks for your attention
You can construct a Template object [Django-doc] with the template string, and then .render(…) [Django-doc] it:
from django.http import HttpResponse
from django.template import Template, RequestContext
def my_view(request):
arbitrary_string_as_template = """
<form action="" method="POST">
{% csrf_token %}
<label for="">Username</label>
<input type="text" name="username">
<label for="">Password</label>
<input type="password" name="password">
<button type="submit">
submit
</button>
</form>
"""
template = Template(arbitrary_string_as_template)
context = RequestContext(request)
return HttpResponse(template.render(context))
If however the content is static, I would advise to use a file. It makes it easier to separate concerns, and write clean files that each focus on a specific part.
So I am building an app that users are able to use a range slider to update a database with a new integer value. I have the slider which provides me with the integer value that I would like to return to the view, but I don't know how to return this value from the template.
https://docs.djangoproject.com/en/3.0/ref/forms/widgets/
I looked at the documentation but I couldn't find anything regarding range inputs.
# forms.py
from django import forms
class UpdateForm(forms.Form):
update = forms.IntegerField(widget=forms.HiddenInput(**something like:value='slider-input**}}))
# views.py
def home_view(request):
form = UpdateForm()
return render(request, 'main/index.html', {'form': form})
# index.html
...
<form id="update-form" method="post">
{% csrf_token %}
{{ form }}
<div id="slider">
<input class="slider-widget" min="0" max="25" step="1" value="0" type="range">
</div>
<div class="options">
<a href="{% url 'main-home' %}">
<img src="{% static 'main/media/cancel.png' %}" alt="cancel">
</a>
<button type="submit">
<img src="{% static 'main/media/confirm.png' %}" alt="confirm">
</button>
</div>
</form>
...
In it's simplest form you can take the slider value directly and do not need a HiddenField.
Your simple form
class UpdateForm(forms.Form):
update = forms.IntegerField()
In your html template just make sure that you add the 'name' attribute to your slider and give it the same name as the field name in your form:
<div id="slider">
<input name="update" class="slider-widget" min="0" max="25" step="1" value="0" type="range">
</div>
and in your view just process the form:
form = UpdateForm(request.GET or None)
if form.is_valid():
slider_value = form.cleaned_data['update']
# do somthing
Actually you do not really need a form for a simple case like this. You can also fetch the value directly in your view
slider_value = request.GET.get('update')
in my flask app I am using mongoDB and on the home page I have a form that is returning all the known collections in that particular database. I am asking the user to pick a collection they want to use as I will use that collection set to return all the documents in other routes or views.
Im struggling how to make this global "selected_collection" a global variable that all the routes and views can use.
for example on the index page I am able select a collection then on the submit it would redirect me to view db_selected there I was trying to make the selected_collection a global variable but if i got to the about view it get an error related to
I imagine I should use flask.g but im not sure how to get it to work. I have read some of the documents but they are a little vague to me.
AttributeError: '_AppCtxGlobals' object has no attribute 'selected_collection'
how can i make this work?
app.py file:
# INDEX
#app.route('/', methods=['GET', 'POST'])
def index():
coll_name = get_db_collection()
return render_template('index.html', coll_name=coll_name)
# LOGIN
#app.route('/db_selected', methods=['GET', 'POST'])
def db_selected():
if request.method == 'POST':
selected_collection = request.form['Item_4']
selected_collection = g.selected_collection
return render_template('db_selected.html',
selected_collection=selected_collection)
#app.route('/about')
def about():
app.logger.info('selected_collection is {}'.format(g.selected_collection))
return render_template('about.html')
index.html file:
{%extends 'layout.html'%}
{%block body%}
<div class="jumbotron text-center">
<h1>Welcome to the index.html file !</h1>
</div>
<div class="container">
{% include 'db_query_bar.html' %}
</div>
{%endblock%}
db_query_bar.html
<form class="form-horizontal" action="{{ url_for('db_selected') }}" name="Item_1" method="POST">
<fieldset>
<legend>Select DB</legend>
<div class="form-group">
<label for="select" class="col-lg-2 control-label">Database Collection:</label>
<select id="DB" class="form-control" name="Item_4" style="width: 70%" >
<!-- <option value="">All</option> -->
{% for item in coll_name %}
<option value="{{item}}">{{item}}</option>
{% endfor %}
</select>
<br>
</div>
<div class="form-group">
<div class="col-lg-10 col-lg-offset-2">
<button type="submit" class="btn btn-success">Submit</button>
</div>
</div>
</fieldset>
</form>
Just to answer this for the global variable I ended up placing
app.selected_collection = "Some Value"
in the top of my flask code this will create a global variable I can use in all the views.
app = Flask(__name__)
# CONFIG MONGO CONNECTION DETAILS
app.config['MONGO_HOST'] = 'DB-Host'
app.config['MONGO_DBNAME'] = 'DB-Collection'
app.selected_collection = "Some Value"
# INIT MONGODB
mongo = PyMongo(app)
I'm making my first Django site that has one app so far named clients and i keep my templates in project_name/clients/templates/clients.
Like the title says i'm able to update an instance of my model Client using UpdateView in my views file and I thought I would be able to delete an instance in the same way using DeleteView but I get the error stated previously. Any help would be appreciated. I've seen other similar posts but nothing that helped me solve this problem
Here's my url file:
from django.conf.urls import url
from . import views
app_name = 'clients'
url(r'^$', views.IndexView.as_view(), name='index'),
# /clients/11/... could be any number
url(r'^(?P<pk>[0-9]+)/$', views.DetailView.as_view(), name='detail'),
# /clients/viewed/
url(r'^viewed/', views.viewed, name='viewed'),
# /clients/add/
url(r'^add/$', views.ClientCreate.as_view(), name='client-add'),
# /clients/3/update/
url(r'^(?P<pk>[0-9]+)/update$', views.ClientUpdate.as_view(), name='client-update'),
# /clients/8/delete/
url(r'^(?P<pk>[0-9]+)/delete/$', views.ClientDelete.as_view(), name='client-delete'),
]
Here's the relevant classes in my views.py:
from __future__ import unicode_literals
from django.views import generic
from django.views.generic.edit import CreateView, UpdateView, DeleteView
from django.core.urlresolvers import reverse_lazy
from django.shortcuts import render
from .models import Client
class ClientUpdate(UpdateView):
model = Client
fields = ['name', 'age', 'height', 'weight',
'history_of_head_trauma', 'profession', 'is_athlete', 'email']
success_url = reverse_lazy('clients:index')
class ClientDelete(DeleteView):
model = Client
success_url = reverse_lazy('clients:index')
Here's the div in my index.html that holds both buttons for updating and deleting:
<div class="panel-footer">
<a type="button" class="btn btn-sm btn-success"><i class="glyphicon glyphicon-envelope"></i></a>
<span class="pull-right">
<i class="glyphicon glyphicon-edit"></i>
<i class="glyphicon glyphicon-remove"></i>
</span>
</div>
For some reason when using UpdateView, your button in html can be just a simple link with the href pointing to the correct url which in my case pointed to ClientUpdate in my views file ...
But for DeleteView the html has to be in a <form>. This was the only code i had to change to make this work. I basically put the form in place of the
<a href="{% url 'clients:client-delete' pk=client.id %}"....>
<div class="panel-footer">
<a type="button" class="btn btn-sm btn-success"><i class="glyphicon glyphicon-envelope"></i></a>
<span class="pull-right">
<i class="glyphicon glyphicon-edit"></i>
<form action="{% url 'clients:client-delete' pk=client.id %}" method="post" style="display: inline;">
{% csrf_token %}
<input type="hidden" name="client_id" value="{{ client.id }}"/>
<button type="submit" class="btn btn-danger btn-small">
<span class="glyphicon glyphicon-trash"></span>
</button>
</form>
</span>
By default, the DeleteView shows a confirmation page for get requests, and deletes the object for post requests. You need to create a template clients/client_confirm_delete.html (or set template_name on the view) to handle GET requests. There is an example template in the docs:
<form action="" method="post">{% csrf_token %}
<p>Are you sure you want to delete "{{ object }}"?</p>
<input type="submit" value="Confirm" />
</form>
Your other option is to add a form to your index page, so that users submit a post request to the delete page. Note that this means that the object will be deleted immediately without confirmation. Even if you do this, it might be a good idea to add a template for GET requests, otherwise you could get errors when users/bots navigate directly to your delete url.
u need to create a dedicated HTML page inside the CBV to execute the delete operation