django file upload progress bar with XMLHttpRequest - python

i created a normal django model.ModelForm and it is worked perfectly until i tried to add Progress bar for files uploading, i have an issue. i recieve the form information(request.POST and request.FILES) twice! but it is save the data only once in database, so also it is work, but i know i have a mistake in my code and i want to understand my mistake.
this is my function for displaying the progress bar:
function UploadFilesWithProgress(form, url) {
const progressbarWrap = document.querySelector('.progress-bar-wrap'),
label = progressbarWrap.querySelector('h6'),
percentage = progressbarWrap.querySelector('span'),
progressbarFill = progressbarWrap.querySelector('.progress > .progress-bar')
let xhr = new XMLHttpRequest()
xhr.open('POST', url, true);
xhr.upload.onloadstart = function (e) {
progressbarWrap.classList.remove('d-none')
percentage.textContent = '0%'
label.textContent = 'uploading...'
};
xhr.upload.onprogress = function (e) {
const percent = e.lengthComputable ? (e.loaded / e.total) * 100 : 0;
progressbarFill.style.width = percent.toFixed(2) + '%';
progressbarFill.setAttribute('aria-valuenow', percent.toFixed(2))
percentage.textContent = percent.toFixed(2) + '%';
}
xhr.upload.onloadend = function (e) {
label.textContent = 'uplaod completed!'
percentage.textContent = 'completed!'
}
xhr.send(new FormData(form));
}
Form = document.getElementById('add-course-form')
if (Form) {
Form.onsubmit = function () {
UploadFilesWithProgress(Form, Form.action);
}
}
and this is my view:
# I use CBV, so i share just the post method to not get missy.
def post(self, *args, **kwargs):
form = OfflineTutorialForm(
user=self.request.user.booth,
data=self.request.POST,
files=self.request.FILES
)
video_formset = AddOfflineVideoTutorialFormSet(
data=self.request.POST,
files=self.request.FILES
)
print(self.request.POST, self.request.FILES)
if form.is_valid() and video_formset.is_valid():
off_tutorial = form.save(commit=False)
off_tutorial.booth = self.request.user.booth
off_tutorial.save()
form.save_m2m()
video_off_tutorial = video_formset.save(commit=False)
for video in video_off_tutorial:
video.tutorial = off_tutorial
video.save()
return redirect('offline-tutorial')
return redirect('/')

It looks like you are uploading the data via form submit and ajax, you can prevent the form from submitting normally with event.preventDefault()
Form.onsubmit = function (event) {
event.preventDefault();
UploadFilesWithProgress(Form, Form.action);
}

Related

How to retrieve the values from a post request function django views. DRF

