update table using SQL INSERT not working in Flask App - flask

So I have searched through existing questions based on my challenge and I haven't found any solution. I need help with updating a database by inserting a new value into a column that was hitherto null during the creation of the table. The code below is a route for profile. The first thing it does is to check if it the user that signed in. If not the user, the user is redirected to a login page. However, if it is the user I want the user to select a value from a drop-down list and then add the value to the users' table where the country column is set initially to NULL. Currently, it is not adding the record to the database. On selection of the value, the value is not updated in the database. The country column I am trying to update remains null/empty
APP.PY
#app.route('/profile', methods=['GET', 'POST'])
def profile():
form = CountryForm(request.form) # A drop down list from where user select a value
first = request.form.get('country_select')
if not g.user:
return redirect(url_for('login'))
else:
if request.method == 'POST' and form.validate():
try:
with sqlite3.connect("tour.db") as con:
cur = con.cursor()
print("Opened database successfully")
cur.execute("INSERT INTO users (country) VALUE (?)",(first) )
con.commit()
flash("Record successfully added")
except:
con.rollback()
flash("error in insert operation")
finally:
return render_template("profile.html", msg = first)
con.close()
return render_template('profile.html', user=get_curr_user(), form=form, country=first)
profile.html
{% extends "base.html" %}
{% block head %}
<title>Profile Page</title>
{% endblock %}
{% block body %}
<h1 class="title">
Welcome, {{g.user.username}}
</h1>
<form method="POST" action="{{ url_for('profile') }}">
<select name="country_select">
{% for x in form.country %}
<option>{{ x }}</option>
{% endfor %}
</select>
<input type="submit" value="submit">
</form>
<p>{{country}}</p>
<div class="auth-wrapper">
Log out
</div>
{% endblock %}
base.html
<html>
<body onload="brython(1)">
{% with messages = get_flashed_messages() %}
{% if messages %}
{% for message in messages %}
<p>{{ message }}</p>
{% endfor %}
{% endif %}
{% endwith %}
{% block body %} {% endblock %}
<script type=”text/python” src=”script/program.py”></script>
</body>
</html>
Looking forward to your contributions. Thanks.

Related

Hx-push-url doesn’t work on back button click

