flask database global variable - flask

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)

Related

Django flash database object

I want to make an app where someone can search for something. When he searches he will get all of the things in the database that start with anything he wrote. I am using the messages framework.Here is the backend code:
def home(request):
if request.method == 'POST':
name = request.POST['name']
search = Team.objects.filter(name__startswith=name).all()
if not search:
messages.info(request, 'There wasnt')
else:
#looping all the items that search has
for i in search:
#flash the object
messages.info(request,i)
return render(request,'home.html')
And the HTML code:
{%if messages%}
{%for msg in messages%}
<div class='searching'>
#showing the name and the title of the object
<p style='color:white;margin-left:25px;'>{{msg.name}} {{msg.title}}</p>
</div>
{%endfor%}
{%endif%}
<form action='' method='post'>
{% csrf_token %}
<input class="form-control" type='text' name='name'>
<br>
<button class='btn btn-primary btn-lg'>OK</button>
</form>
But when I run it I don't get anything. Also I don't use extra_tags because I want the name and the title appear in the same div.
What should I do?
Pls can someone reply? I really need a help. Plsss.
Thanks.

How Do You Trigger HTMX Page Refresh After User Updates Any Part of The Page?

I have been working with HTMX and it's pretty cool compared to the dreaded formsets and Javascript. I have it working....My only issue is when the user updates the form anywhere...you have to manually refresh the page to reset the list of todos. My issue is identical to this one...https://stackoverflow.com/questions/66664407/dynamically-update-table-when-creating-new-enty-using-htmx but there is no resolution listed.....
Here's a quick overview of my code...
My view...
def create_to_do(request):
user = User.objects.get(id=request.user.id)
to_dos = NewToDo.objects.filter(created_by=user)
form = ToDoForm(request.POST or None)
if request.method == "POST":
if form.is_valid():
to_do = form.save(commit=False)
to_do.created_by = user
to_do.creation_date = timezone.now()
to_do.save()
return redirect("MyToDoList:detail-to-do", pk=to_do.id)
else:
return render(request, "partials/to_do_form.html", {
"form":form
})
context = {
"form": form,
"user": user,
"to_dos": to_dos,
}
return render(request, "create_to_do.html", context)
Partial detailview....
<button class="button35" hx-get="{% url 'MyToDoList:update-to-do' to_do.id %}" hx-swap="outerHTML">
Update
</button>
<button class="button34" hx-post="{% url 'MyToDoList:delete-to-do' to_do.id %}" hx-swap="outerHTML">
Delete
</button>
</div>
Partial todo form....
<div hx-target="this" hx-swap="outerHTML" class="">
<form method="POST">
{% csrf_token %}
{% if to_do %}
<button class="button35" hx-post="{% url 'MyToDoList:update-to-do' to_do.id %}">
Save
</button>
<button class="button34" hx-get="{% url 'MyToDoList:detail-to-do' to_do.id %}">
Cancel
</button>
</div>
{% else %}
<button class="button35" hx-post=".">
Save
</button>
</div>
{% endif %}
</form>
</div>
My main create form html..
<button class="button36" hx-get="{% url 'MyToDoList:create-to-do-form' %}" hx-swap="beforeend" hx-target="#bookforms">Add Form</button>
<div id="bookforms" class=""></div>
<div class="">
{% if to_dos %}
{% for to_do in to_dos %}
{% include "partials/to_do_detail.html" %}
{% endfor %}
{% endif %}
After a day of playing and pulling my hair out..it's all working as I want...I just need to figure out how to incorporate a dynamic page load if anything changes so that the entire page gets reloaded....so that the records get sorted according to my number field...
Thanks in advance for any thoughts or suggestions.
So thanks to a kind soul on Facebook....I added this Javascript to my code and it works.
$(document).on("click", ".yourclass", function(){
location.reload();
});
In case you need this, I had the problem when I have to update two/mutliple parts of the page after post.
I manage to solve it by trigger_client_event
Thanks to this issue: How do I manually trigger a hx-get event of an element from JavaScript
HTMX rocks!