I have a function that makes a queryset when data from my frontend is posted.
This viewset is using a serializer of combined models.
On my index page on the fronted I have a treeview filter and this view loads the query to
a config page. I need to access the event id's after this query is made to be passed to a separate task on the backend for polling.
However I cannot access the data in this function. How would I get retrieve this query and filter on the data? right now I can't print the queryset to see its structure.
Edit:
I can see the response payload now and the structure is as follows
[{"id":395,"event":{"id":175,"start_time":"28-10-20","sport_id":"9","event_id":"1576232279920003","event_name":"Botic Van de Zandschulp vs Benjamin Bonzi","status":"open"},"market":{"id":198,"market_id":"1576232286670003","market_name":"Moneyline","status":"open","volume":50.4951,"is_ip":"False","event":175},"bettriggers":null,"stakes":null,"userstakes":null,"order":null,"runner_id":"1576232286740003","name":"Botic Van de Zandschulp","back_odds":1.62893,"lay_odds":1.68028},{"id":396,"event":{"id":175,"start_time":"28-10-20","sport_id":"9","event_id":"1576232279920003","event_name":"Botic Van de Zandschulp vs Benjamin Bonzi","status":"open"},"market":{"id":198,"market_id":"1576232286670003","market_name":"Moneyline","status":"open","volume":50.4951,"is_ip":"False","event":175},"bettriggers":null,"stakes":null,"userstakes":null,"order":null,"runner_id":"1576232286780103","name":"Benjamin Bonzi","back_odds":2.47,"lay_odds":2.59}]
class CombinedViewSet(mixins.ListModelMixin,
mixins.DestroyModelMixin,
mixins.RetrieveModelMixin,
viewsets.GenericViewSet):
permission_classes = [IsMeOrReadOnly]
queryset = Runner.objects.all()
serializer_class = CombinedSerializer
#action(detail=False, methods=['POST','GET])
def loaditem(self, request):
keys = request.data['keys']
queryset = []
for xx in keys:
if xx['time_key'] is None:
if xx['event_key'] is None:
queryset.extend(Runner.objects.filter(event__sport_id=xx['sport_key']))
else:
queryset.extend(Runner.objects.filter(event__event_id=xx['event_key']))
else:
date_str = xx['time_key']
datetime_obj = datetime.datetime.strptime(date_str, '%d-%m-%y')
queryset.extend(Runner.objects.filter(event__start_time__date=datetime_obj, event__sport_id=xx['sport_key']))
serializer_class = CombinedSerializer(queryset, many=True)
return Response(serializer_class.data)
What my end goal is to pass in the filtered list of event_id's from load item function to a backend celery task
#shared_task(bind=True, base=QueueOnce, once={'graceful': True})
def get_events(self):
api = get_client()
sports = api.reference_data.get_sports()
logger.warning(f'GET EVENTS task has been called now')
events = api.market_data.get_selected_events(event_ids=['2323','34343','1576232279920003','etc'])
This is what my serializer looks like
class CombinedSerializer(serializers.ModelSerializer):
event = EventSerializer()
market = MarketSerializer()
bettriggers = BetTriggersSerializer()
stakes = StakesSerializer()
userstakes = UserStakesSerializer()
order = OrderStakesSerializer()
class Meta:
model = Runner
fields= '__all__'
Frontend code for posting data
load_item: function (event) {
if(this.value == null) return;
var len = this.value.length;
var req_key = [];
for (var x=0; x<len; x++) {
var str = ''+this.value[x];
var tmp_arr = str.split('#');
var sport_key = null;
var time_key = null;
var event_key = null;
switch(tmp_arr.length) {
case 1:
sport_key = tmp_arr[0];
break;
case 2:
event_key = tmp_arr[1];
break;
case 3:
time_key = tmp_arr[2];
sport_key = tmp_arr[1];
break;
}
req_key.push({sport_key:sport_key, event_key:event_key, time_key:time_key});
}
var vobj = this
this.$axios.post('/api/combined/loaditem/', {
keys : req_key
})
.then(function (response) {
vobj.$store.dispatch('load_runner', response.data)
vobj.$router.push('/configuration')
})
.catch(function (error) {
//currentObj.output = error;
console.log(error)
});
},

Django - How to get checked objects in template checkboxes?

