I built a web app with Vue js and Django, django rest framework , I am only able to post data from the backend. When I try and fill in the data from the form with vue js nothing posts. here is my code hope someone smart can solve this. Thank you for your help it is appreciated. I followed the tutorial from: https://blog.logrocket.com/how-to-build-vue-js-app-django-rest-framework/
I attempted it twice there may be some code issues with her code. but I am open for anyone to help thank you.
Tasks.vue
<template>
<div class="tasks_container">
<div class="add_task">
<form v-on:submit.prevent="submitForm">
<div class="form-group">
<label for="title">Title</label>
<input type="text" class="form-control" id="title" v-model="title" />
</div>
<div class="form-group">
<label for="description">Description</label>
<textarea
class="form-control"
id="description"
v-model="description"
></textarea>
</div>
<div class="form-group">
<button type="submit">Add Task</button>
</div>
</form>
</div>
<div class="tasks_content">
<h1>Tasks</h1>
<ul class="tasks_list">
<li v-for="task in tasks" :key="task.id">
<h2>{{ task.title }}</h2>
<p>{{ task.description }}</p>
<button #click="toggleTask(task)">
{{ task.completed ? "Undo" : "Complete" }}
</button>
<button #click="deleteTask(task)">Delete</button>
</li>
</ul>
</div>
</div>
</template>
<script>
export default {
data() {
return {
tasks: [],
title: "",
description: "",
};
},
methods: {
async getData() {
try {
// fetch tasks
const response = await this.$http.get(
"http://localhost:8000/api/tasks/"
);
// set the data returned as tasks
this.tasks = response.data;
} catch (error) {
// log the error
console.log(error);
}
},
},
async submitForm() {
try {
// Send a POST request to the API
const response = await this.$http.post(
"http://localhost:8000/api/tasks/",
{
title: this.title,
description: this.description,
completed: false,
}
);
// Append the returned data to the tasks array
this.tasks.push(response.data);
// Reset the title and description field values.
this.title = "";
this.description = "";
} catch (error) {
// Log the error
console.log(error);
}
},
async toggleTask(task) {
try {
// Send a request to API to update the task
const response = await this.$http.put(
`http://localhost:8000/api/tasks/${task.id}/`,
{
completed: !task.completed,
title: task.title,
description: task.description,
}
);
// Get the index of the task being updated
let taskIndex = this.tasks.findIndex((t) => t.id === task.id);
// Reset the tasks array with the new data of the updated task
this.tasks = this.tasks.map((task) => {
if (this.tasks.findIndex((t) => t.id === task.id) === taskIndex) {
return response.data;
}
return task;
});
} catch (error) {
// Log any error
console.log(error);
}
},
async deleteTask(task) {
// Confirm if one wants to delete the task
let confirmation = confirm("Do you want to delete this task?");
if (confirmation) {
try {
// Send a request to delete the task
await this.$http.delete(`http://localhost:8000/api/tasks/${task.id}`);
// Refresh the tasks
this.getData();
} catch (error) {
// Log any error
console.log(error);
}
}
},
created() {
// Fetch tasks on page load
this.getData();
},
};
</script>
App.vue
<template>
<div id="app">
<img alt="Vue logo" src="./assets/logo.png" />
<Tasks />
</div>
</template>
<script>
import Tasks from "./components/Tasks.vue";
export default {
name: "App",
components: {
Tasks,
},
};
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
main.js
import Vue from 'vue'
import App from './App.vue'
import axios from 'axios'
// set a prototype for http
Vue.prototype.$http = axios;
Vue.config.productionTip = false
new Vue({
render: h => h(App),
}).$mount('#app')
vies.py
# parsing data from the client
from rest_framework.parsers import JSONParser
# To bypass having a CSRF token
from django.views.decorators.csrf import csrf_exempt
# for sending response to the client
from django.http import HttpResponse, JsonResponse
# API definition for task
from .serializers import TaskSerializer
# Task model
from .models import Task
#csrf_exempt
def tasks(request):
'''
List all task snippets
'''
if(request.method == 'GET'):
# get all the tasks
tasks = Task.objects.all()
# serialize the task data
serializer = TaskSerializer(tasks, many=True)
# return a Json response
return JsonResponse(serializer.data,safe=False)
elif(request.method == 'POST'):
# parse the incoming information
data = JSONParser().parse(request)
# instanciate with the serializer
serializer = TaskSerializer(data=data)
# check if the sent information is okay
if(serializer.is_valid()):
# if okay, save it on the database
serializer.save()
# provide a Json Response with the data that was saved
return JsonResponse(serializer.data, status=201)
# provide a Json Response with the necessary error information
return JsonResponse(serializer.errors, status=400)
#csrf_exempt
def task_detail(request, pk):
try:
# obtain the task with the passed id.
task = Task.objects.get(pk=pk)
except:
# respond with a 404 error message
return HttpResponse(status=404)
if(request.method == 'PUT'):
# parse the incoming information
data = JSONParser().parse(request)
# instanciate with the serializer
serializer = TaskSerializer(task, data=data)
# check whether the sent information is okay
if(serializer.is_valid()):
# if okay, save it on the database
serializer.save()
# provide a JSON response with the data that was submitted
return JsonResponse(serializer.data, status=201)
# provide a JSON response with the necessary error information
return JsonResponse(serializer.errors, status=400)
elif(request.method == 'DELETE'):
# delete the task
task.delete()
# return a no content response.
return HttpResponse(status=204)
serializers.py
from rest_framework import routers,serializers,viewsets
from .models import Task
class TaskSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Task
fields = ['id', 'title', 'description', 'completed', 'created_at']
Related
I am trying to submit my crispy form using fetch and then methods to django backend. All my fields are submitting to the server. but files are shown as empty fields in the server.
below, is my front end from
{{ photo.media }}
<form action="" method="post" class="form my-4 px-2" enctype="multipart/form-data" id="photo_form"
onsubmit="">
{% csrf_token %}
{{photo|crispy}}
<input type="submit" value="Add" class="btn btn-primary btn-lg">
</form>
Here is the ajax request I made
<script>
const photoForm = document.querySelector('#photo_form');
console.log(photoForm.values);
photoForm.addEventListener('submit', (event) => {
event.preventDefault();
const photoFormData = new FormData(photoForm);
photoFormData.forEach((value, key) => {
console.log(key + ': ' + value);
});
fetch("{% url 'add_photo' %}", {
method: 'POST',
body: photoFormData,
contentType: false,
processData: false,
})
.then((response) => response.json())
.then((data) => {
console.log(data);
if (data.result == 'success') {
$('.modal-body').html('Form submission was successful!');
$('#modal-dialog').modal('show');
photoForm.reset();
} else {
$('.modal-body').html('There was an error with the form submission.');
$('#modal-dialog').modal('show');
}
});
});
</script>
Below, is the model I Made
class Photos(models.Model):
photo_title = models.CharField(max_length=50, blank=False)
photo_description = models.CharField(max_length=50, blank=False)
photo_date = models.DateField(blank=False)
photo_location = models.CharField(max_length=50, blank=False)
photo_file = models.ImageField(upload_to='photos', blank=False)
def __str__(self):
return self.photo_title
Below, is the view function
""" ajax add photo event to home wall """
def add_photo(request):
if request.method == 'POST':
response_data = {}
photoForm = UploadPhotosForm(request.POST)
print(photoForm.is_valid())
print(photoForm.errors)
if photoForm.is_valid():
photoForm.save()
response_data['result'] = 'success'
print(response_data)
return HttpResponse(
JsonResponse(response_data),
)
else:
response_data['result'] = 'error'
print(photoForm.errors)
return HttpResponse(
JsonResponse(response_data),
)
While I tried to figure out the problem, I got these outputs
from client side
csrfmiddlewaretoken: xDJ7qlvfOgaPta6VXkIH03QlT1AybEQ46xcC2ri09MO4F7DbBPGbeNehMrJa3Rjy
(index):141 photo_title: sadfsf
(index):141 photo_description: sfsfse
(index):141 photo_date: 2022-12-22
(index):141 photo_location: adsafd
(index):141 photo_file: [object File]
(index):144
POST http://127.0.0.1:8000/manager/add/photo/ 500 (Internal Server Error)
(anonymous) # (index):144
VM750:1
Uncaught (in promise) SyntaxError: Unexpected token '<', "<!DOCTYPE "... is not valid JSON
Promise.then (async)
(anonymous) # (index):149
from server side
False
<ul class="errorlist"><li>photo_file<ul class="errorlist"><li>This field is required.</li></ul></li></ul>
<ul class="errorlist"><li>photo_file<ul class="errorlist"><li>This field is required.</li></ul></li></ul>
[21/Dec/2022 15:09:10] "POST /manager/add/photo/ HTTP/1.1" 200 19
can someone help me out to figure out the problem?
In your post method, change to:
photoForm = UploadPhotosForm(request.POST,request.FILES)
I am trying to make an application with Django Rest Framework and template without using any front-end application. I created the login form and user list by following this documentation https://www.django-rest-framework.org/topics/html-and-forms/. It works fine when submitting forms and showing list with templates. But when I am trying to authenticate login with simplejwt from the browser, the authentication fails. Failed Authentication
Then I looked around and found this documentation https://ilovedjango.com/django/rest-api-framework/authentication/tips/working-example-of-jwt-authentication-with-ajax-django-rest-framework/ .
I can use the ajax post call to get the token and set it to local storage on submit and set the header of another API later from the local storage, but in that case, it is not going to the action="{% url 'user:user-list-list' %}" of the form in the template after submit. So it stays on the login page and hits only the token/ URL for the token. When I add
location.href = "{% url 'user:user-list-list' %}" in the ajax success, it loads the user_list but says 401 unauthorized.
Here is my user_login.html template:
{% load rest_framework %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
</head>
<body>
<h1>User Login</h1>
<form action="{% url 'user:user-list-list' %}" method="POST" id="login">
{% csrf_token %}
<div class="form-group ">
<label>Username</label>
<input id="username" name="username" class="form-control" type="text" placeholder="Enter Username" value="">
</div>
<div class="form-group ">
<label>Password</label>
<input id="password" name="password" class="form-control" type="password" placeholder="Enter Password" value="">
</div>
<input type="submit" value="Login" id="submit">
</form>
</body>
<script>
$("#login").submit(function (event) {
event.preventDefault();
let formData = new FormData();
formData.append('username', $('#username').val().trim());
formData.append('password', $('#password').val().trim());
$.ajax({
url: "http://127.0.0.1:8008/token/",
type: "POST",
data: formData,
cache: false,
processData: false,
contentType: false,
success: function (data) {
// store tokens in localStorage
window.localStorage.setItem('refreshToken', data['refresh']);
window.localStorage.setItem('accessToken', data['access']);
},
error: function (rs, e) {
console.error(rs.status);
console.error(rs.responseText);
}
}); // end ajax
});
</script>
</html>
Here is my login in views.py:
# ////////////////////////////////////////////////////
# #DESC USER LOGIN
# #ROUTE POST api/login/
# #ACCESS Public
# ////////////////////////////////////////////////////
class UserLoginView(viewsets.ModelViewSet):
renderer_classes = [TemplateHTMLRenderer]
template_name = 'user_login.html'
permission_classes = (AllowAny,)
serializer_class = UserLoginSerializer
def create(self, request, *args, **kwargs):
username = request.data['username']
password = request.data['password']
try:
user = User.objects.get(username=username)
serializer = self.serializer_class(data=request.data)
serializer.is_valid(raise_exception=True)
response = {}
if user.is_active == 1 or user.is_active == True:
response = {
'success': 'True',
'statuscode': status.HTTP_200_OK,
'status': 'Active',
'message': 'User login successful',
'token': serializer.data['token'],
'error': ''
}
elif user.is_active == 2:
response = {
'success': 'True',
'statuscode': status.HTTP_400_BAD_REQUEST,
'status': 'Blocked',
'message': 'User has been blocked',
'error': ''
}
elif user.is_active == 3:
response = {
'success': 'True',
'statuscode': status.HTTP_400_BAD_REQUEST,
'status': 'Unverified',
'message': 'Please verify your email to login!',
'error': ''
}
mylog.info(request.data)
Log.objects.create(
user_id=user.id,
date_time=datetime.now(),
login_date=datetime.now(),
component='LoginUser',
ip=request.META.get('REMOTE_ADDR')
# ip=request.META.get('HTTP_X_REAL_IP')
)
status_code = status.HTTP_200_OK
return Response(response, status=status_code)
except Exception as e:
print(e)
response = {
'success': False,
'statuscode': status.HTTP_400_BAD_REQUEST,
'message': 'Invalid username or password',
'error': str(e)
}
return Response(response)
def list(self, request):
try:
serializer = UserLoginFormSerializer()
return Response({'serializer': serializer.data})
except Exception as e:
print(e)
response = {
'success': False,
'error': str(e)
}
return Response(response)
Here is my user list in views.py:
# /////////////////////////////////////////////////////////////////////////////
# #DESC USER LIST, USER GET, USER UPDATE
# #ROUTE GET api/userlist/, GET api/userlist/pk/, PUT api/userlist/pk/
# #ACCESS Authenticated User
# /////////////////////////////////////////////////////////////////////////////
class UserListView(viewsets.ModelViewSet):
renderer_classes = [TemplateHTMLRenderer]
template_name = 'user_list.html'
permission_classes = [IsAuthenticated]
serializer_class = UserSerializer
def list(self, request, *args, **kwargs):
users = User.objects.all()
serializer = UserSerializer(users, many=True)
try:
response = {
'success': True,
'statuscode': status.HTTP_200_OK,
'data': serializer.data,
'message': "View users Successful"
}
return Response({'response': response})
except Exception as e:
print(e)
response = {
'success': False,
'statuscode': status.HTTP_400_BAD_REQUEST,
'message': 'User list fetch error',
'menu': 0,
'error': str(e)
}
mylog.error(e)
return Response(response)
I understand that I need to somehow get the token in the header of the user list API for the authentication to work, but I can't seem to find a way. Is this anyhow possible?
According to the documentation, I added this code in the script of user_list.html, but didn't work as the API is not authenticated for the user.
$(document).ready(function () {
$.ajax({
url: '{% url 'user:user-list-list' %}',
headers: {
'Authorization': `Bearer ${window.localStorage.getItem('accessToken')}`
},
type: "GET",
tokenFlag: true,
success: function (data) {
console.log(data);
},
error: handleAjaxError
});
});
function handleAjaxError(rs, e) {
/*
And if it returns 401, then we call obtainAccessTokenWithRefreshToken() method
To get a new access token using refresh token.
*/
if (rs.status == 401) {
if (this.tokenFlag) {
this.tokenFlag = false;
if (obtainAccessTokenWithRefreshToken()) {
this.headers["Authorization"] = `Bearer ${window.localStorage.getItem('accessToken')}`
$.ajax(this); // calling API endpoint again with new access token
}
}
} else {
console.error(rs.responseText);
}
}
function obtainAccessTokenWithRefreshToken() {
/*
This method will create new access token by using refresh token.
If refresh token is invalid it will redirect user to login page
*/
let flag = true;
let formData = new FormData();
formData.append('refresh', window.localStorage.getItem('refreshToken'));
$.ajax({
url: 'http://127.0.0.1:8008/token/refresh/',
type: "POST",
data: formData,
async: false,
cache: false,
processData: false,
contentType: false,
success: function (data) {
window.localStorage.setItem('accessToken', data['access']);
},
error: function (rs, e) {
if (rs.status == 401) {
flag = false;
window.location.href = "/user/login/";
} else {
console.error(rs.responseText);
}
}
}); // end ajax
return flag
}
How can I authenticate the user and render all other Rest APIs with authenticated users in this approach?
The problem that you have is you are mixing sessionStorage and localStorage.
In login.html jQuery code, you are using localStorage to store a accessToke and refreshToken
// store tokens in localStorage
localStorage.setItem('refreshToken', data['refresh']);
localStorage.setItem('accessToken', data['access']);
And in the list_users.html, you are trying to access the token with
sessionStorage
Change this code which is return accessToken null
headers: {
'Authorization': `Bearer
${window.sessionStorage.getItem('accessToken')}` // accessToken is null
},
To be this
headers: {
'Authorization': `Bearer
${localStorage.getItem('accessToken')}`
},
Now you have access to the accessToken stored in localStorage.
I am trying to delete some elements in database when user clicks on delete icon but as i am sending id through POST request , i am getting empty dictionary ,
{% for skills in seeker_skills %}
<div class="col-md-4">
<button class="btn btn-info mx-2">{{skills.skill_name}}<span class="badge badge-dark ">{{skills.skill_level}}</span></button><span><i class="fas fa-trash-alt delete_skill" data-attr={{skills.id}} style="cursor: pointer;"></i></span>
</div>
{% endfor %}
updated snippet , i am calling it on click
Ajax code
let delete_class_list = $('.delete_skill')
delete_class_list.click(function(e){
let value = this.getAttribute("data-attr")
let contain_icon = this
let contain_label = contain_icon.parentElement.previousSibling
console.log(contain_label)
$.ajax({
url:'/delete_skill/',
method : 'POST',
data: {
skill_id:value
},
dataType: "json",
contentType: "application/json",
success :function(data){
console.log(data)
contain_label.remove()
contain_icon.remove()
}
,
error:function(e){
console.log(e)
}
})
})
My view
#csrf_exempt
def delete_skill(request):
if request.method == 'POST':
data = {}
print('method is post')
job_id = request.POST.get('skill_id')
print(job_id)
try:
Job_Skillset.objects.get(id=job_id).delete()
data['status'] = 'deleted'
except ObjectDoesNotExist:
data['status'] = 'nodata'
return JsonResponse(data,safe=False)
You're setting your content type to application/json which is incorrect, remove it.
$.ajax({
url:'/delete_skill/',
method : 'POST',
data: {
skill_id:value
},
dataType: "json",
success :function(data){
console.log(data)
contain_label.remove()
contain_icon.remove()
}
,
error:function(e){
console.log(e)
}
})
I am building a website and I want to implement searching. I want the user to enter some text and want to show suggestions using ajax. when the user click on specific product or category I want to redirect the user to related page. Here is what I have done so far:
$(function () {
$("#search").autocomplete({
source: "{% url 'ajax-search' %}",
select: function (event, ui) { //item selected
AutoCompleteSelectHandler(event, ui)
},
minLength: 5,
});
});
<div class="search">
<label for="search"></label>
<input type="text" oninput="" style="height: 36px" class="searchTerm" placeholder="What are you looking for?" name="searchtext" id="search">
<button type="submit" class="searchButton">
<i class="fa fa-search"></i>
</button>
</div>
path('ajax/search', views.autocompleteModel, name='ajax-search'),
def autocompleteModel(request):
if request.is_ajax():
q = request.GET.get('term', '')
lookups = Q(name__icontains=q) | Q(category__name__icontains=q)
products = Product.objects.filter(lookups).distinct()
results = []
for product in products:
place_json = {}
place_json = product.name
product_url = 'prodcuts/product/' + str(product.id)
results.append(place_json)
data = json.dumps(results)
else:
data = 'fail'
mimetype = 'application/json'
return HttpResponse(data, mimetype)
In your javascript section you have to do something like this:
$(function () {
$("#search").autocomplete({
source: "{% url 'ajax-search' %}",
select: function (event, ui) {
window.location.href = ui.item.value;
},
minLength: 5,
});
});
And Python code part should look like this:
results = []
for product in products:
item = dict(
label = product.name,
value = '/products/product/' + str(product.id)
)
results.append(item)
data = json.dumps(results)
Consider a textarea input to enter emails.
The view has a forloop: for each email the view tries to create a user. Then, if the user is created, I append it to my array "newUers", if the user already exists, I append it to the "alreadyUsers" array.
When the loop ends, I want to render a view with these arrays. But it does not work...
The users are correctly created but the view does not render the template.
Any idea?
invitations.html: a textarea with an an ajax call on submit
<div id="invitations">
<label>Enter your clients email</label>
<textarea v-model="invitations" class="textarea" id="invitations" name="invitations"></textarea>
</div>
<div>
<input id="send" type="submit" value="Save" #click="submit()">
</div>
user_invitation.js: the ajax call (based on Vue)
var vue = new Vue({
el: '#invitations',
data: {
invitations: '',
},
methods: {
submit: function () {
var self = this;
$.ajax({
type: 'POST',
url: '/accounts/invitations/create/',
data: {
invitations: this.invitations,
csrfmiddlewaretoken: $('input[name=csrfmiddlewaretoken]').val(),
},
context: this,
success: function () {
console.log("ajax success");
},
error: function () {
console.log("ajax error");
}
})
}
}
});
views.py
def InvitationCreateView(request):
newUsers = []
alreadyUsers = []
for client in request.POST['invitations'].split('\n'):
try:
# Get informations for creating the User
user = User.objects.create(
username=client,
email=client,
)
user.groups.add(Group.objects.get(name='Clients'))
user.save()
newUsers.append(client)
# Check if user already exists
except IntegrityError:
alreadyUsers.append(client)
return render(request, 'accounts/agent_invitations_confirmation.html',
{"newUsers": newUsers, "alreadyUsers": alreadyUsers})