Helloo,
I am following a tutorial to allow User to select Light/Dark Mode using HTML, CSS, JS.
I have following documentation and tutorial but the issue is that the content of the page itself is not showing and I am not sure the reason.
So what I did is I created 2 css files dark and light, and create a mode application with the settings.
I am currently receiving an error:
django.contrib.auth.models.User.setting.RelatedObjectDoesNotExist: User has no setting.
To start here is the base.html
<link id="mystylesheet" href="{% static 'css/app-light.css' %}" type="text/css" rel="stylesheet">
<!-- Mode -->
<div id="mode" class="section" style="padding-top: 1rem; padding-bottom: 3rem;text-align: right">
<button onclick="swapStyle('css/app-light.css')" type="button" class="btn btn-secondary">Light Mode</button>
<button onclick="swapStyle('css/app-dark.css')" type="button" class="btn btn-dark">Dark Mode</button>
</div>
<!-- Mode -->
<script type="text/javascript">
function getCookie(name) {
var cookieValue = null;
if (document.cookie && document.cookie !== '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var 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;
}
var csrftoken = getCookie('csrftoken');
var cssFile = "{% static 'css' %}"
function swapStyles(sheet){
document.getElementById('mystylesheet').href = cssFile + '/' + sheet
localStorage.setItem('theme', sheet)
updateTheme(sheet)
}
function loadSettings(){
//Call data and set local storage
var url = "{% url 'mode:user_settings' %}"
fetch(url, {
method:'GET',
headers:{
'Content-type':'application/json'
}
})
.then((response) => response.json())
.then(function(data){
console.log('Data:', data)
var theme = data.value;
if (theme == 'light.css' || null){
swapStyles('light.css')
}else if(theme == 'dark.css'){
swapStyles('dark.css')
}
})
}
loadSettings()
function updateTheme(theme){
var url = "{% url 'mode:update_theme' %}"
fetch(url, {
method:'POST',
headers:{
'Content-type':'application/json',
'X-CSRFToken':csrftoken,
},
body:JSON.stringify({'theme':theme})
})
}
</script>
Here is the model.py
class Setting(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
name = models.CharField(max_length=200)
value = models.CharField(max_length=200)
def __str__(self):
return self.name
here is the views.py
def index(request):
return render(request, 'base.html')
def userSettings(request):
user, created = User.objects.get_or_create(id=1)
setting = user.setting
seralizer = UserSerailizer(setting, many=False)
return JsonResponse(seralizer.data, safe=False)
def updateTheme(request):
data = json.loads(request.body)
theme = data['theme']
user, created = User.objects.get_or_create(id=1)
user.setting.value = theme
user.setting.save()
print('Request:', theme)
return JsonResponse('Updated..', safe=False)
Here is the serializer.py
from .models import *
class UserSerailizer(serializers.ModelSerializer):
class Meta:
model = Setting
fields = '__all__'
Here is urls.py
app_name = 'mode'
urlpatterns = [
path('', views.index, name="index"),
path('user_settings/', views.userSettings, name="user_settings"),
path('update_theme/', views.updateTheme, name="update_theme"),
]
Here is the traceback
Traceback (most recent call last):
File "C:\Users\Ahmed\Desktop\Project\venv\lib\site-packages\django\core\handlers\exception.py", line 47, in inner
response = get_response(request)
File "C:\Users\Ahmed\Desktop\Project\venv\lib\site-packages\django\core\handlers\base.py", line 179, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "C:\Users\Ahmed\Desktop\Project\mode\views.py", line 17, in userSettings
setting = user.setting
File "C:\Users\Ahmed\Desktop\Project\venv\lib\site-packages\django\db\models\fields\related_descriptors.py", line 421, in __get__
raise self.RelatedObjectDoesNotExist(
django.contrib.auth.models.User.setting.RelatedObjectDoesNotExist: User has no setting.
You need to handle the case when a user will not have a setting in userSettings function.
def userSettings(request):
user, created = User.objects.get_or_create(id=1)
setting = getattr(user, 'setting', None)
if setting:
seralizer = UserSerailizer(setting, many=False)
return JsonResponse(seralizer.data, safe=False)
else:
return JsonResponse({'message': "User don't have a setting."}, safe=False)
And also make sure that updateTheme function works perfectly. If it doesn't work try following.
def updateTheme(request):
data = json.loads(request.body)
theme = data['theme']
user, created = User.objects.get_or_create(id=1)
setting = Setting.objects.get_or_create(user=user, value=theme, name='a name')
setting.save()
print('Request:', theme)
return JsonResponse('Updated..', safe=False)
Note that in the name field of Setting model you didn't pass null=True. So you have to pass name when creating a setting of a user.
Also in your base.html you are using onclick="swapStyle()" yet your javascript function is function swapStyles(){}. Change this
setting = getattr(user, 'setting', None)
Related
I saw a similar question but the answer is rather vague. I created a function based view for updateItem. I am trying to get json data to load based on my request. but am getting the error -> object has no attribute 'data'
Views.py file:
def updateItem(request):
data = json.loads(request.data)
productId = data['productId']
action = data['action']
print("productID", productId, "action", action)
customer = request.user.customer
product = Product.objects.get(id=productId)
order, created = Order.objects.get_or_create(customer=customer,complete=False)
orderItem, created = OrderItem.objects.get_or_create(order=order, product=product)
if action == 'add':
orderItem.quantity = (orderItem.quantity + 1)
elif action == 'remove':
orderItem.quantity = (orderItem.quantity - 1)
orderItem.save()
if orderItem.quantity <= 0:
orderItem.delete()
return JsonResponse("Item was added!", safe=False)
JS File:
function updateUserOrder(productId, action) {
console.log('User is logged in...');
let url = '/update_item/';
fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrftoken,
},
body: JSON.stringify({ productId: productId, action: action }),
})
.then((res) => {
return res.json();
})
.then((data) => {
console.log('data', data);
});
}
urls python file:
urlpatterns = [
path("",views.store,name="store"),
path("cart/",views.cart,name="cart"),
path("checkout/",views.checkout,name="checkout"),
path("update_item/",views.updateItem,name="update_item"),
]
The Error seems to also occur in my fetch function in the JS file. With my method POST. Can't find a solution, what am I doing wrong here?
The main problem is that you are trying to access 'request.data', there is no such attribute. What you want is to retrieve data from the POST request.
(Also, note that good practice is to have your views and variable names in snake_case form, whereas camelCase is used for classes):
def updateItem(request):
data = json.loads(request.POST.get('data'))
...
return JsonResponse("Item was added!", safe=False)
Although, to complete my answer, I must say that I had problems with your JS function, with the csrf token not being properly attached. My test solution:
views.py
from django.shortcuts import render
from django.http import JsonResponse
import json
def update_item(request):
return render(request, 'update_item.html', {})
def update_item_ajax(request):
data = json.loads(request.POST.get('data'))
print(data)
...
return JsonResponse({'message': '"Item was added!"'}, safe=False)
# output of update_item_ajax print
{'productId': 1, 'action': 'myaction'}
urls.py
from django.urls import path
from core import views
app_name = 'core'
urlpatterns = [
path('update/item/', views.update_item, name='update-item'),
path('update/item/ajax/', views.update_item_ajax, name='update-item-ajax'),
]
update_item.html
{% extends 'base.html' %}
{% block content %}
<button onclick="updateUserOrder(1, 'action')"> update item </button>
{% endblock %}
{% block script %}
<script>
function updateUserOrder(productId, action) {
console.log('User is logged in...');
let url = "{% url 'core:update-item-ajax' %}";
var payload = {
productId: productId,
action: action
};
var data = new FormData();
data.append( 'data' , JSON.stringify( payload ) );
data.append('csrfmiddlewaretoken', '{{ csrf_token }}');
fetch(url,
{
method: 'POST',
body: data,
})
.then(function(res){ return res.json(); })
.then(function(data){ console.log(data); });
}
</script>
{% endblock %}
Try:
data = json.loads(request.body)
Because the request doesn't have data, since you pass the data as body: JSON.stringify({ productId: productId, action: action }),
To create a post, the user must go through the form for creating posts and upload an image, but I don’t know how to do this.
I tried to send file event.target.files[0] but I received "POST /api/tests/ HTTP/1.1" 400 91
it didn't help, I tried to send event.target.files[0].name but that didn't help either.
TestForm.jsx:
import React, {useState} from 'react';
import axios from "axios";
function TestForm() {
const [testInputs, setTestInputs] = useState({title: '', title_image: '', test_type: ''});
console.log(testInputs);
axios.defaults.xsrfCookieName = 'csrftoken'
axios.defaults.xsrfHeaderName = "X-CSRFTOKEN"
const handleClick = () => {
axios({
method: 'POST',
url: 'http://127.0.0.1:8000/api/tests/',
data: {
author: 1,
title: 'sad',
title_image: testInputs.title_image.name,
test_type: 2,
question: [1, 3, 4],
result: [1, 2]
}
})
}
return (
<div>
<form>
<input onChange={(event) => {setTestInputs({...testInputs, title_image: event.target.files[0]}); console.log(event.target)}} type="file" placeholder='upload'/>
</form>
<button onClick={handleClick}>asd</button>
</div>
);
}
export default TestForm;
models.py
class Test(models.Model):
author = models.ForeignKey(User, on_delete=models.CASCADE)
title = models.CharField(max_length=150)
title_image = models.ImageField(default="images/IMG_1270.JPG/", null=True, blank=True, upload_to='titleImages/')
test_type = models.ForeignKey(TestType, on_delete=models.CASCADE)
question = models.ManyToManyField(TestQuestionBlok)
result = models.ManyToManyField(TestResult, blank=True)
def __str__(self):
return self.title
views.py
class TestList(APIView):
def post(self, request, format=None):
serializer1 = TestSerializers(data=request.data)
if serializer1.is_valid():
print(serializer1.data)
return Response(serializer1.data, status=status.HTTP_200_OK)
return Response(serializer1.errors, status=status.HTTP_400_BAD_REQUEST)
#Api
import axios;
const avatarupload = (data, uuid) => {
return axios.post(`endpoint/`, data).then(
(res) => res,
(error) => error.response
);
};
#Store
getAvatar = async (data, cb) => {
const uuid = LocalStorageService.getUuid();
const resp = await avatarupload(data, uuid);
if (resp.status === 200) {
this.setMessage('Successfully Updated');
this.setUser(resp.data);
cb();
} else {
cb(resp.data.error);
}
this.setPicLoading(false);
};
#web page
const handleFileChange = async (event) => {
const data = new FormData();
data.append('avatar', event.target.files[0]);
getAvatar(data, (error) => {
setError(error);
});
setFader(1);
};
<Form.Group controlId='formBasicText'>
<button
className='primary'
type='button'
onClick={handleChangeAvatarClick}
>
CHANGE AVATAR
</button>
<Form.Control
style={{ display: 'none' }}
type='file'
ref={hiddenFileInput}
onChange={handleFileChange}
accept='image/*'
/>
</Form.Group>
I've been trying to console.log the Json(response) from my View in my home.html template with no success. Here is my code:
Views.py
def Tweets_view(request, *arg, **kwargs):
qs = Tweets.objects.all()
for x in qs:
tweet_list = { 'id': x.id, 'content': x.content }
context = { 'response': tweet_list }
return JsonResponse(context)
urls.py
from django.contrib import admin
from django.urls import path
from tweets.views import Tweets_view_id, Tweets_view
urlpatterns = [
path('admin/', admin.site.urls),
path('tweets', Tweets_view), #N.B This is the URL I'm trying to access.
path('tweets/<int:tweet_id>', Tweets_view_id)
]
home.html
{% extends './base.html' %}
{% block content% }
<div id="tweets">
LOADING ...
</div>
<script>
const tweetsElement = document.getElementById("tweets")
const xhr = new XMLHttpRequest()
const method = "post"
const url = "/tweets"
const responseType = "json"
xhr.responseType = responseType
xhr.open(method, url)
xhr.onload = function () {
const serverResponse = xhr.response
var listedItems = serverResponse.response
console.log(listedItems)
}
xhr.send()
</script>
{% endblock content% }
my browser (Displays nothing in the console)
This is the link to the my browser display image. No data displays in my console.
Put a console.log to see if you enter your function xhr.onload right before const serverResponse.
And try changing your
const serverResponse = xhr.response
to
const serverResponse = this.response
(console.log both to see what happens).
source
I have been trying to upload multiple images at once but my API takes only one image among the list of images. What might be the reason for not taking all the images ? What have i done wrong?
Here's my code.
urls.py
url(r'^api/', RentalList.as_view()),
url(r'^api/upload/', FileUploadView.as_view()),
url(r'^api/(?P<pk>[0-9]+)/$', RentalDetail.as_view()),
Models.py
class Rental(models.Model):
email = models.CharField(max_length=120,blank=True, null=True)
phoneNumber = models.PositiveIntegerField(blank=False,null=True,
help_text=_("Phone number of contact person"))
listingName = models.CharField(_("Lisitng Name"), max_length=255, blank=False, null=True,
help_text=_("Title of the rental space"))
summary = models.TextField(max_length=500, blank=True, null= True,
help_text=_("Description of the rental space"))
property = models.CharField(_("Property type"),max_length=10,null=True)
price = models.PositiveIntegerField(blank=False,null=True,
help_text=_("Rental price of the space per month"))
city = models.CharField(_("City"), max_length=255, blank=False, null=True,
help_text=_("City of the rental space"))
place = models.CharField(_("Place"), max_length=255, blank=False, null=True,
help_text=_("Place of the rental space"))
phone_image = models.CharField(max_length=2048,blank=True,null=True,
help_text=_("image form of the phone number"))
image = models.FileField(upload_to='upload/',null=True,blank=True)
Views.py
class RentalList(generics.ListCreateAPIView):
serializer_class = RentalSerializer
queryset = Rental.objects.all()
def get(self,request,format=None):
rental = self.get_queryset()
serializer_rental = RentalSerializer(rental,many=True)
return Response(serializer_rental.data)
#permission_classes((IsAdminUser, ))
def post(self,request,format=None):
user=request.user
serializer_rental = RentalSerializer(data=request.data,context={'user':user})
if serializer_rental.is_valid():
serializer_rental.save()
return Response(serializer_rental.data,status=status.HTTP_201_CREATED)
return Response(serializer_rental.errors,status=status.HTTP_400_BAD_REQUEST)
class RentalDetail(generics.RetrieveUpdateDestroyAPIView):
queryset=Rental.objects.all()
serializer_class = RentalSerializer
class FileUploadView(APIView):
parser_classes = (MultiPartParser, FormParser, )
def post(self, request, format=None):
uploaded_file = request.FILES['image']
print('up_file is',uploaded_file)
filename = '/media/upload'
with open(filename, 'wb+') as destination:
for chunk in uploaded_file.chunks():
print('chunk',chunk)
destination.write(chunk)
destination.close()
my_saved_file = open(filename)
return Response(uploaded_file.name, status.HTTP_201_CREATED)
registration.jsx
var RenderPhotos = React.createClass({
getInitialState: function () {
return {
files:[]
};
},
onDrop(files) {
console.log('Received files: ', files);
this.setState({
files: files
});
},
showFiles() {
const files = this.state.files || null;
console.log('files',files);
if (!files.length) {
return null;
}
return (
<div>
<h3>Dropped files: </h3>
<ul className="gallery">
{
files.map((file, idx) => {
return (
<li className="col-md-3" key={idx}>
<img src={file.preview} width={100}/>
<div>{file.name}</div>
</li>
);
})
}
</ul>
</div>
);
},
render: function () {
return (
<div>
<h3>Photos can bring your space to life</h3>
<p>Add photos of spaces to give more insight of your space </p>
<hr/>
<div className="col-md-12">
<form method="post" encType="multipart/form-data">
<Dropzone onDrop={this.onDrop}
style={style}
activeStyle={activeStyle}>
Try dropping some files here, or click to select files to upload.
</Dropzone>
</form>
{this.showFiles()}
</div>
<div className="row continueBtn text-right">
<button className="btn how-it-works pull-left" onClick={this.props.previousStep}>Back</button>
<button className="btn how-it-works" onClick={this.submitRent}>Submit</button>
</div>
</div>
);
},
submitRent: function(e) {
// want to store the data so that when user reverts back to this form the data should be in same previous state
var req = request.post('http://localhost:8000/api/upload/');
var image = [];
image = new FormData();
var that = this;
var index;
for (index = 0; index < that.state.files.length; ++index) {
console.log(that.state.files[index]);
image.append('image',that.state.files[index]);
}
req.send(image);
console.log('req is',req);
req.end((err, res) => {
if (err) {
console.log('error', err);
} else {
console.log('success', res);
}
});
}
});
I have posted all the code thinking that it might be easy for tracing the errors.
Do i need to create ManyToMany field for image?
form.html
<form action='/login/' method = 'post'>
{% csrf_token %}
<label>Email: (*)</label><input type='text' name='email' value='' /><br />
<label>Password: </label><input type='password' name='password' value='' /><br />
<input type='submit' name='submit' value='Log in' />
</form>
and views.py i use HttpResponse not render_to_response
def login(request):
success = False
message = ''
try:
emp = Employee.objects.get(email = request.POST['email'])
if emp.password == md5.new(request.POST['password']).hexdigest() :
emp.token = md5.new(request.POST['email'] + str(datetime.now().microsecond)).hexdigest()
emp.save()
info = serializers.serialize('json', Employee.objects.filter(email = request.POST['email']))
success = True
return HttpResponse(json.dumps({'success':str(success).lower(), 'info':info}))
else:
message = 'Password wrong!'
return HttpResponse(json.dumps({'success':str(success).lower(), 'message':message}), status = 401)
except:
message = 'Email not found!'
return HttpResponse(json.dumps({'success':str(success).lower(), 'message':message}), status = 401)
if use render_to_response, i just add RequestContext but HttpResponse, i don't know what to do.
i use Django 1.4
Where's my problem
=========================
My problem is sloved when I change the function that render the HTML :
def homepage(request):
return render_to_response('index.html')
to
def homepage(request):
return render_to_response('index.html', context_instance=RequestContext(request))
That's a stupid mistake... thanks...
If you are using ajax to send the form and have included jQuery, you have two possibilities:
Manually add the csrfmiddlewaretoken data to your POST request
Automate CSRF token handling by modifying jQuery ajax request headers
1. Manually add csrfmiddlewaretoken
var data = {
csrfmiddlewaretoken: $('#myForm input[name=csrfmiddlewaretoken]').val(),
foo: 'bar',
};
$.ajax({
type: 'POST',
url: 'url/to/ajax/',
data: data,
dataType: 'json',
success: function(result, textStatus, jqXHR) {
// do something with result
},
});
2. Automate CSRF token handling
jQuery(document).ajaxSend(function(event, xhr, settings) {
function getCookie(name) {
var cookieValue = null;
if (document.cookie && document.cookie != '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = jQuery.trim(cookies[i]);
// 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;
}
function sameOrigin(url) {
// url could be relative or scheme relative or absolute
var host = document.location.host; // host + port
var protocol = document.location.protocol;
var sr_origin = '//' + host;
var origin = protocol + sr_origin;
// Allow absolute or scheme relative URLs to same origin
return (url == origin || url.slice(0, origin.length + 1) == origin + '/') ||
(url == sr_origin || url.slice(0, sr_origin.length + 1) == sr_origin + '/') ||
// or any other URL that isn't scheme relative or absolute i.e relative.
!(/^(\/\/|http:|https:).*/.test(url));
}
function safeMethod(method) {
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
if (!safeMethod(settings.type) && sameOrigin(settings.url)) {
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
}
});
But: It is said that modifying the ajax request headers is bad practice. Therefore i'd go with solution number one.
Source: Cross Site Request Forgery protection: AJAX
The Django Documentations (CSRF DOC LINK) clearly explains how to enable it.
This should be the basic way of writing view with csrf token enabled..
from django.views.decorators.csrf import csrf_protect
#csrf_protect
def form(request):
if request.method == 'GET':
#your code
context = {}
return render (request, "page.html", context )