Im new in Django,
I'm using xhtml2pdf for rendering data objects from template to PDF file , and i want to allow users to render only checked objects by checkboxes into pdf, is there anyway to filter that in Django ?
Thanks
views.py :
def render_to_pdf(template_src, context_dict={}):
template = get_template(template_src)
html = template.render(context_dict)
result = BytesIO()
pdf = pisa.pisaDocument(BytesIO(html.encode('ISO-8859-1')), result, link_callback=link_callback)
if pdf.err:
return HttpResponse('Error')
return HttpResponse(result.getvalue(), content_type='application/pdf')
class ViewPDF(View):
#method_decorator(login_required(login_url='livraison:login_page'))
def get(self, request, *args, **kwargs):
checked_objects = [i dont know how to get them]
queryset = Livraison.objects.filter(id__in=[checked_objects]) # i want something does that
data = {
'livraisons' : queryset,
'now' : f'Livraisons-{date.today()}'
}
pdf = render_to_pdf('pdf_template.html', data)
return HttpResponse(pdf, content_type='application/pdf')
use forms to get user data.
class LivraisonSelectForm(forms.Form):
livraison = forms.ModelChoiceField(label='select', queryset=Livraison.objects.all(), widget=forms.CheckboxInput())
then use it in your view:
class ViewPDF(FormView):
form_class = LivraisonSelectForm
template_name = 'path_to_template_with_html_to_filter_data'
#method_decorator(login_required(login_url='livraison:login_page'))
def form_valid(self, form):
checked_objects = form.cleaned_data.get('livraison', [])
queryset = Livraison.objects.filter(id__in=checked_objects) # i want something does that
data = {
'livraisons' : queryset,
'now' : f'Livraisons-{date.today()}'
}
pdf = render_to_pdf('pdf_template.html', data)
return HttpResponse(pdf, content_type='application/pdf')
and don't forget to show this form in your html {{ form }}
**
UPDATE
**
I Found a solution , i used Ajax code to collect every selected object
// check selected objects (#pdf is the id of the button which gonna generate the pdf file)
$('#pdf').click(function () {
var id = [];
$(':checkbox:checked').each(function (i) {
id[i] = $(this).val()
})
if (id.length === 0) {
alert('Please Select something..');
} else {
$.ajax({
url: '.',
method: 'GET',
data: {
id,
},
success: function (response) {
console.log('PDF is ready')
}
})
}
});
then i ad the variable into the view function to collect the selected objects and filter the queryset
myFunction.selected_ones = request.GET.getlist('id[]')
then filter queryset in the generated_pdf_func
queryset = MODEL.objects.filter(id__in=[x for x in myFunction.selected_ones if x != '0'])
NOTE : <if x != '0'> is important in case you want to select all because it returns 0 and you don't have any id = 0 in the DB

Update Api from Ajax to Python