I am trying to integrate Htmx with django and achieve single page application behaviour. I am rewritting Djangoproject.com poll app with htmx. When I click on detail page link, content loads, htmx push a new url in address bar. When I press back button, it took me to index page perfectly for the first time, after that if I again go to detail page and click back button, url shows of the index, button index content doesn’t load, content remains same as detail page.
Here is my code
views.py
def index(request):
latest_question_list = Question.objects.filter(pub_date__lte=timezone.now()).order_by('-pub_date')[:5]
context = {'latest_question_list': latest_question_list}
if request.headers.get("Hx-Request") is not None:
return render(request, 'main/index/index.html', context)
else:
return render(request, 'main/index/index-full.html', context)
def detail(request, question_id):
question = get_object_or_404(Question, pk=question_id)
print(request.headers.get("Hx-Request"))
if request.headers.get("Hx-Request") is not None:
return render(request, 'main/detail/detail.html', {'question': question})
else:
return render(request, 'main/detail/detail-full.html', {'question': question})
index.html
<div id="index" class="">
{% if latest_question_list %}
<ul>
{% for question in latest_question_list %}
<li><div class="has-text-link" hx-get="{% url 'main:detail' question.id %}" hx-push-url="true" hx-target="#index" hx-swap="outerHTML">{{ question.question_text }}</div></li>
{% endfor %}
</ul>
{% else %}
<p>
No polls are available.
</p>
{% endif %}
</div>
index-full.html
{% extends 'base.html' %}
{% block content %}
{% include 'main/index/index.html' %}
{% endblock content %}
detail.html
<div id="detail" class="">
<form action="{% url 'main:vote' question.id %}" method="post">
{% csrf_token %}
<fieldset>
<legend><h1>{{ question.question_text }}</h1></legend>
{% if error_message %}<p>
<strong>{{ error_message }}</strong>
</p>
{% endif %}
{% 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 %}
</fieldset>
<input type="submit" value="Vote">
</form>
</div>
detail-full.html
{% extends 'base.html' %}
{% block content %}
{% include 'main/detail/detail.html %}
{% endblock content %}
I found no error in browser console, no error in terminal
Now, I know I can put a back button in detail page that can took me to index page. But user won't use that, they will just use the back button on their device.
Adding this javascript code you can reload the page when the user click the back button:
var auxBack = performance.getEntriesByType("navigation");
if (auxBack[0].type === "back_forward") {
location.reload(true);
}

How to fix pagination after making a search for specific data in django_tables2

In my project I am using with success django_tables2 in order to achieve server side processing.
The only thing that I do not know how to handle is that after searching, for example by name in a template rendering clients for my application, the search despite the fact that gives some returned results based on the name, it is not working properly if the result records are spread in more than one page based on my pagination.
In other words, when I am clicking the 2 (second page of my returned results), the app is showing all the pages concerning the clients 1 2 3 ...45 next (as i want to reach the /clients/ url, and not the 1 2 next structure for only the custom search data.
This happening also when I am clicking the next and previous buttons.
One easy solution It could be to increase my pagination limit in order to show all the possible results in one page, but this solution is not proper for big result sets.
Is there any solution to avoid loading and showing all the pages in the search bar and only keeping the results of my custom search?
Below is my snippets.
url.py
url(r'^clients/$', views.client_list, name='client_list'),
models.py
class Client(models.Model):
name = models.CharField(max_length=50, verbose_name="Name")
surname = models.CharField(max_length=50, verbose_name="Surname")
activity = models.IntegerField(choices=ACTIVITY_OPTIONS, null=True,default=ACTIVE)
views.py
def client_list(request, template_name='clients/client_list.html'):
if request.method == 'POST':
search_string = request.POST['search_client']
current_client=Client.objects.filter(Q(activity=1) & Q(name=search_string)| Q(surname=search_string))
single_table=ClientTable(current_client)
RequestConfig(request).configure(single_table)
return render(request,template_name, {'single_table': single_table})
else:
clients=Client.objects.filter(activity=1)
table = ClientTable(clients)
RequestConfig(request).configure(table)
return render(request,template_name, {'table': table})
tables.py
class ClientTable(tables.Table):
class Meta:
#define the model
model = Client
exclude=('..')
template_name = 'django_tables2/bootstrap.html'
sequence = ("surname", "name",)
template
{% extends 'base.html' %}
{% load has_group %}
{% load render_table from django_tables2 %}
{% load bootstrap3 %}
{% load static %}
{% load staticfiles %}
{% block content %}
<div class="container">
<div class="row">
<div class="col-md-12">
<form class="well" method="post" action="">
{% csrf_token %}
Client Search:<br>
<input type="text" class="form-control" id="search" name="search_client">
<br>
{% buttons %}
<button type="submit" class="btn btn-primary">
{% bootstrap_icon "like" %} Submit
</button>
{% endbuttons %}
</form>
{% if single_table %}
{% render_table single_table %}
{% endif %}
{% if table %}
{% render_table table %}
{% endif %}
</div>
</div>
</div>
{% endblock %}
Finally after searching I found a solution.
Django filters https://django-filter.readthedocs.io/en/master/index.html can be used in situations like this one.
The steps I followed are:
1) import the 'django_filters', to settings.py
2) Define the filters.py
import django_filters
from .models import Patient
class ClientFilter(django_filters.FilterSet):
name = django_filters.CharFilter(lookup_expr='icontains')
class Meta:
model = Client
fields = ['id','name','surname']
3) Modify the views.py
class FilteredClientListView(SingleTableMixin, FilterView):
table_class = ClientTable
model = Client
template_name ='clients/client_list2.html'
filterset_class = ClientFilter
4) Modify urls.py accordingly since I used class based function
url(r'^clients2/$', views.FilteredClientListView.as_view(), name='client_list2'),
5) Modify my template
{% extends 'base.html' %}
{% load has_group %}
{% load render_table from django_tables2 %}
{% load bootstrap3 %}
{% load static %}
{% load staticfiles %}
{% block content %}
<div class="container">
<div class="row">
<div class="col-md-12">
<form class="well" method="post" action="">
{% csrf_token %}
Client Search:<br>
<input type="text" class="form-control" id="search" name="search_client">
<br>
{% buttons %}
<button type="submit" class="btn btn-primary">
{% bootstrap_icon "like" %} Submit
</button>
{% endbuttons %}
</form>
{% if filter %}
<form action="" method="get" class="form form-inline">
{% bootstrap_form filter.form layout='inline' %}
{% bootstrap_button 'filter' %}
</form>
{% endif %}
{% if single_table %}
{% render_table single_table %}
{% endif %}
{% if table %}
{% render_table table %}
{% endif %}
</div>
</div>
</div>
{% endblock %}
P.S : importing in the views.py the appropriate tables and filters

Deleting object from a view in Django

