I've a project one of the models has image field to upload picture , i made it modelformset_factory to upload multiple images , but from webcam ! is there any django tips or modules to do that ? i tried this but i cant take more than one picture , and cant assign taken photo into the ImageField?
my image upload model
class Document(models.Model):
booking =models.ForeignKey(Booking,on_delete=models.PROTECT)
docs = models.ImageField(upload_to=upload_docs)
def __str__(self):
return str(self.booking.id)
my forms.py
class UploadDocumentsForm(forms.ModelForm):
class Meta:
model = Document
fields = ['docs']
UploadDocumentFormSet = modelformset_factory(Document,form=UploadDocumentsForm,extra=1,can_delete=True)
my views.py
#login_required
def add_new_image(request,id):
obj = get_object_or_404(Booking,id=id)
if request.method == 'POST':
images = UploadDocumentFormSet(request.POST,request.FILES)
if images.is_valid():
for img in images:
if img.is_valid() and img.cleaned_data !={}:
img_post = img.save(commit=False)
img_post.booking = obj
img_post.save()
return redirect(reverse_lazy("booking:add_booking",kwargs={"room_no":obj.room_no.room_no}))
else:
messages.error(request,_('take a picture or choose an image'))
images = UploadDocumentFormSet(queryset=Document.objects.none())
return render(request,'booking/add_img.html',{'obj':obj,'images':images})
const player = document.getElementById('player');
const canvas = document.getElementById('canvas');
const context = canvas.getContext('2d');
const captureButton = document.getElementById('capture');
const constraints = {
video: true,
};
captureButton.addEventListener('click', (e) => {
// Draw the video frame to the canvas.
context.drawImage(player, 0, 0, canvas.width, canvas.height);
e.preventDefault();
});
// Attach the video stream to the video element and autoplay.
navigator.mediaDevices.getUserMedia(constraints)
.then((stream) => {
player.srcObject = stream;
});
$('#addButton').click(function() {
var form_dex1 = $('#id_form-TOTAL_FORMS').val();
$('#images').append($('#formset').html().replace(/__prefix__/g,form_dex1));
$('#id_form-TOTAL_FORMS').val(parseInt(form_dex1) + 1);
});
<button id="addButton" class="px-4 py-1 pb-2 text-white focus:outline-none header rounded-xl">
{% trans "add new form" %}
<i class="bi bi-plus"></i>
</button>
<form action="" method="POST" enctype="multipart/form-data" dir="ltr">{% csrf_token %}
{% for form in images.forms %}
{{form.id}}
<div id="main_form" class="text-lg">
<div class="border border-purple-900 mt-2 rounded-lg p-2 text-center">
<p>{% for i in obj.takes_by.all %}
{{forloop.counter}} : {{i.full_name}}
{% endfor %}
</p>
</div>
</div>
<hr>
{{images.management_form}}
<div class="form-group mt-3" id="images">
{{ form.docs | add_class:'form-control-file' }}
</div>
<video id="player" controls autoplay></video>
<button id="capture">Capture</button>
<canvas id="canvas" width=320 height=240></canvas>
{% endfor %}
<div class="form-group mt-3" id="formset" style="display: none;">
{{ images.empty_form.docs | add_class:'form-control-file' }}
</div>
<button class="header pt-2 text-white px-4 p-1 rounded-lg mt-4">{% trans "save" %}</button>
</form>
but im not sure how to achieve it ?!
thank you for helping
Related
I'm using Javascript to make part of my web page editable for logged-in admin users. In one page, I have cards that display information about three people from the database. The cards contain username, skills, and bio fields. The username is also used a second time in the bio.
When the edit button is clicked, the first username, skills, and the bio without the username become editable. And when I change the username and click on the save button only the first username changes. For the one in the bio to update I need to reload the page even though they have the same id in my HTML template. How can I change the second one as well without reloading the page?
about.html:
% extends "potbs/layout.html" %}
{% load static %}
{% block script %}
<script src="{% static 'potbs/about.js' %}"></script>
{% endblock %}
{% block body %}
<div class="container">
<div class="row justify-content-center">
{% for member in team_members %}
<div class="col" id="border">
<!--If user is admin, show edit button-->
{% if user.is_superuser %}
<div class="position-relative" id="edit_button_{{member.id}}" style="display: block;">
<button class="btn btn-lg position-absolute top-0 end-0" id="edit_profile" data-id="{{member.id}}" data-username="{{member.username}}">
<i class="fa fa-edit fa-solid" style="color: white; margin-right: 5px;"></i></button>
</div>
{% endif %}
<div class="col-xs-12 center-block text-center">
<!--Display profile picture-->
<img class="pp" id="pp_{{member.id}}" src="{{member.profile_picture.url}}" alt="{{member.username}}">
<!--Edit form-->
<div class="form-group" id="edit_{{member.id}}">
</div>
<!--Display username,skills and bio-->
<div id="remove_{{member.id}}" style="display: block;">
<h3 class="username" id="username_{{member.id}}">{{member.username}}</h3>
<p class ="skills" id="skills_{{member.id}}">{{member.skills}}</p>
<div class="bio">
<strong class="username" id="username_{{member.id}}" style="font-size: large;">{{member.username}}, </strong><p id="bio_{{member.id}}">{{member.bio}}</p>
</div>
</div>
</div>
</div>
{% endfor %}
</div>
</div>
{% endblock %}
about.js:
document.addEventListener("DOMContentLoaded", function(){
const button = document.querySelectorAll("#edit_profile")
button.forEach(function(button){
button.onclick = function(){
const memberID = button.dataset.id;
const usernameID = button.dataset.username;
const username = document.getElementById(`username_${memberID}`);
const skills = document.getElementById(`skills_${memberID}`);
const bio = document.getElementById(`bio_${memberID}`);
//Create textareas for editable fields
let edit_username = document.createElement("textarea");
edit_username.setAttribute("rows", "1");
edit_username.innerHTML = username.innerHTML
edit_username.id = `edit_username_${memberID}`;
edit_username.className = `form-control username ${usernameID}`;
let edit_skills = document.createElement("textarea");
edit_skills.setAttribute("rows", "1");
edit_skills.innerHTML = skills.innerHTML;
edit_skills.id = `edit_skills_${memberID}`;
edit_skills.className = "form-control skills";
let edit_bio = document.createElement("textarea");
edit_bio.setAttribute("rows", "5");
edit_bio.innerHTML = bio.innerHTML;
edit_bio.id = `edit_bio_${memberID}`;
edit_bio.className = "form-control bio";
edit_bio.style.borderRadius = "15px";
//Create cancel button
const cancelButton = document.createElement("button");
cancelButton.innerHTML = "Cancel";
cancelButton.id = `cancelButton_${memberID}`;
cancelButton.className = "btn btn-danger col-3";
cancelButton.style.margin = "10px";
//Create save button
const saveButton = document.createElement("button");
saveButton.innerHTML = "Save";
saveButton.id = `saveButton_${memberID}`;
saveButton.className = "btn btn-success col-3";
saveButton.style.margin = "10px";
//Hide the edit button and current content
document.getElementById(`edit_button_${memberID}`).style.display = "none";
document.getElementById(`remove_${memberID}`).style.display = "none";
//Add textarea fields to the div
document.getElementById(`edit_${memberID}`).append(edit_username);
document.getElementById(`edit_${memberID}`).append(edit_skills);
document.getElementById(`edit_${memberID}`).append(edit_bio);
document.getElementById(`edit_${memberID}`).append(saveButton);
document.getElementById(`edit_${memberID}`).append(cancelButton);
// When the cancel button is clicked
cancelButton.addEventListener("click",function(){
cancel(memberID);
})
// When the save button is clicked
saveButton.addEventListener("click", function(){
edit_username = document.getElementById(`edit_username_${memberID}`);
edit_skills = document.getElementById(`edit_skills_${memberID}`);
edit_bio = document.getElementById(`edit_bio_${memberID}`);
fetch(`/edit_profile/${memberID}`,{
method: "POST",
body: JSON.stringify({
username: edit_username.value,
skills: edit_skills.value,
bio: edit_bio.value,
})
})
.then(response => response.json())
.then(result => {
console.log(result);
if(result[`error`]){
cancel(memberID)
}
else {
username.innerHTML = result.username;
skills.innerHTML = result.skills;
bio.innerHTML = result.bio;
cancel(memberID)
}
})
.catch(error => {
console.error(error);
console.log(edit_username.value);
})
})
}
});
})
Iam building my portfolio website and i build a simple stocktracker. I added some charts from Chart.js, but somehow only one gets rendered when I excecute the code.
I managed to assign all the divs and data dynamically by making the variables dynamic. I did this by adding the portfolio id in the for loop. I can't figure out why its not working. Appreciate any help.
{% extends 'base.html' %}
{% block page_content %}
{% if user.is_authenticated %}
<body>
<div class="container">
<div class="row">
<div class="col-12">
<h2>
Welcome to the stocktracker
</h2>
<p>I build this stocktracker app to learn database operations. To get current stock data, I linked this to
the free API from Polygon.io. It's only possible to do 5 API calls per minute. You will see an error
message whenever the api calls are exceeded.
<br><br>Current features are:
<ol>
<li>Basic CRUD database operation</li>
<li>Adding portfolio's linked to user</li>
<li>Only show portfolio's linked to user</li>
<li>Show general KPI's in portfolio overview</li>
<li>KPI's calculated based on positions in portfolio</li>
<li>Adding position to portfolio</li>
<li>API connection with Polygon.io to get live stock data</li>
<li>Chart.js integration for visual representation of portfolio metrics</li>
</ol>
</p>
</div>
</div>
<div class="row">
<div class="col-8">
<h2>Select your portfolio</h2>
</div>
<div class="col-4 text-end">
<!-- Button trigger modal -->
<button type="button" class="btn btn-secondary" data-bs-toggle="modal" data-bs-target="#addPortfolioModal">
Add new portfolio
</button>
<!-- Modal -->
<div class="modal fade" id="addPortfolioModal" tabindex="-1" role="dialog"
aria-labelledby="addPortfolioModalLabel"
aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="addPortfolioLabel">Modal title</h5>
<button type="button" class="close" data-bs-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<form name="portfolio_form" method="post">
{% csrf_token %}
<p>
{{ portfolio_form }}
</p>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close
</button>
<input type="submit" value="Submit"/>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
<div>
{% for portfolio in portfolios %}
<div class="row pt-4">
<div class="col-6">
<a class="btn btn-primary" href="{% url 'portfolio_detail' portfolio.pk%}">Go to {{ portfolio }}</a>
</div>
</div>
{% if portfolio.total_positions > 0 %}
<div>
{% load static %}
<div class="col-4 text-start" style="width: 50%;">
<canvas id="pie-chart{{ portfolio.pk }}"></canvas>
<script src="https://cdn.jsdelivr.net/npm/chart.js#2.9.3/dist/Chart.min.js"></script>
<script>
var randomNum_{{ portfolio.pk }} = () => Math.floor(Math.random() * (235 - 52 + 1) + 52);
function rgbToHex(r, g, b) {
return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
}
countPositions = {{ portfolio.total_positions|safe }};
var barColors_{{ portfolio.pk }} = [];
for (let i = 0; i < countPositions; i++) {
randomGeneratedColor = rgbToHex(randomNum_{{ portfolio.pk }}(), randomNum_{{ portfolio.pk }}(), randomNum_{{ portfolio.pk }}());
while (barColors_{{ portfolio.pk }}.includes(randomGeneratedColor)) {
randomGeneratedColor = rgbToHex(randomNum(), randomNum(), randomNum());
}
barColors_{{ portfolio.pk }}.push(randomGeneratedColor);
}
var config_{{ portfolio.pk }} = {
type: 'pie',
data: {
datasets: [{
data: {{ portfolio.data_for_chart_array|safe }},
backgroundColor: barColors_{{ portfolio.pk }},
label: 'Stock ticker'
}],
labels: {{ portfolio.labels_array|safe }}
},
options: {
responsive: true
}
};
window.onload = function() {
var ctx = document.getElementById('pie-chart{{ portfolio.pk }}').getContext('2d');
window.myPie = new Chart(ctx_{{ portfolio.pk }}, config_{{ portfolio.pk }});
};
</script>
</div>
</div>
{% endif %}
<div class="row">
<div class="col-4 pt-2">
<b>Total amount invested:</b> {{ portfolio.total_amount_invested }}
<br><b>Positions:</b> {{ portfolio.total_positions }}
<br><b>Profit:</b> {{ portfolio.total_profit }}
<br><b>Profit in %:</b> {{ portfolio.total_profit_percentage }} %
</div>
</div>
</div>
{% endfor %}
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap#5.1.3/dist/js/bootstrap.bundle.min.js"
integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p"
crossorigin="anonymous"></script>
</div>
</body>
{% endif %}
{% endblock %}
Somehow only the last chart gets rendered instead of all three.
You have a loop there, and in each iteration of the loop, you're using window.onload = function() {…};
Basically, you're overwriting the onload function at each iteration of the loop, so only the last overwrite survives.
What you want is to add load event listeners on the window instead of continually overwriting one single listener.
To achieve this, I would recommend replacing this:
window.onload = function () {…}
with this:
window.addEventListener('load', function() {…})`
See addEventListener
Another way of seeing that window.onload = function () {…} is problematic is the following snippet:
window.onload = function () { alert('one') };
window.onload = function () { alert('two') };
Q: What do you expect to happen on page load here?
A: Similarly to your case, only the second function (alerting "two") will be called.
When I changed the import method I got an error on a live search.
This is the JQUERY code I'm using. The error I'm gettin is the blogpost['title'] is empty.
I've read that it might be due to the name blogpost being the overall container, so it's not actually a single blogpost but all the blogpost, but I don't know how to fix this. I think the most helpful would be someone taking a look at the rdata and the json error. Thanks!
<script>
var data = '{{qs_json}}'
data = data.replace(/"/g, '"');
data = data.replace(/(?:\r\n|\r|\n)/g, '');
console.log(data)
rdata = JSON.parse(data)
console.log(rdata)
const input = document.getElementById('search_form')
let filteredArr = []
input.addEventListener('keyup', (e) => {
jsbox.innerHTML = ""
filteredArr = rdata.filter(blogpost => blogpost['title'].toLowerCase().includes(e.target.value.toLowerCase()))
if (filteredArr.length > 0) {
filteredArr.map(blogpost => {
jsbox.innerHTML += `
<div class="col mt-5 ml-1">
<a href="blog/${blogpost.slug}" style="text-decoration: none">
<div class= "card">
<div class='blogpost_image_container'>
<img src="${blogpost.image}" class="card-img-top" alt="blogpost image">
</div>
<div class="card-body">
<h5 class="card-title">${blogpost.title} </h5>
<p class="card-text"> ${blogpost.subtitle} </p>
<span id="category_badge" class="badge rounded-pill bg-warning text-dark"> ${blogpost.category}
</div>
</div>
</div >
</a> `
})
}
else {
jsbox.innerHTML = `<div class= "col mt-5 ml-1"> <h5 class="card-title"> No Matches Found! </h5></div >`
}
})
</script>
However the console logged Rdata shows something different:
The Console logged rdata
The error message
This is my django view import:
class BlogListView(ListView):
model = BlogPost
template_name = "blog/blog.html"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
if self.request.GET.get('category_filter'):
cat_filter = self.request.GET.get('category_filter')
all_blogposts = BlogPost.objects.filter(
category=cat_filter)
print(all_blogposts)
else:
all_blogposts = BlogPost.objects.all()
data = serializers.serialize("json", all_blogposts)
context["qs_json"] = data
context["blogposts"] = all_blogposts
context["categories"] = Category.objects.all()
return context
And this is the forloop in the django template, not sure if it's useful.
<div class="row row-cols-1 row-cols-md-2 g-4" id="jsbox">
{% for blogpost in blogposts %}
<div class="col mt-5 ml-1">
<div class="card">
<a href="{% url 'blogpost' blogpost.slug %}">
<div class='blogpost_image_container'>
<img src="{{ blogpost.image }}" class="card-img-top" alt="blogpost image">
</div>
<div class="card-body">
<h5 class="card-title">{{ blogpost.title }} </h5>
<p class="card-text"> {{ blogpost.subtitle}} </p>
<span id="category_badge" class="badge rounded-pill bg-warning text-dark">
{{ blogpost.category }}</span>
</div>
</a>
</div>
</div>
{% endfor %}
</div>
{% endblock %}
I am trying to implement a Live Search using Javascript for my Django Project, I search by words is working but I am only capable of getting Titles only as a result. I am trying to add the Href so that It can direct the title to the url.
Here is what I have tried:
class Item(models.Model):
title = models.CharField(max_length=100)
image = models.ImageField(blank=False, upload_to=upload_design_to)
price = models.DecimalField(decimal_places=2, max_digits=100)
discount_price = models.DecimalField(decimal_places=2, max_digits=100, blank=True, null=True)
timestamp = models.DateTimeField(default=timezone.now)
def get_absolute_url(self):
return reverse("store:product-detail", kwargs={'slug': self.slug})
Here is the views.py
class ItemListView(ListView):
model = Item
paginate_by = 12
template_name = "store/product_list.html"
ordering = ['-timestamp']
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["qs_json"] = json.dumps(list(Item.objects.values()),cls=DjangoJSONEncoder)
return context
Here is the template.html
<input id="search_here" class="mb-2 form-control" placeholder="Type to search...">
<!--Card-->
<div id="box" class='row card-group'>
{% for item in object_list %}
<div class="col-4 mb-3">
<div class="card h-100">
<a href="{{item.get_absolute_url}}">
<embed src="{{ item.image.url }}" class="card-img-top" alt="..."/>
</a>
<div class="card-body">
<h5 class="card-title">{{ item.title }}</h5>
<p class="card-text">
{% if item.description %}
{{ item.description }}
{% endif %}
</p>
</div>
<div class="card-footer">
<small class="text-muted">{{ item.timestamp }}</small>
</div>
</div>
</div>
{% endfor %}
</div>
<!--Card-->
Here is the JS
<script>
const data = '{{qs_json}}'
const rdata = JSON.parse(data.replace(/"/g, '"'))
console.log(rdata)
const input = document.getElementById('search_here')
console.log(input)
let filteredArr = []
input.addEventListener('keyup', (e)=>{
box.innerHTML = ""
filteredArr = rdata.filter(store=> store['title'].includes(e.target.value))
console.log(filteredArr)
var url = "{{item.get_absolute_url}}";
if (filteredArr.length > 0){
filteredArr.map(store=>{
box.innerHTML += `<br>${store['title']}<br>`
})
} else {
box.innerHTML = "<b>No results found...</b>"
}
})
</script>
I am currently reciving an error:
Page not found (404)
Request Method: GET
Request URL: http://127.0.0.1:8000/url
My question:
How to add a link to direct to {{item.get_absolute_url}} using JS
The current code:
box.innerHTML += `<br>${store['title']}<br>`
is linking to the string literal "url".
Since var url contains the URL you want to link to, this change will create the <a> link with the href set to the value of url:
box.innerHTML += `<br>${store['title']}<br>`
I am trying to upload multiple files for a blog post object, however, it seems that my Ajax form is not working properly and I cannot see the files uploading.
Since there is no post object at the time of creating the images, I am trying to upload the files then get them in my view and after saving the post I am trying to save those files by assigning the id of that post to them. Currently, my issue is it seems my files are not uploading and I cannot get them at all.
I am not getting any error and therefore, I cannot find an issue.
Below is my file upload and post create view:
#login_required
def post_create(request):
data = dict()
if request.method == 'POST':
form = PostForm(request.POST)
if form.is_valid():
post = form.save(False)
post.author = request.user
#post.likes = None
post.save()
for image in request.FILES.getlist('file'):
instance = Images(post=Post.objects.get(post.id),image=image)
instance.save()
data['form_is_valid'] = True
posts = Post.objects.all()
posts = Post.objects.order_by('-last_edited')
data['posts'] = render_to_string('home/posts/home_post.html',{'posts':posts},request=request)
else:
data['form_is_valid'] = False
else:
form = PostForm
context = {
'form':form
}
data['html_form'] = render_to_string('home/posts/post_create.html',context,request=request)
return JsonResponse(data)
class PostImageUpload(LoginRequiredMixin, View):
def get(self, request):
images = Images.objects.all()
return render(self.request, 'home/posts/post_create.html', {'images':images} )
def post(self, request):
data = dict()
form = ImageForm(self.request.POST, self.request.FILES)
if form.is_valid():
image = form.save(False)
image.save()
data = {'is_valid': True, 'name': image.file.name, 'url': image.file.url}
else:
data['is_valid'] = False
return JsonResponse(data)
This my javascript code:
$(document).ready(function(){
$(".js-upload-images").click(function () {
$("#fileupload").click();
});
$("#fileupload").fileupload({
change : function (e, data) {
if(data.files.length >= 4){
alert("Sorry, you can only upload up to 4 images")
return false;
}
},
dataType: 'json',
sequentialUploads: true,
start: function (e) {
$("#modal-progress").show();
},
stop: function (e) {
$("#modal-progress").hide();
},
progressall: function (e, data) {
var progress = parseInt(data.loaded / data.total * 100, 10);
var strProgress = progress + "%";
$(".progress-bar").css({"width": strProgress});
$(".progress-bar").text(strProgress);
},
done: function (e, data) {
if (data.result.is_valid) {
$("#image_list tbody").prepend(
"<tr><td><a href='" + data.result.url + "'>" + data.result.name + "</a></td></tr>"
)
}
}
});
});
HTML Code
{% load crispy_forms_tags %}
{% load static %}
<script src="{% static 'js/image_upload.js' %}"></script>
<script src="{% static 'js/jquery-file-upload/js/vendor/jquery.ui.widget.js' %}"></script>
<script src="{% static 'js/jquery-file-upload/js/jquery.iframe-transport.js' %}"></script>
<script src="{% static 'js/jquery-file-upload/js/jquery.fileupload.js' %}"></script>
<form method="POST" data-url="{% url 'home:post-create' %}" class="post-create-form">
{% csrf_token %}
<div class="modal-header">
<h5 class="modal-title" >Create a Post</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
{{ form|crispy }}
<div class="my-3 mx-3">
<button type="button" class="btn btn-sm mr-auto btn-primary js-upload-images">
<span><i class="fas fa-camera"></i></span>
</button>
<input id="fileupload" type="file" name="file" multiple
style="display: none;"
data-url="{% url 'home:post-image-upload' %}"
data-form-data='{"csrfmiddlewaretoken": "{{ csrf_token }}"}'>
<table id="image_list" class="table table-bordered my-2">
<tbody>
{% for image in images %}
<tr>
<td>{{ image.file.name }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
<div class="modal fade" id="modal-progress" data-backdrop="static" data-keyboard="false">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">Uploading...</h4>
</div>
<div class="modal-body">
<div class="progress">
<div class="progress-bar" role="progressbar" style="width: 0%;">0%</div>
</div>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<button type="submit" class="btn btn-primary">Post</button>
</div>
</form>
The fileupload framework that I am using is working as well as I can see in the terminal Django is successfully completing the get request.
I appreciate all the help in advance!