I don't know how to append data to API in Flask from JS to Python without using a global list in Python route, which is causing all users to see same API info.
I have an ajax post request in my JS static file that allows a user to select an item and upon selecting that item it posts that data to Python route which then loads data and appends it to a global array. And then within the route I return the JSON list to the api. I am trying to figure out another way to do this because with this method first of all from my understanding global variables are God awful for this exact reason because all users can see the global api info.
// On load cart
window.onload = function wowzers(){
var array = [];
var sum = 0;
// Get Data
var xhr = new XMLHttpRequest();
xhr.open('GET', 'pricing/orders/' + username +'/api', true);
xhr.onload = function(){
var data = JSON.parse(this.response);
if(xhr.status >= 200 && xhr.status < 400){
for(x in data){
for(key in data[x]){
array.push(Number(data[x][key]));
sum+=Number(data[x][key]);
subtotal.innerHTML = sum;
row = cart.insertRow(-1);
// Delete Data
row.addEventListener('click', function deleterow(){
index = this.rowIndex;
$.post('pricing/orders/delete', {
delete_item: index
});
cart.deleteRow(index);
subtotal.innerHTML = sum-Number(cart.rows[index].cells[1].innerHTML);
});
cell1 = row.insertCell(0);
cell2 = row.insertCell(1);
cell3 = row.insertCell(2);
cell1.innerHTML = key;
cell2. innerHTML = data[x][key];
cell3. innerHTML = "<button class='btn btn-danger'>Delete</button>"
}
}
console.log(sum);
}else{
console.log(error)
}
}
xhr.send()
}
//Dynamic Cart
for(x = 0; x < tablerows; x++){
table.rows[x].addEventListener('click', addCartItem);
}
function addCartItem(ev){
var array = [];
var sum = 0;
index = this.rowIndex;
equipmentCell = table.rows[index].cells[0];
priceCell = table.rows[index].cells[1];
equipmentName = equipmentCell.innerHTML;
equipmentPrice = priceCell.innerHTML;
// Post Data
$.post('/pricing/orders/' + username + '/api', {
javascript_data: JSON.stringify({[equipmentName]:equipmentPrice})
});
cartrow = cart.insertRow(-1);
// Delete Data
cartrow.addEventListener('click', function deleterow(){
index = this.rowIndex;
subtotal.innerHTML = sum-Number(cart.rows[index].cells[1].innerHTML);
$.post('pricing/orders/delete', {
delete_item: index
});
cart.deleteRow(index);
});
cell1 = cartrow.insertCell(0);
cell2 = cartrow.insertCell(1);
cell3 = cartrow.insertCell(2);
cell1.innerHTML= equipmentName;
cell2.innerHTML = equipmentPrice;
cell3.innerHTML = "<button class='btn btn-danger'>Delete</button>";
// Open Api information
var xhr = new XMLHttpRequest();
xhr.open('GET', 'pricing/orders/' + username +'/api', true);
xhr.onload = function(){
var data = JSON.parse(this.response);
if(xhr.status >= 200 && xhr.status < 400){
for(x in data){
for(y in data[x]){
array.push(Number(data[x][y]));
sum+=Number(data[x][y]);
subtotal.innerHTML = sum;
}
}
}else{
console.log(error);
}
}
xhr.send();
}
Route Logic
# ---------------------------------- USER CART API -----------------------------
#app.route('/pricing/orders/<user_name>/api', methods=['POST', 'GET'])
#login_required
def api(user_name):
user_name = current_user.username
if request.method == 'POST':
cart.append(json.loads(request.form["javascript_data"]))
return jsonify(cart)
# ---------------------------- DELETE ITEM IN CART ROUTE ----------------------------------
#app.route('/pricing/orders/delete', methods=['POST', 'GET'])
#login_required
def delete_item():
if request.method == 'POST':
print(cart[json.loads(request.form["delete_item"])])
cart.pop(json.loads(request.form["delete_item"]))
print(cart)
return jsonify({"whoa": "there"})
# ----------------------------- DISPLAY CART BADGE LENGTH---------------------------------
#app.context_processor
def inject_badge_length():
badge_length = len(cart)
return {'BADGE_LENGTH' : badge_length}
I'm hoping I can post data to Python route and then append particular data to API without global list so all users are only able to view their own data. I'm a beginner in the RESTFUL API arena, and just need pointing in the right direction.
It seems like you are running into an issue with storing data.
Most likely, you will want some type of ORM like SQLAlchemy to handle your data storage. It has a bit of a learning curve, but will make things much easier to manage in the long run.

Python/Django form where user selects from a list of Images

