0

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) What I see on my Laptop

And this is what I get on a different PC connected to the same LAN What I see on a different PC

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...

Emos Turi
  • 156
  • 1
  • 8

1 Answers1

0

You might having issue with the ip address. Like, this different computer might have an activated VPN or any other issue that points to other ip adress not a localhost.

So, in your django settings.py try to change this:

CORS_ALLOWED_ORIGINS = [
    "http://192.168.0.6:3000",
]

to this approach:

CORS_ORIGIN_WHITELIST = [
     'http://localhost:3000',
]

Or if you want to allow all:

CORS_ORIGIN_ALLOW_ALL = True # If you use this approach then `CORS_ORIGIN_WHITELIST` will not have any effect
CORS_ALLOW_CREDENTIALS = True

And check if it works.

Elias Prado
  • 1,518
  • 2
  • 17
  • 32