How to link user post with its session using flask and MongoDB? - python

I am trying to link users post using Flask. For instance, A user add a new product into the database from a form and it be displayed on its User template.
I don't know whether the post should be added to the database linked by user Id or I just need to use its session.
I have a simple function that I use in the form to insert the post into the collection but I don know whether I need to improve to link with the session user?
app.py:
#app.route('/insert_product', methods=['POST'])
def insert_product():
products=mongo.db.products
products.insert_one(request.form.to_dict())
return redirect(url_for('index'))
User template:
<form class="text-center border border-light p-5" action="{{url_for('insert_product')}}" method='POST'>
<p class="h4 mb-4">Add a new product</p>
<div class="form-row mb-4">
<!-- Category -->
<select class="form-control " name="category_name">
<option disabled selected>Select Category</option>
{% for cat in category %}
<option value='{{cat.category_name}}'>{{cat.category_name}}</option>
{% endfor %}
</select>
</div>
<!-- Product Name -->
<input type="text" id="product_name" name="product_name" class="form-control mb-4" placeholder="Product Name" required>
<!-- Price -->
<input type="number" min="1" step="any" id="#" name="price" class="form-control mb-4" placeholder="Price" required>
<input type="text" id="url" name="url" class="form-control mb-4" placeholder="Add Image URL"> {% if session['email'] != None %}
<input type="text" id="seller" name="seller" class="form-control mb-4" placeholder="Seller Name" value="{{session['name']}}" required> {% endif %}
<div class="form-group green-border-focus">
<textarea class="form-control" id="product_description" name='product_description' placeholder="Add product description" rows="3" required></textarea>
</div>
<!-- Sign up button -->
<button class="btn btn-info my-4 btn-block" type="submit">Submit</button>
<hr>
<!-- Terms of service -->
<p>By clicking
<em>Sign up</em> you agree to our
terms of service
</form>
I am able to display the post and all other CRUD functions. Just this small issue I would like to know to complete my project. Thank you.

I found the answer. I just needed to match the seller name into the collection with the section name using pymongo declaring it as a variable items=mongo.db.find({'seller':session.get('name')}) looping to retrieve the products/posts:
#app.route('/user')
def user():
items=mongo.db.products.find({'seller':session.get('name')})
category=mongo.db.category.find()
email = session.get('email')
if not email:
return redirect(url_for('login'))
return render_template('user.html', category=category, items=items)
Retrieving all the products done by its logged/session users:
{% for item in items%}
code here..
{% endfor %}

Related

Is there anyway to know at which card "add comment" has clicked using flask

I'm trying to add a comment section to my web app however, I want to know which book its "add comment" has clicked I'm thinking about getting the book's ID.
Here is my python
#app.route("/comment", methods=["GET", "POST"])
def comment():
if request.method == "POST":
if not request.form.get("comment"):
return apology("must provide comment", 400)
book = request.form.get("book_id")
print(session["user_id"])
print(book)
id = session["user_id"]
print(id)
user = db.execute("SELECT username FROM users WHERE id=?", id)
db.execute("INSERT INTO comment (comment, user,book_id) VALUES(?, ?,?)", comment, user,book)
return render_template ("index.html")
else:
return render_template ("comment.html")
Here is my html code
<form action="/comment" method="get">
<div class="container">
<div class="row g-3">
{% for book in books %}
<div class="col-12 col-md-6 col-lg-4">
<div class="card">
<img src="{{book.volumeInfo.imageLinks.smallThumbnail}}">
<div class="card-body">
<h5 style="color:red" class="card-title">{{book.volumeInfo.title}}</h5>
<p style="color:blue" class="card-text">{{book.volumeInfo.authors}}</p>
<p style="visibility:hidden" class="card-text">{{book.id}}</p>
<input name="book" style="visibility:hidden" class="form-control mx-auto w-auto" name="book_id" value="{{book.id}}" type="text">
More Info
<button value="{{book.id}}" class="btn btn-primary">add comment</button>
</div>
</div>
</div>
{% endfor %}
</div>
</div>
This HTML element
<input name="book" style="visibility:hidden" class="form-control mx-auto w-auto" name="book_id" value="{{book.id}}" type="text">
has two different values for attribute name, please try removing one of them, that is
<input name="book_id" style="visibility:hidden" class="form-control mx-auto w-auto" value="{{book.id}}" type="text">
and then write if you can access book_id properly in your Flask application. As side if you need to have input invisble to user you might use type="hidden" rather than tinker with styling, in this case
<input name="book_id" value="{{book.id}}" type="hidden">