I'm new to django and want to make a form that allows a user to select one of three images using radio boxes, once the user selects the image it is saved to their profile and displayed on their profile page.
I am using:
django 1.8.3
userena 1.4.1
Any help or links to documentation that will help would be great.
Basic example. Models:
def get_upload(instance, filename):
return "uploaded_files/user_%s_%s_%s" % (instance.user, datetime.datetime.today().strftime("%d-%m-%Y %H-%M-%S"), filename)
class UserModel():
# your fields
image = models.FileField(upload_to=get_upload, default='')
FileField
Forms:
class UploadForm(forms.ModelForm):
"""Auxiliary class to make file uploading more convenient."""
def __init__(self, *args, **kwargs):
super(UploadForm, self).__init__(*args, **kwargs)
class Meta:
model = UserModel
fields = ('image')
View:
def upload(request):
if request.method == "POST":
profile = request.user.profile
image_type = request.POST.get("image_type", None)
if image_type == "blah":
profile.image = request.FILES[image_type]
else:
return HttpResponse("Error")
request.user.profile.save()
return HttpResponse('OK')
request.FILES
JS with soem Jquery:
var SIZE_RESTRICT = 10*1024*1024; //10 Mbytes
$(document).ready(function()
{
$(".upload_file").find(".upload_button").click(send_file);
$(".upload_file").find(".upload_file_form").find("input[type='file']").click(enable_upload);
});
function send_file()
{
if ($(this).attr("enabled") != "true") return;
// Prevent double-triple clicks with multiple upload.
$(this).attr("enabled", "false");
var form = $(this).parent().find(".upload_file_form").get(0);
var formData = new FormData(form);
var file = $(form).find("input[type='file']").get(0).files[0];
// Not sure about this
// Prevent attack with HUGE files, that will smash server memory
// TODO: Restrict file types (Ex. MIME-image, pdf, doc)
if (file.size > SIZE_RESTRICT)
{
alert("File is too big.");
return;
}
formData.append("proof_type", $(this).attr("upload-type"));
var xhr = new XMLHttpRequest();
var that = this;
// TODO: Define another events like error, abort
xhr.upload.onprogress = function(e) {
// TODO: Progressbar as e.loaded / e.total
if (e.lengthComputable)
console.log((e.loaded / e.total) * 100);
else
console.log("Cant count length");
};
xhr.onload = function(e){
// TODO: Show success confirmation to user.
if (this.response == "Success")
{
// pass
alert(this.response);
}
else if (this.response == "Error")
{
// pass
alert(this.response);
}
else
{
// pass
}
};
xhr.open('POST', '/upload_proof');
xhr.send(formData);
}
function enable_upload()
{
$(this).parent().parent().find(".upload_button").attr("enabled", "true");
}
Actually another simple example could be founded in docs
If the set of images is small and fixed, the best option is to use the choice attribute in the field that defines the image within your model.
The image field could be the path to the image file on the file system.
class UserProfile(models.Model):
GOOD = 'Good.jpg'
UGLY = 'Ugly.jpg'
BAD = 'Bad.jpg'
AVATAR_CHOICES = (
(GOOD, 'Good'),
(UGLY, 'Ugly'),
(BAD, 'Bad'),
)
avatar_img = models.CharField(max_length=255,
choices=AVATAR_CHOICES,
default=GOOD)
Another option is to use FilePathField as your model field
FilePathField(path="/path/to/avatar_images", match="*.jpg", recursive=False)
Another way is to fill the form field dynamically when the form is instantiated.
Please see this SO QA for more on that.
However, as Django docs say
But if you find yourself hacking choices to be dynamic, you’re
probably better off using a proper database table with a ForeignKey
To specify Radiobuttons to be used for the form field, please refer to the official docs on how to set the proper widget.

Return data to ajax function data shown in below format

Using jsondump in python I need to send response to ajaxpage
object format in python shell show in below image
how to use the Java server object notation function to send response
//view output data
[<Userpost: Userpost object>, <Userpost: Userpost object>]
//this is my django view
def load_scroll_posts(request):
if request.method == 'POST':
post_id = request.POST['post_id']
loaded_posts = Userpost.objects.filter(id__gte = post_id)
return HttpResponse(json.dumps({'up':loaded_posts}))
//this is my ajax function
function load_remain_user_posts() {
var post_id = $(".message_box:last").attr("id");
var csrftoken = getCookie('csrftoken');
$.post('/theweber.in/load_m',{
post_id ':post_id,'
csrfmiddlewaretoken ':csrftoken},
function(data){
//console.log(data)
var obj = JSON.parse(data);
console.log(obj)
});
}
in console nothing displaying
Perhaps you mean to pass the two variables as parameters to your post? Something like:
function load_remain_user_posts() {
var post_id = $(".message_box:last").attr("id");
var csrftoken = getCookie('csrftoken');
var parameters = {
"post_id": post_id,
"csrfmiddlewaretoken": csrftoken
};
$.post('/theweber.in/load_m', parameters, function (data) {
//console.log(data)
var obj = JSON.parse(data);
console.log(obj)
});
}

Categories

Resources