Button in the base template to switch between locations

I have a base.html template which lets me choose between shops- I want to use this setting to save a product in relationship to it's location.
I already implemented a middleware that gives me a list of all shops for a logged in user and the current shop (is this a smart way?):
from .models import Shop
class ActiveShopMiddleware(object):
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
shops = Shop.objects.filter(user=request.user.id)
request.current_shop = shops[0]
request.shops = shops
response = self.get_response(request)
return response
I create products using a form, and I want to add the current shop information to that. I do this by handing initial data to the form:
def get_initial(self):
return {"shop": self.request.current_shop.id
I want to be able to switch between shops like in the screenshot:
I tried this in base template:
{% if user.is_authenticated %}
{% if request.num_shops > 1 %}
<div class="dropdown" aria-labelledby="userMenu">
<button class="btn btn-primary dropdown-toggle mr-2" type="button" id="dropdownMenu0" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">shop: {{ request.current_shop }}</button>
<form method="post" action="">
{% csrf_token %}
<div class="dropdown-menu" aria-labelledby="dropdownMenu1">
{% for shop in request.shops %}
<input type="hidden" name="tessst" value="{{ shop.id }}">
<a class="dropdown-item" href="/">{{ shop }}</a>
{% endfor %}
</form>
</div>
</div>
{% endif %}
I want to get the shop_id variable in my index view:
def index(request):
shop_id = request.POST["tessst"]
Is this an ok approach? I wanted to avoid having an additional parameter in my urls.
i think it's better that you generate this shops datas in form . i mean you send this data to front from django fom class.
e.g:
. you can create custom form field and then every form generate this shop field for user. and then in your view you can handle this data .
. also you can create custom model field but it depends on your project .

Django CustomMiddleware causing csrf_token issues during log in

I have been trying to implement this logic:
Whenever a user signs up, confirms his email, his account is active. However, in order to let the user gain full access to the website, he must enter some data first about his own self. I call it complete-profile.
I figured making a middleware is a good way to implement the logic. So I wrote the following:
class CompleteProfileMiddleware:
def __init__(self, get_response):
self.get_response = get_response
# One-time configuration and initialization.
def __call__(self, request):
# Code to be executed for each request before
# the view (and later middleware) are called.
response = self.get_response(request)
if request.path == "/account/" + request.user.username + '/complete-registration/':
pass
elif request.user.is_anonymous:
pass
elif request.user.is_superuser:
pass
elif request.user.student.complete_profile:
pass
elif not request.user.student.complete_profile:
return redirect('/account/' + request.user.username + '/complete-registration/')
# Code to be executed for each request/response after
# the view is called.
return response
However, now, for accessing the complete profile page, people need to log in first. And during the log in process, it gives issues with the csrf token as: Forbidden. CSRF verification failed. Request aborted.
If I remove the middleware everything starts working again, so the issue has to be here.
Here's the login template:
<div class="main">
<section class="signup">
<div class="container">
<div class="row">
<div class="signup-content col-sm-12">
<form id="signup-form" class="signup-form" method="post" action="{% url 'login' %}">
{% csrf_token %}
<h2 class="form-title">Log In</h2>
{{ form | crispy}}
<input type="submit" style="margin-top: 10px" value="Login" class="button" id="" />
<input type="hidden" name="next" value="{{ next }}" />
</form>
<div class="col-sm-12" style="text-align: right; margin-top: 5px">
Forgot Password?
</div>
<p class="loginhere">
New Here ? Create an account here
</p>
</div>
</div>
</div>
</section>
</div>
Without middleware everything works fine ?
You should send csrftoken during POST request, it's possible using django template language. You can use {% csrf_token %} template tag.

In django, how to use another model data from function based views

So I have a form that updates a key_instance object with a borrower. Currently my app needs the user to enter the name of the borrower, but I want it to display a dropdown list of data from another model the user model to select from, is there anyway to do this in a class based view? Here are my views.py and my template. What I was thinking is that I would like to use a get_list_or_404 on the user model and display it as a drop down list in the template and use that selection to populate the form field.
I manged to get the dropdown list to display in my template but I'm not sure as to how to save that value in my views.
Does anyone know if this is the right way or if this is doable? Thank you!!
views.py
def submit_key_request(request, pk):
"""
View function for renewing a specific keyInstance by admin
"""
key_inst=get_object_or_404(KeyInstance, pk=pk)
names = get_list_or_404(Users)
# If this is a POST request then process the Form data
if request.method == 'POST':
# Create a form instance and populate it with data from the request (binding):
form = UpdateKeyForm(request.POST)
# Check if the form is valid:
if form.is_valid():
# process the data in form.cleaned_data as required (here we just write it to the model due_back field)
key_inst.is_requested = True
key_inst.status = 'r'
key_inst.date_requested = datetime.date.today()
key_inst.borrower = form.cleaned_data['borrower']
key_inst.save()
# redirect to a new URL:
return HttpResponseRedirect(reverse('all-available-keys') )
# If this is a GET (or any other method) create the default form.
else:
form = UpdateKeyForm(initial={'borrower': 'N/A'})
return render(request, 'catalog/keyinstance_request_update.html', {'form': form, 'keyinst':key_inst})
template
{% extends "base_generic.html" %}
{% block content %}
<div class="wrapper">
<div class="centered"> <h1>Request Keys For Room: {{keyinst.roomkey}}</h1></div>
<div class="square-box">
<div class="square-content">
<form action="" method="post" >
{% csrf_token %}
<table style="display: inline-flex">
{{ form}}
</table>
<select name = 'name'>
{% for name in names %}
<option value="{{ name }}">{{ name }}</option>
{% endfor %}
</select>
<p>
(Please use their login name i.e. <b>{{ user.get_username }}</b>)
</p>
<p><input required id="checkBox" type="checkbox" onclick="validate()"> I accept the terms and conditions</p>
<p id="text" style="display:none">You Have Agreed To the Terms and Conditions</p>
<input type="submit" value="Submit" />
</form>
</div>
</div>
</div>
{% endblock %}
Here is how I manged to do it, Not sure if this is the best 'pythonic' or best practice. Please let me know if it's not.
my views.py
def submit_key_request(request, pk):
"""
View function for renewing a specific keyInstance by admin
"""
key_inst=get_object_or_404(KeyInstance, pk=pk)
names = get_list_or_404(User)
# If this is a POST request then process the Form data
if request.method == 'POST':
name = request.POST['name']
key_inst.is_requested = True
key_inst.status = 'r'
key_inst.date_requested = datetime.date.today()
key_inst.borrower = name
key_inst.save()
return HttpResponseRedirect(reverse('all-available-keys') )
# If this is a GET (or any other method) create the default form.
else:
pass
return render(request, 'catalog/keyinstance_request_update.html', {'keyinst':key_inst, 'names':names})
template
{% extends "base_generic.html" %}
{% block content %}
<div class="wrapper">
<div class="centered"> <h1>Request Keys For Room: {{keyinst.roomkey}}</h1></div>
<div class="square-box">
<div class="square-content">
<form action="" method="post" >
{% csrf_token %}
</br>
<select name = 'name' required>
{% for key in names %}
<option value="{{ key }}">{{ key }}</option>
{% endfor %}
</select>
<p>
(Please use their login name i.e. <b>{{ user.get_username }}</b>)
</p>
<p><input required id="checkBox" type="checkbox" onclick="validate()"> I accept the terms and conditions</p>
<p id="text" style="display:none">You Have Agreed To the Terms and Conditions</p>
<input type="submit" value="Submit" />
</form>
</div>
</div>
</div>
{% endblock %}