Django ModelForm non-required CharField giving errors

I have a ModelForm for a model that has a couple of files and with every file, a type description (what kind of file it is). This description field on the model has CHOICES. I have set these file uploads and description uploads as hidden fields on my form, and not required. Now the file upload is working, but the description is giving field errors, the placeholder in the dropdown is not a valid choice, it says. That's true, but since it is not required, I would like it to just be left out of the validation and I am stuck on how.
My codes, shortened them up a bit to keep it concise.
models.py
class Dog(models.Model):
FILE_TYPE_CHOICES = [
('SB', 'Stamboom'),
('RB', 'Registratiebewijs'),
('SJP', 'SJP-diploma'),
('CDD', 'CDD-diploma'),
('WT', 'Workingtestdiploma'),
('MISC', 'Overig'),
]
dog_id = models.UUIDField(unique=True, default=uuid.uuid4)
file_1 = models.FileField(upload_to=user_directory_path, blank=True, validators=[extension_validator])
desc_1 = models.CharField(choices=FILE_TYPE_CHOICES, blank=True, max_length=5)
forms.py (I excluded all these fields from the model-code above to keep it more clear, but this is to demonstrate that these fields are not required. If I print the required attribute of 'desc_1' in the view, it also says false
class DogForm(ModelForm):
class Meta:
model = Dog
fields = ('stamboomnummer', 'stamboomnaam', 'date_of_birth', 'breed',
'sex', 'sire', 'dam', 'microchip', 'breeder', 'owner',
'file_1', 'desc_1')
required = ('stamboomnummer', 'stamboomnaam', 'date_of_birth', 'breed',
'sex', 'sire', 'dam', 'microchip', 'breeder', 'owner')
widgets = {'file_1': forms.HiddenInput(),
'desc_1': forms.HiddenInput(),
}
views.py
#login_required
def newdog(request):
file_opties = Dog.FILE_TYPE_CHOICES
if request.method == 'POST':
form = DogForm(request.POST, request.FILES)
if form.is_valid():
dog = form.save(commit=False)
if request.FILES.get('file_1'):
dog.file_1 = request.FILES['file_1']
dog.user = request.user
dog.save()
assign_perm('accounts.view_dog', request.user, dog)
assign_perm('accounts.change_dog', request.user, dog)
assign_perm('accounts.delete_dog', request.user, dog)
return redirect('accounts:profile')
else:
form = DogForm()
return render(request, 'accounts/add_dog.html', {'form': form,
'buttontitle': 'Opslaan',
'formtitle': 'Hond toevoegen',
'file_type': file_opties})
My form template:
{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% block title %}Title{% endblock %}
{% block content %}
<h2>{{ formtitle }}</h2>
<form id='hond' method="post" enctype="multipart/form-data">
{% csrf_token %}
{% for field in form.visible_fields %}
<div class="mb-3">
{{ field.errors }}
{{ field.label }}{% if field.field.required %}*{% endif %} <br>{{ field }}
</div>
{% endfor %}
{% if form.instance.file_1 %}
{{ form.instance.get_desc_1_display }}<br>
{% endif %}
<div class="input-group mb-3">
<input class="form-control" type="file" name="file_1" id="id_file_1">
<select class="form-select" name="desc_1" id="id_desc_1">
<option selected>Type bestand</option>
{% for item in file_type %}
<option value={{ item.0 }}>{{ item.1 }}</option>
{% endfor %}
</select>
</div>
<button class="btn btn-primary" type="submit">{{ buttontitle }}</button>
</form>
<button class="btn btn-primary" style="margin-top:20px" onclick="history.back()">Annuleren</button>
{% endblock %}
This is my form HTML, with the file input and description input right on the bottom
<form id="hond" method="post" enctype="multipart/form-data">
<input type="hidden" name="csrfmiddlewaretoken" value="gxmQEruF9vTKQshK1M4YnRRg4r0X1SkzEJwbAOwQcbq1mmGvBRSC89DwmZfT6Sv7">
<div class="mb-3">
Stamboomnummer* <br><input type="text" name="stamboomnummer" class="form-control textInput" maxlength="20" required="" id="id_stamboomnummer">
</div>
<div class="mb-3">
Stamboomnaam* <br><input type="text" name="stamboomnaam" class="form-control textInput" maxlength="60" required="" id="id_stamboomnaam">
</div>
<div class="mb-3">
Geboortedatum* <br><input type="text" name="date_of_birth" class="form-control" required="" id="id_date_of_birth">
</div>
<div class="mb-3">
Ras* <br><select name="breed" class="form-select" id="id_breed">
<option value="FR" selected="">Flatcoated Retriever</option>
<option value="CBR">Chesapeake Bay Retriever</option>
<option value="CCR">Curly Coated Retriever</option>
<option value="GR">Golden Retriever</option>
<option value="LR">Labrador Retriever</option>
<option value="NSDTR">Nova Scotia Duck Tolling Retriever</option>
<option value="MISC">Ander ras, geen retriever</option>
</select>
</div>
<div class="mb-3">
Geslacht* <br><select name="sex" class="form-select" required="" id="id_sex">
<option value="" selected="">---------</option>
<option value="REU">Reu</option>
<option value="TEEF">Teef</option>
</select>
</div>
<div class="mb-3">
Vader* <br><input type="text" name="sire" class="form-control textInput" maxlength="60" required="" id="id_sire">
</div>
<div class="mb-3">
Moeder* <br><input type="text" name="dam" class="form-control textInput" maxlength="60" required="" id="id_dam">
</div>
<div class="mb-3">
Chipnummer* <br><input type="text" name="microchip" class="form-control textInput" maxlength="30" required="" id="id_microchip">
</div>
<div class="mb-3">
Fokker* <br><input type="text" name="breeder" class="form-control textInput" maxlength="50" required="" id="id_breeder">
</div>
<div class="mb-3">
Eigenaar* <br><input type="text" name="owner" class="form-control textInput" maxlength="50" required="" id="id_owner">
</div>
<div class="input-group mb-3">
<input class="form-control" type="file" name="file_1" id="id_file_1">
<select class="form-select" name="desc_1" id="id_desc_1">
<option selected="">Type bestand</option>
<option value="SB">Stamboom</option>
<option value="RB">Registratiebewijs</option>
<option value="SJP">SJP-diploma</option>
<option value="CDD">CDD-diploma</option>
<option value="WT">Workingtestdiploma</option>
<option value="MISC">Overig</option>
</select>
</div>
<button class="btn btn-primary" type="submit">Opslaan</button>
</form>
Now, form.is_valid() is False, and the form errors are:
desc_1: Selecteer een geldige keuze. Type bestand is geen beschikbare keuze.
Which means something like: Select a valid option, Type bestand (which is the placeholder text in my form) is not a valid option.
I have tried to override the clean-function but the field is not in the cleaned_data (which is logical I guess, since it's not a valid option) and I do not know how to get in before. I think I might have to define a custom field, but I cannot seem to find how to do that on a modelform with a hidden input :/ Any help would be greatly appreciated :)
Your form is submitting desc_1, so there's a an input with name="desc_1" that has a populated value of Type bestand somewhere in your template. blank=True means the value can be left empty. Since your field has choices and blank=True, the submitted value can be either empty or one of the FILE_TYPE_CHOICES.
You're saying that Type bestand is the placeholder for this field, but if you rendered this field as a hidden input ({{ form.desc_1 }} since you have a widget overridden) it would not and should not have a placeholder.
A regular form equivalent would be:
<input type="hidden" name="desc_1" value="">
Where the value attribute is either left empty or populated with one of the existing options, nothing else.
I will also add that if you're displaying desc_1 field as a <select> element, the placeholder option's value also has to be empty.
Edit
You have an option element that is selected by default. Add the disabled attribute to stop the form from submitting the placeholder text as a value for desc_1:
<option value="" selected disabled>Type bestand</option>

Why request.method is not getting invoked?

I have a read-only textbox which preloaded value from database which upon a button click sends it's value to a method present in backend to perform DELETE query of sql. The problem is occuring when I am click on the button the method is invoked but the request.method condition is not invoked. It is directly going to the end return statement of the method.
#app.route('/home/delete_reminder/<string:id_val>',methods=['GET','POST'])
#is_logged_in
def delete_reminder(id_val):
if request.method=='POST':
desc = request.form['description']
x = desc.split(',')
cur = mysql.connection.cursor()
cur.execute('DELETE FROM set_reminder WHERE DATE=%s,SUBJECT=%s,DESCRIPTION=%s',[x[0],x[1],x[2]])
cur.execute('DELETE FROM recur WHERE RECUR_NEXT=%s',[id_val])
flash('Reminder Deleted','danger')
mysql.connection.commit()
cur.close()
return redirect(url_for('search_reminder_to_delete'))
This is my backend code.
<form method="POST">
{% for data in value %}
<div class="form-group">
<label>Description</label>
<input type="text" name="description" class="form-control" readonly="true" value="{{data.DATE}},{{data.SUBJECT}},{{data.DESCRIPTION}}">
</div>
Delete Reminder
{% endfor %}
</form>
This is the html part.
Your button isn't a button, it's a link. You aren't submitting your form.
If you want to fo that then you need to make you form tag:
<form method="POST" action="/home/delete_reminder/{{data.RECUR_NEXT}}">
and switch your button to be a real button that submits the form:
<div class="button">
<button type="submit" class="btn btn-warning">Send your message</button>
</div>
EDIT: Seeing that you want to have multiple possible routes for your form based on the loop.
You could try and use the formaction attribute, although it isn't going to be supported by every browser version.
<form method="POST">
{% for data in value %}
<div class="form-group">
<label>Description</label>
<input type="text" name="description" class="form-control" readonly="true" value="{{data.DATE}},{{data.SUBJECT}},{{data.DESCRIPTION}}">
</div>
<div class="button">
<button formaction="/home/delete_reminder/{{data.RECUR_NEXT}}" class="btn btn-warning" type="submit" class="btn btn-warning">Delete Reminder</button>
</div>
{% endfor %}
However this will still result in your description field that is passed to the request having every single description from the whole form in a list or possibly just the last one as a single value (I can't quite remember the behaviour of multiple inputs with the same name), which I don't think is what you're expecting to happen.
It may just be easiest to create a separate form for each link in a loop to be honest:
{% for data in value %}
<form method="POST" action="/home/delete_reminder/{{data.RECUR_NEXT}}">
<div class="form-group">
<label>Description</label>
<input type="text" name="description" class="form-control" readonly="true" value="{{data.DATE}},{{data.SUBJECT}},{{data.DESCRIPTION}}">
</div>
<div class="button">
<button class="btn btn-warning" type="submit" class="btn btn-warning">Delete Reminder</button>
</div>
</form>
{% endfor %}

NOT NULL constraint failed: adminside_event.event_data

I have problem with my code which is i try to submit my Event form in the models. But when i run the form it will show the whole form (and another thing is that it will not show the values in the select box of the rounds) and when i click on the the submit button it will through an error.Please help me out this.
VIEW SIDE CODE:--
def addevents(request):
if request.method=="POST":
name=request.POST['events']
est=request.POST['starttime']
eet=request.POST['endtime']
s=Event()
s.ename=name
s.event_start_time=est
s.event_end_time=eet
s.save()
cats = request.POST.getlist('cats')
for i in cats:
s.categories.add(Category.objects.get(id=i))
s.save()
roundd = request.POST.getlist('rround')
for j in roundd:
s.rounds.add(Round.objects.get(id=j))
s.save()
return render(request,'adminside/addevents.html')
else:
rounds = Round.objects.all()
categories = Category.objects.all()
return render(request,'adminside/addevents.html',{'categories':categories,'rounds':rounds})
MODELS SIDE:-
class Event(models.Model):
ename=models.CharField(max_length=200)
categories = models.ManyToManyField(Category)
event_data = models.DateField()
event_start_time = models.TimeField()
event_end_time = models.TimeField()
rounds = models.ManyToManyField(Round)
EVENT PAGE FORM:-
{% extends 'adminside/master.html' %}
{% block content %}
<div class="col-12">
<div class="card">
<div class="card-body">
<h4 class="card-title">Events</h4>
<p class="card-description"> All fields are Compulsory </p>
<form class="forms-sample" method="POST">
{% csrf_token %}
<div class="form-group">
<label for="exampleInputEmail1">Add Event</label>
<input type="text" class="form-control" name="events" id="exampleInputEmail1" placeholder="Enter Event">
</div>
<div class="form-group">
<label>Categories:</label>
<select class="form-control" multiple name="cats">
{% for i in categories %}
<option value="{{ i.id }}">{{ i.cname }}</option>
{% endfor %}
</select>
</div>
<div class="form-group">
<label for="exampleInputEmail1">Event Start Time</label>
<input type="text" class="form-control" name="starttime" id="exampleInputEmail1" placeholder="Enter Event Start Time">
</div>
<div class="form-group">
<label for="exampleInputEmail1">Event End Time</label>
<input type="text" class="form-control" name="endtime" id="exampleInputEmail1" placeholder="Enter Event End Time">
</div>
<div class="form-group">
<label for="exampleInputEmail1">Round Name</label>
<select class="form-control form-control-lg" id="exampleFormControlSelect1" multiple name="rround">
{% for i in rounds %}
<option value="{{i.id}}">{{i.round}}</option>
{% endfor %}
</select>
</div>
<button type="submit" value=Addme class="btn btn-success mr-2">Submit</button>
<button class="btn btn-light">Cancel</button>
</form>
</div>
</div>
</div>
{% endblock %}
in addevents view you need to add something in event_data before saving because this value do not accept null or modify your models.py
event_data = models.DateField()
modify this to default value like the current time
event_data = models.DateField(default=timezone.now)
hope this helps

How to send data to view from form after asking for confirmation?

I created a simple form where I'm asking for user input and then posting that to the database. Now I would like the user to confirm the data in form is correct, and for that I'm using a Bootstrap modal.
How can I send the data from the form to the view when pressing the 'OK' button on the modal.
I'm new to the Django framework, and maybe there is another better way without using bootstrap modals.
Form:
class ReportForm(forms.Form):
report_title = forms.ChoiceField(choices=get_report_titles())
report_link = forms.CharField(widget=forms.Textarea, required=False)
Html file:
<form class="w-100" action="" method="post">
{% csrf_token %}
<label class="pl-0 mt-auto mr-2">Report Name</label>
<select name="report_title" class="form-control report-name">
<option selected>Select report</option>
{% for name in report_names %}
<option>{{ name }}</option>
{% endfor %}
</select>
<div class="my-1 col-lg-12 float-left pl-0">
<label>Report Link</label>
<input class="form-control bg-white" type="text" id="report" name="report_link">
</div>
<input id="confirm" value="Save" type="button" data-toggle="modal" data-target="#exampleModalCenter" class="btn btn-outline-success" />
</form>
<!-- Modal -->
<div class=" modal fade" id="exampleModalCenter" tabindex="-1" role="dialog" aria-labelledby="exampleModalCenterTitle" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLongTitle">Confirmation</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
Make sure you have the right title and link.
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary">Save</button>
</div>
</div>
</div>
</div>
View:
def report_view(request):
if request.method == 'POST':
form = ReportForm(request.POST)
if form.is_valid():
report_title = form.cleaned_data['report_title']
report_link = form.cleaned_data['report_link']
new_report = Report(title = report_title, link = report_link)
new_report.save()
Simply update your code with these lines, add id="exampleForm".
start form tag with
<form class="w-100" action="" id="exampleForm" method="post">
Replace Save button with (add id="save"):
<button type="button" id="save" class="btn btn-primary">Save</button>
and finally add this script at the bottom to submit your form when save is clicked:
<script>
$("#save").on("click", function(e) {
$("#exampleForm").submit();
});
</script>
also I feel your view is not written correctly. It should be something like this, I'm not sure what you're trying to do:
def report_view(request):
if request.method == 'POST' and form.is_valid():
form = ReportForm(request.POST)
report_title = form.cleaned_data['report_title']
report_link = form.cleaned_data['report_link']
new_report = Report(title = report_title, link = report_link)
new_report.save()
Let me know if you still need help
This needs changing because you're not giving any values.
<select name="report_title" class="form-control report-name">
<option selected>Select report</option>
{% for name in report_names %}
<option>{{ name }}</option>
{% endfor %}
</select>
Try:
<select name="report_title" class="form-control report-name">
<option selected>Select report</option>
{% for name in report_names %}
<option value="{{name.pk}}">{{ name }}</option>
{% endfor %}
</select>
where name.pk is the value relating to the choices.
Also, if you change your form to a ModelForm you can just do:
if form.is_valid():
new_report = form.save()

Categories