I can see the frontend form though, but if I try to submit the console would show: "Fetch API cannot load http://localhost:8000/api/task-create/ due to access control checks." and the next line is: "Failed to load resource: Cannot establish connection with the server."
This is what I see on my PC, (no problem with this every function works perfectly)
And this is what I get on a different PC connected to the same LAN
I think it has something to do with headers and CORS, Django REST Framework Authentication, I have tried it all but it doesn't seem to work.
Any hints?
This is my settings.py:
Django settings for todoapp project.
Generated by 'django-admin startproject' using Django 3.2.
For more information on this file, see
https://docs.djangoproject.com/en/3.2/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/3.2/ref/settings/
"""
from pathlib import Path
import os
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'django-insecure-whh5g$8**@u4t1m%13=c$6!k-5#o0jwhr&&7i7^d$ky%$ku+ls'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = ['*']
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework',
'corsheaders',
'api.apps.ApiConfig'
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'corsheaders.middleware.CorsMiddleware',
]
ROOT_URLCONF = 'todoapp.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [
os.path.join(BASE_DIR, 'frontend/build')
],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
WSGI_APPLICATION = 'todoapp.wsgi.application'
# Database
# https://docs.djangoproject.com/en/3.2/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
# Password validation
# https://docs.djangoproject.com/en/3.2/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
# Internationalization
# https://docs.djangoproject.com/en/3.2/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.2/howto/static-files/
STATIC_URL = '/static/'
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'frontend/build/static')
]
# Default primary key field type
# https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
CORS_ALLOWED_ORIGINS = [
"http://192.168.0.6:3000",
]
my views.py:
from django.shortcuts import render
from django.http import JsonResponse
from rest_framework.decorators import api_view
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from .serializers import TaskSerializer
from .models import Task
# Create your views here.
@api_view(['GET'])
def apiOverview(request):
api_urls = {
'List':'task-list/',
'Detail View':'/task-detail/<str:pk>',
'Create':'/task-create/',
'Update':'task-update/<str:pk>',
'Delete':'task-delete/<str:pk>',
}
return Response(api_urls)
@api_view(['GET'])
def taskList(request):
tasks = Task.objects.all()
serializer = TaskSerializer(tasks, many=True)
return Response(serializer.data)
@api_view(['GET'])
def taskDetail(request, id):
task = Task.objects.get(id=id)
serializer = TaskSerializer(task, many=False)
return Response(serializer.data)
@api_view(['POST'])
def taskCreate(request):
serializer = TaskSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
@api_view(['POST'])
def taskUpdate(request, id):
task = Task.objects.get(id=id)
serializer = TaskSerializer(instance=task, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
@api_view(['DELETE'])
def taskDelete(request, id):
task = Task.objects.get(id=id)
task.delete()
return Response('Task succesfully deleted!')
and my react main component App.js:
import React from "react"
import './App.css';
import TodoItem from "./TodoItem"
import Form from "./Form"
class App extends React.Component {
constructor(props){
super(props)
this.state = {
todoList:[],
activeItem:{
id:null,
title:'',
completed:false,
},
editing:false,
}
this.fetchTasks = this.fetchTasks.bind(this)
this.handleChange = this.handleChange.bind(this)
this.handleSubmit = this.handleSubmit.bind(this)
this.getCookie = this.getCookie.bind(this)
this.handleEdit = this.handleEdit.bind(this)
this.handleDelete = this.handleDelete.bind(this)
this.handleCompleted = this.handleCompleted.bind(this)
}
getCookie(name) {
let cookieValue = null;
if (document.cookie && document.cookie !== '') {
const cookies = document.cookie.split(';');
for (let i = 0; i < cookies.length; i++) {
const cookie = cookies[i].trim();
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
componentDidMount(){
this.fetchTasks()
}
fetchTasks(){
fetch('http://localhost:8000/api/task-list/')
.then(response => response.json())
.then(data =>
this.setState({
todoList: data
})
)
}
handleChange(event){
let value = event.target.value
this.setState({
activeItem: {
...this.state.activeItem,
title: value
}
})
}
handleSubmit(event){
event.preventDefault()
let csrftoken = this.getCookie('csrftoken')
let url='http://localhost:8000/api/task-create/'
if(this.state.editing === true){
url=`http://localhost:8000/api/task-update/${this.state.activeItem.id}/`
this.setState({
editing: false
})
}
fetch(url,{
method: 'POST',
headers:{
'Content-type':'application/json',
'X-CSRFToken': csrftoken,
},
body: JSON.stringify(this.state.activeItem)
}).then(()=>{
this.fetchTasks()
this.setState({
activeItem:{
id:null,
title:'',
completed:false,
}
})
}).catch((e)=>{
console.log('ERROR:',e)
})
}
handleEdit(todo){
this.setState({
activeItem: todo,
editing: true,
})
}
handleDelete(todo){
let csrftoken = this.getCookie('csrftoken')
let url = `http://localhost:8000/api/task-delete/${todo.id}/`
fetch(url, {
method: 'DELETE',
headers: {
'Content-type': 'application/json',
'X-CSRFToken': csrftoken
}
}).then((response)=>{
this.fetchTasks()
}).catch((error)=>{
console.log('ERROR:',error)
})
}
handleCompleted(todo){
let csrftoken = this.getCookie('csrftoken')
const url=`http://localhost:8000/api/task-update/${todo.id}/`
todo.completed= !todo.completed
fetch(url,{
method:'POST',
headers:{
'Content-type': 'application/json',
'X-CSRFToken': csrftoken
},
body: JSON.stringify({
title:todo.title,
completed:todo.completed,})
}).then(()=>{
this.fetchTasks()
}).catch((e)=>{
console.log('ERROR:',e)
})
}
render(){
let todoItems = this.state.todoList.map((todo, id)=>{
return(
<TodoItem
key={id} todo={todo}
onClick={()=> this.handleEdit(todo)}
onDelete={()=> this.handleDelete(todo)}
onCompleted={()=> this.handleCompleted(todo)}
/>
)
})
return(
<div className="container">
<div id="task-container">
<Form
onChange={this.handleChange}
onSubmit={this.handleSubmit}
data={this.state.activeItem}
/>
<div id="list-wrapper">
{todoItems}
</div>
</div>
</div>
)
}
}
export default App;
Thanks for the help in adavnce...