I have a page that shows a list of objects and I want to add a button beside each one to enable the user to delete it. I've found a few questions about similar scenarios online but for some reason I keep getting errors when I try to replicate the solutions.
Here is the delete function in views.py:
def delete_dish(request, pk):
query = Dish.objects.get_object_or_404(pk)
supermenu = query['supermenu'].pk
query.delete()
return redirect('foodmenu:menu', supermenu)
Here is the form in the HTML template:
{% if not supermenu.dish_set.count == 0 %}
<ul>
{% for dish in supermenu.dish_set.all %}
<li>
{{ dish.name }} - {{ dish.description }}
<form action="{% url 'foodmenu:delete_dish' dish.id %}" method="POST">
{% csrf_token %}
<button type="submit">X</button>
</form>
</li>
{% if not dish.price_set.count == 0 %}
<ul>
{% for price in dish.price_set.all %}
{% if price.label %}
<li>{{ price.label }}: {{ price.cost }}</li>
{% else %}
<li>{{ price.cost }}</li>
{% endif %}
{% endfor %}
</ul>
{% endif %}
{% endfor %}
</ul>
{% else %}
<p>No dishes on this menu!</p>
{% endif %}
And here is the urls.py:
app_name = 'foodmenu'
urlpatterns = [
...
path('dish/delete/<int:dish.id>', views.delete_dish, name="delete_dish")
]
When I click the button, the browser goes to ./dish/delete/1 (1 being the pk of the object), but Django returns a 404 error.
Instead of query = Dish.objects.get_object_or_404(pk) you should use get_object_or_404 shortcut:
from django.shortcuts import get_object_or_404
from django.views.decorators.http import require_POST
#require_POST
def delete_dish(request, pk):
if request.method
query = get_object_or_404(Dish, pk=pk)
supermenu = query.supermenu.pk
query.delete()
return redirect('foodmenu:menu', supermenu)
Also change your url pattern to this:
path('dish/delete/<int:pk>/', views.delete_dish, name="delete_dish")
UPD
As #daniherrera mentioned in his comment, you probably want to check request's method, to prevent accidental deletions. For this you can use require_POST decorator.

Django inclusion_tag contents not displaying

I cannot get the contents of an inclusion_tag to display. I am not getting an errors so i know that the tag is registering and I am almost certain that it is loading correctly. The tag is created in crudapp/templatetags/crudapp_tags.py
from django import template
register = template.Library()
#register.inclusion_tag("forum.html")
def results(poll):
form = 'blah'
return {'form': form}
templates/forum.html
{% extends 'index.html' %}
{% load crudapp_tags %}
{% results poll %}
<p>aaa</p>
{% block homepage %}
<p>bbb</p> <!-- Only this displays -->
{% if form %}
<p>Form exists</p>
{% endif %}
{% for item in form %}
<p>This is {{ item }}</p>
{% endfor %}
<div>
<p>{% if user.is_authenticated %}Add a New Topic: <span class="glyphicon glyphicon-plus"></span>{% endif %}</p>
</div>
<div>
<p>{{ totalposts.count }} posts, {{ totaltopics.count }} topics, {{ totalusers.count }} users, {{ totalviews.numviews}} views</p>
</div>
{% endblock %}
The file set up is as follows,
If you are using an inclusion tag, then the tag renders another template. You need to move the code that uses form out of forum.html and into a new template, e.g. results.html
results.html
{% if form %}
<p>Form exists</p>
{% endif %}
{% for item in form %}
<p>This is {{ item }}</p>
{% endfor %}
Then change your tag to use this template
#register.inclusion_tag("results.html")
def results(poll):
form = 'blah'
return {'form': form}
Finally, since you are extending a template, you need to move then tag into a block, otherwise the result won't be used.
{% block homepage %}
{% results poll %}
...
{% endblock %}
If you want to add an item to the template context instead of rendering another template, then you want a simple tag instead.
#register.simple_tag
def fetch_result():
result = ['foo', 'bar']
return result
Then in your template:
{% fetch_result as result %}
{% for item in result %}
<p>This is {{ item }}</p>
{% endfor %}
The {% fetch_result as result %} works for simple tags in Django 1.9+. In earlier versions, you want an assignment tag.

django: how to access only first error message in form.errors?

I have a model called Users and I have a form for that model called UsersForm. In my views.py, I created a version of UsersForm, like so
form = UsersForm()
if reqest.method == POST:
form = UsersForm(request.POST)
if form.is_valid():
form.save()
c = {}
c.update(csrf(request))
c.update({'form':form})
return render_to_response('home_page.html', c)
Now, my home_page.html is this:
<html>
<body>
<form method="post" action="">{% csrf_token %}
{{ form }}
<input type="submit" value="Register"/>
</form>
{% if form.errors %}
{% for field in form %}
<p> {{field.errors}} </p>
{% endfor %}
{% endif %}
</body>
</html>
So, what I want is, I want to display only the first error in {{ field.errors}}.
What I was thinking was something like:
{% if form.errors %}
{% for field in form %}
<p> {{field.errors}} </p> {{ break}}
{% endfor %}
{% endif %}
but there is no break in the django template language, right? I also tried thinking about using {% for field in form|slice:":1" %} but that wouldn't work either. Anyone know how to do this?
You can index lists in a django template by using the dot notation:
{{ field.errors.0 }}
Be sure to check that there is at least 1 error before doing that though, or you will get an Index out of range error.
Take the template tag route.
Here's a sample template tag:
from django.template.defaulttags import register
#register.filter(name='show_error')
def show_error(dictionary):
try:
return dictionary.values()[0][0]
except (TypeError,IndexError,AttributeError):
return 'tip: try again'
And use it in your template like so:
{% if form.errors %}{{ form.errors|show_error }}</span>{% endif %}