Hey I'm trying to combine two dictionaries filled with JSON data without duplicates. I'm using Flask and Jinja2 to build an api to fetch json data from an api and post it on a web page, I want to be able to filter based off of tags and then combine the results every time I make a request. Currently I'm able to filter based off of tags chosen by submitting buttons on Jinja but I'm having trouble getting it to combine when I select a new tag, when a new tag is selected it filters only using that tag and doesn't combine the dictionary from the previous result.
main.py:
#app.route('/api', methods=['GET', 'POST'])
def add_tag():
name = request.form['tags']
form = APInameForm()
url= 'https://api.hatchways.io/assessment/blog/posts?tag='+name
try:
api = requests.get(url).json()
api = api['posts']
ilist = []
nlist = []
for i in api:
ilist.append(i)
if not ilist:
output = '{<br>'
output = output + '"error": "Tags parameter is required" <br>'
output = output + '}'
return output
return render_template('/index.html', test=ilist)
except requests.ConnectionError:
return "Connection Error"
#app.route('/')
def index():
return render_template("index.html")
index.html:
{% extends 'base.html' %}
{% block content %}
<form class="text-center pt-3" method="POST" action="/api">
<input type="text" class="form-control" placeholder="Search" name="tags">
<input type="submit" value="Search" />
</form>
<br/><br/><br/>
<h1>Recommended Tags:</h1>
<form class="form-inline" method="POST" action="/api">
<div class="control">
<input type="submit" class="btn btn-primary mb-2" name="tags" value="tech">
</input>
</div>
<div class="control">
<input type="submit" class="btn btn-primary mb-2" name="tags" value="history">
</input>
</div>
<div class="control">
<input type="submit" class="btn btn-primary mb-2" name="tags" value="startups">
</input>
</div>
<div class="control">
<input type="submit" class="btn btn-primary mb-2" name="tags" value="health">
</input>
</div>
<div class="control">
<input type="submit" class="btn btn-primary mb-2" name="tags" value="science">
</input>
</div>
<div class="control">
<input type="submit" class="btn btn-primary mb-2" name="tags" value="design">
</input>
</div>
<div class="control">
<input type="submit" class="btn btn-primary mb-2" name="tags" value="culture">
</input>
</div>
<div class="control">
<input type="submit" class="btn btn-primary mb-2" name="tags" value="history">
</input>
</div>
</form>
<br/><br/><br/>
<code>
{<br>
"posts": [{<br>
{% for item in test %}
"id": {{ item.id }}<br>
"author": {{ item.author }}<br>
"autherId": {{ item.authorId }}<br>
"likes": {{ item.likes }}<br>
"popularity" :{{ item.popularity }}<br>
"reads": {{ item.reads }}<br>
"tags": {{ item.tags }}<br><br>
{% endfor %}
}
]
</code>
{% endblock %}
I am not sure I really understand your question.
But could it be that a simple use of a set will solve your problem?
Sets can't have duplicates
https://www.w3schools.com/python/python_sets.asp
You need to store the previous data somewhere outside these functions to be able to use it in later calls to them. Temporarily, that could be in a variable defined at the top level in your module (.py file).
If you need it to persist longer (across worker threads, sessions or restarts of your custom server), you might need to write to a file or database.
To merge the JSON dictionaries you can use the dict.update method (see official docs).
Given two dict instances d1, d2, calling d1.update(d2) will merge d2 into d1, overwriting values for any keys that are the same.
combined_data = {}
#app.route('/api', methods=['GET', 'POST'])
def add_tag():
response = requests.get(url)
data = response.json()
combined_data.update(data)
# ..now render combined_data
Related
I have a comment section and I want to allow users to delete their comments, however when I click the delete button the comment doesn't get delete, and over that a new comment with nothing get add.
Here is my python code. When I tried to print "delete" I got none in my terminal window
#app.route("/deletecomment", methods=["GET", "POST"])
#login_required
def deletecomment():
delete = request.args.get("delete")
print(delete)
#if the method is get
if request.method == "GET":
#testing purpose
print("vvv")
print(delete)
#delete the comment
comments = db.execute("DELETE FROM comment WHERE comment=?",delete)
return redirect (url_for("addcomment"))
Here is my html. Is it bad to have a form inside another form?
<form action="/comment" method="get">
<div class="row bootstrap snippets bootdeys">
<div class="col-md-8 col-sm-12">
<div class="comment-wrapper">
<div class="panel panel-info">
<div class="panel-heading">
Comment panel
</div>
<div class="panel-body">
<textarea name="comment" class="form-control" placeholder="write a comment..." rows="3"></textarea>
<br>
<button type="submit" class="btn btn-info pull-right">Post</button>
<div class="clearfix"></div>
<hr>
{% for comments in comments %}
<ul class="media-list">
<!--<button type="submit" class="btn btn-danger">Delete</button>-->
<li class="media">
<a href="#" class="pull-left">
<img src="https://bootdey.com/img/Content/user_1.jpg" alt="" class="img-circle">
</a>
<div class="media-body">
<!--<button type="submit" class="btn btn-danger">Delete</button>-->
<span class="text-muted pull-right">
</span>
<!--<button type="submit" class="btn btn-danger">Delete</button>-->
<strong class="text-success">{{comments.user}}</strong>
<form action="/deletecomment" method="get">
<p name="delete">
{{comments.comment}}
</p>
<button id="but" type="submit" class="btn btn-danger">Delete</button>
</form>
</div>
</li>
</div>
</ul>
{% endfor %}
</div>
</div>
</div>
</div>
</div>
</form>
Put the comment ID as a URL parameter in the action URL
<form action="/deletecomment?delete={{comment.id}}" method="get">
and change the controller to use the parameter as the ID in the query.
#app.route("/deletecomment", methods=["GET", "POST"])
#login_required
def deletecomment():
#if the method is get
if request.method == "GET":
delete = request.args.get("delete")
print(delete)
#testing purpose
print("vvv")
print(delete)
#delete the comment
comments = db.execute("DELETE FROM comment WHERE id=?",delete)
return redirect (url_for("addcomment"))
I have this HTML page in which I have 2 forms. Django is not checking the form validation for the first form. I want it to check form validation for the first form.
This is the Html Code
<form method="post" id="msform">
{% csrf_token %}
<!-- progressbar -->
<ul id="progressbar">
<li class="active" id="conf"><strong>Configuration</strong></li>
<li id="auth"><strong>Authentication</strong></li>
</ul>
<div class="progress">
<div class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar" aria-valuemin="0" aria-valuemax="100"></div>
</div> <br> <!-- fieldsets -->
<fieldset>
<div class="form-card">
<div class="row">
<div class="col-7">
<h2 class="fs-title">Cluster Configuration</h2>
</div>
<div class="col-5">
<h2 class="steps">Step 1 - 2</h2>
</div>
</div>
{{ form1|crispy }}
</div> <input type="button" name="next" class="next action-button" value="Next" />
</fieldset>
<fieldset>
<div class="form-card">
<div class="row">
<div class="col-7">
<h2 class="fs-title">Authentication</h2>
</div>
<div class="col-5">
<h2 class="steps">Step 2 - 2</h2>
</div>
</div>
{{ form2|crispy }}
</div><button type="submit" class="btn btn-primary" >Next</button>
</fieldset>
</form>
If I use submit button instead of next for the first form then neither the second form opens nor the form is submitted (i.e. nothing is happening).
So I think the issue might be because you have over arching form tag, and two forms sent inside it from your view function:
What you have right now is this:
<form>
<fieldset>
<! –– Your Code ––>
{{ form1|crispy }}
</div> <input type="button" name="next" class="next action-button" value="Next" />
</fieldset>
<fieldset>
<! –– Your Code ––>
{{ form2|crispy }}
</div><button type="submit" class="btn btn-primary" >Next</button>
</fieldset>
</form>
As you can see from the above simplification of your original post, you have two forms templated inside one form tag. Thus when you hit either of the the submit button both of them gets sent.
If I am not mistaken, I believe what you might want is something along the lines of this:
<form name="form1" id="form1">
<fieldset>
<! –– Your Code ––>
{{ form1|crispy }}
</div> <input type="button" name="form1" class="next action-button" value="Next1" />
</fieldset>
</form>
<form name="form2" id="form2">
<fieldset>
<! –– Your Code ––>
{{ form1|crispy }}
</div> <input type="button" name="form2" class="next action-button" value="Next2" />
</fieldset>
</form>
Take note of the fact that I have changed your button names, as well as added ids and names to each form, you might also want to add ids as well as unique values to your buttons as well. This would help you build if conditions to determine which form has been submitted and so on, in your view function
Here is a link that describe how to handle this in more depth.
Which is all nice and dandy, but the conclusion of that linked page is this:
Let me know if it helps, feel free to ask more if you do not understand/the changes does not work
I want to use input field for authentication but if I search for authentication tutorial they are using built-in Django forms which I can't design it using html
You can customize how forms are rendered or you can pretty much write any HTML that you want just make sure your input name attributes match whatever you are accepting on backend.
Here's an example using Bootstrap 4 for styling. Start out by creating a view that subclasses LoginView. In the html file, instead of using {{ form }} or {{ form.username }} & {{ form.password }}, you can supply your own html for the fields. Just make sure your inputs are named the same as in {{ form }}.
views.py:
from django.contrib.auth.views import LoginView
class MyLoginView(LoginView):
template_name = 'login.html'
login.html:
{% block content %}
...
<div id="login-row" class="row justify-content-center align-items-center">
<div id="login-column" class="col-md-6">
<div id="login-box" class="col-md-12">
<form id="login-form" class="form" action="" method="post">
{% csrf_token %}
<div class="form-group">
<label for="username" class="text-white">Username:</label><br>
<input type="text" name="username" id="username" class="form-control" required>
</div>
<div class="form-group">
<label for="password" class="text-white">Password:</label><br>
<input type="password" name="password" id="password" class="form-control" required>
</div>
<div class="form-group">
<input type="submit" name="login" class="btn btn-light btn-md btn-block mt-5"
value="log in">
</div>
</form>
</div>
</div>
</div>
...
{% endblock content %}
I am trying to use a check box control in a simple django application. Code Logic seems to be fine, But I am getting an empty fruit list ([None, None]). I don't know why it's not working, Can anybody point out the mistake. Thanks in advance
index.html
<div class="form-check">
<input class="form-check-input" type="checkbox" value="Apple" id="apple">
<label class="form-check-label" for="apple">Apple</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" value="Mango" id="mango">
<label class="form-check-label" for="mango">Mango</label>
</div>
view.py
if request.method == 'POST':
fruit = []
fruit.append(request.POST.get('apple'))
fruit.append(request.POST.get('mango'))
As Daniel mentioned, you have to add a name attribute to form elements, so they are submitted to the server.
index.html
<form method="post">
{% csrf_token %}
<div class="form-check">
<input class="form-check-input" type="checkbox" value="Apple" id="apple" name="fruits">
<label class="form-check-label" for="apple">Apple</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" value="Mango" id="mango" name="fruits">
<label class="form-check-label" for="mango">Mango</label>
</div>
<button type="submit">Submit</button>
</form>
That way, you can get a list of fruits in your view:
views.py
if request.method == 'POST':
fruits = request.POST.getlist('fruits')
The fruits variable would be a list of check inputs. E.g.:
['Apple', 'Mango']
input elements need a name attribute, otherwise the browser does not send any data.
In my Django template, {{ form.ietf_tag|bootstrap }} renders as
Django rendering
<div class="form-group">
<label class="control-label " for="id_ietf_tag">IETF tag</label>
<div class=" ">
<input class=" form-control" id="id_ietf_tag" maxlength="12" name="ietf_tag" type="text">
</div>
</div>
I want to insert a <button> before <input>, so I figured I'll just copy, paste, and modify the rendered HTML to where it looks something like this:
Manual rendering
<div class="row">
<div class="col-md-6">
<form action="" method="post">
{% csrf_token %}
<!-- Manually render ietf_tag input -->
<div class="form-group flex {% if form.ietf_tag.errors %}has-error{% endif %}">
<label for="{{ form.ietf_tag.id_for_label }}" class="control-label">{{ form.ietf_tag.label }}</label>
<div class=" ">
<button class="btn btn-primary get-code" data-url="{% url 'ajax_temporary_code' %}">Get Code</button>
<input id="{{ form.ietf_tag.id_for_label }}" class="form-control temp-code required" maxlength="12" name="{{ form.ietf_tag.html_name }}1" type="text" disabled value="{{ form.ietf_tag.value|default:"-" }}">
</div>
<span class="help-block">{{ form.ietf_tag.errors.0 }}</span>
</div>
<!-- -->
{{ form.common_name|bootstrap }}
{{ form.native_name|bootstrap }}
{{ form.direction|bootstrap }}
{{ form.comment|bootstrap }}
<button type="submit" class="btn btn-primary pull-right">Create</button>
</form>
</div>
</div>
The problem
On <form> submission, everything else is submitted except the ietf_tag, which I manually rendered.
QueryDict: {u'common_name': [u''], u'comment': [u''], u'csrfmiddlewaretoken': [u'G6UP5DxrSHHPPQzj6SbxM06Hh8yT9ksm'], u'direction': [u'l'], u'native_name': [u'']}
I double check the name attribute and it was correct. There was no problem using Django-rendered input.
Why is this happening?
Maybe I can accomplish the same result without having to copy, paste, and modify the HTML directly in the template?
EDIT: Put more context in the HTML code
Silly me. The disabled attribute in <input> is what causes the problem. I removed it and now the value is included in the form submission.
Lesson learned
If your <input> is disabled, the value won't be submitted by the form.