I'm working on an assignment to use the fetch API to do some of the normal things we would have Python do in our views with JavaScript such as adding records or querying the database. One issue I'm running across is passing the normal properties we would see in Django, say a user or username, where it just shows up as a literal user id when I pull it from the sql database with the fetch API. With the views, html and JavaScript I have written now, how would I go about pulling the username with fetch in JavaScript that I can normally grab with a variable or view with a print statement in the Django console, instead of just viewing the user id from the database. I feel like I'm missing a step and I'm just not seeing it.
urls
app_name = "network"
urlpatterns = [
path("", views.index, name="index"),
path("login", views.login_view, name="login"),
path("logout", views.logout_view, name="logout"),
path("register", views.register, name="register"),
# API Routes
path("addpost", views.post, name="post"),
path("<str:navbar_item>", views.viewposts, name="viewposts"),
]
models.py
class User(AbstractUser):
pass
class Profile(models.Model):
user = models.OneToOneField(User, null=True, on_delete=models.CASCADE)
bio = models.TextField(null=True, blank=True)
# pics
website = models.CharField(max_length=225, null=True, blank=True)
follower = models.ManyToManyField(
User, blank=True, related_name="followed_user") # user following this profile
# profile user that follows this profile
following = models.ManyToManyField(
User, blank=True, related_name="following_user")
def __str__(self):
return f"{self.user}'s' profile id is {self.id}"
def following_users(self):
for username in self.following:
return username
def get_absolute_url(self):
return reverse("network:profile-detail", args=[str(self.id)])
class Post(models.Model):
created_by = models.ForeignKey(User, on_delete=models.CASCADE, related_name="post_user")
body = models.TextField(max_length=1000)
timestamp = models.DateTimeField(auto_now_add=True)
likes = models.ManyToManyField(User, blank=True, related_name="post_likes")
def __str__(self):
return f"{self.created_by} posted {self.body}"
def get_absolute_url(self):
return reverse("network:post-detail", args=[str(self.id)])
def total_likes(self):
return self.likes.count()
class Meta:
ordering = ["-timestamp"]
views.py
def index(request):
if request.user.is_authenticated:
return render(request, "network/index.html", {})
else:
return HttpResponseRedirect(reverse("network:login"))
#login_required
def post(request):
# Composing a new post must be done via POST
if request.method != "POST":
return JsonResponse({"error": "You must POST your request."}, status=404)
try:
data = json.loads(request.body)
body = data.get("body", "")
user = request.user
print(user)
post = Post(created_by=user, body=body)
# post = Post(created_by=Profile.objects.get(user=user), body=body)
post.save()
except AttributeError:
return JsonResponse({"error": "AttributeError thrown."}, status=500)
return JsonResponse({"message": "Post created."}, status=201)
#login_required
def viewposts(request, navbar_item):
if navbar_item == "viewposts":
posts = Post.objects.all()
posts = posts.order_by("-timestamp")
json_post = serialize("json", posts)
print(posts)
return HttpResponse(json_post, content_type="application/json")
else:
return JsonResponse({"error": "Invalid page."}, status=400)
index.html
{% extends "network/layout.html" %}
{% load static %}
{% block body %}
<div class="container p-5">
{% if error %}
{{ error }}
{% endif %}
<h1 class="display-4">All Posts</h1>
<div class="form-group border rounded p-4">
<h2 class="diplay-3">New Post</h2>
<form id="addpost" class="form-group pt-5">
{% csrf_token %}
<div class="form-group">
<textarea class="form-control" id="body" placeholder="Add post here..."></textarea>
</div>
<input type="submit" class="btn btn-primary"/>
</form>
</div>
<div id="all-posts" class="all-posts">
</div>
</div>
{% endblock %}
{% block script %}
<script src="{% static 'network/main.js' %}"></script>
{% endblock %}
JavaScript
// Post on index page # API Routes /addpost
const addPost = () => {
const addPostUrl = '/addpost';
const csrftoken = getCookie('csrftoken');
const body = document.querySelector('#body').value;
// body needs to be passed into an object before using the stringify method
const bodyObject = { body };
fetch(addPostUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrftoken,
},
body: JSON.stringify(bodyObject)
})
.then(response => response.json())
.then(result => {
console.log(result);
})
.catch(error => {
console.log(error);
});
return false;
};
// Load posts in index page # API Routes /navbar_item
function loadPosts(navItem, event) {
preventPageLoad(event);
const postUrl = `/${navItem}`;
// Send a GET request to the URL to retrieve all posts
fetch(postUrl)
.then(response => response.json())
.then(data => {
data.forEach(post => {
const { fields } = post;
const allPostsContainer = document.querySelector("#all-posts");
const element = document.createElement('div');
const postId = `#post-${fields.id}`;
element.style.textDecoration = 'none';
element.classList.add('HoverClass1');
element.setAttribute('id', `post-${fields.id}`);
element.classList.add('d-flex', 'flex-column' ,'justify-content-between', 'p-4', 'm-3', 'lead', 'border', 'rounded');
element.style.color = '#000000';
element.innerHTML =
// This is returning an id
`<div class="bd-highlight font-weight-bolder mr-5">${fields.created_by}</div>
<div class="bd-highlight">${fields.timestamp}</div>
<div class="flex-fill bd-highlight">${fields.body}</div>`;
console.log(fields);
allPostsContainer.append(element);
const linePost = document.querySelector(postId);
linePost.addEventListener('click', (event) => {
console.log(event);
});
});
})
.catch(error => {
console.log(error);
});
return false;
}
Images showing my admin console in Django versus the browser console and what fetch is pulling in JavaScript. You'll see in the admin console we can view the username, but in the browser console all I'm getting is the user id with fetch.
I figured out how to do this. I added a serialize method to the Post model to convert these properties to JSON.
def serialize(self):
return {
'id': self.id,
'created_by': self.created_by.username,
'body': self.body,
'timestamp': self.timestamp.strftime('%b %-d %Y, %-I:%M %p'),
'likes': self.total_likes()
}
Then in views.py, in my viewposts function, instead of my the HttpResponse, I used JsonResponse and passed the model's serialize method as an argument.
#login_required
def viewposts(request, navbar_item):
if navbar_item == "viewposts":
posts = Post.objects.all()
posts = posts.order_by("-timestamp")
return JsonResponse([post.serialize() for post in posts], safe=False)
else:
return JsonResponse({"error": "Invalid page."}, status=400)
This allowed me to not have to deconstruct anything in my JavaScript file. So I could pull any attributes from my query using dot notation directly off of the data model in fetch.
Related
I want to display countries and states in Django form, for that I am trying to get data from json, create form, pass json data to form and get state of the country on ajax request. I managed to write the process as far as I learned, but at last form is not rendered on Django template. How can I render Django form with following code structure?
My Model:
from django.db import models
class Address(models.Model):
country = models.CharField(null=True, blank=True, max_length=100)
state = models.CharField(null=True, blank=True, max_length=100)
def __str__(self):
return '{} {}'.format(self.country, self.state)
My Forms.py:
import json
def readJson(filename):
with open(filename, mode="r", encoding="utf-8") as fp:
return json.load(fp)
def get_country():
""" GET COUNTRY SELECTION """
filepath = './static/data/countries_states_cities.json'
all_data = readJson(filepath)
all_countries = [('-----', '---Select a Country---')]
for x in all_data:
y = (x['name'], x['name'])
all_countries.append(y)
return all_countries
def return_state_by_country(country):
""" GET STATE SELECTION BY COUNTRY INPUT """
filepath = './static/data/countries_states_cities.json'
all_data = readJson(filepath)
all_states = []
for x in all_data:
if x['name'] == country:
if 'states' in x:
for state in x['states']:
y = (state['name'], state['name'])
all_states.append(state['name'])
else:
all_states.append(country)
return all_states
class AddressForm(forms.ModelForm):
country = forms.ChoiceField(
choices = get_country(),
required = False,
label='Country / Region*',
widget=forms.Select(attrs={'class': 'form-control', 'id': 'id_country'}),
)
class Meta:
model = Address
fields = ['country']
My Form.html
<form class="" action="" method="post">
{% csrf_token %}
{% for error in errors %}
<div class="alert alert-danger mb-4" role="alert">
<strong>{{ error }}</strong>
</div>
{% endfor %}
<div class="row">
<div class="col-lg-6">
<div class="mb-4">
{{ form.country}}
</div>
</div>
<div class="col-lg-6">
<div class="mb-4">
<div class="form-group">
<label >Select a Province/State</label>
<select id="id_province" class="form-control" name="state">
<option value="-----">Select Province/State</option>
</select>
</div>
</div>
</div>
</div>
</form>
My Views:
def readJson(filename):
with open(filename, mode="r", encoding="utf-8") as fp:
return json.load(fp)
def return_state_by_country(country):
""" GET STATE SELECTION BY COUNTRY INPUT """
filepath = './static/data/countries_states_cities.json'
all_data = readJson(filepath)
all_states = []
for x in all_data:
if x['name'] == country:
if 'states' in x:
for state in x['states']:
y = (state['name'], state['name'])
all_states.append(state['name'])
else:
all_states.append(country)
return all_states
def getProvince(request):
country = request.POST.get('country')
provinces = return_state_by_country(country)
return JsonResponse({'provinces': provinces})
def processForm(request):
context = {}
if request.method == 'GET':
form = AddressForm()
context['form'] = form
return render(request, './ecommerce/checkout.html', context)
if request.method == 'POST':
form = AddressForm(request.POST)
if form.is_valid():
selected_province = request.POST['state']
obj = form.save(commit=False)
obj.state = selected_province
obj.save()
return render(request, './ecommerce/checkout.html', context)
My Ajax:
<script>
$("#id_country").change(function () {
var countryId = $(this).val();
$.ajax({
type: "POST",
url: "{% url 'ecommerce:get-province' %}",
data: {
'csrfmiddlewaretoken': '{{ csrf_token }}',
'country': country
},
success: function (data) {
console.log(data.provinces);
let html_data = '<option value="-----">Select Province/State</option>';
data.provinces.forEach(function (data) {
html_data += `<option value="${data}">${data}</option>`
});
$("#id_province").html(html_data);
}
});
});
</script>
I am trying to print form.country on template but its not working. What could be the problem?
With ModelForms I find that this type of configuration, in which everything falls under class Meta: works.
However im dubious about that get_country() method. If you share it I can take a deeper look and maybe even test it to make sure that it's not doing anything funky.
If your list of countries is somewhat static and not too long you might wanna consider using a TextChoices enum type in your model attribute to limit the choice selection. Django forms will automatically render a dropdown widget listing the items from your enum.
You can checkout this answer if you want to look into that, which further links to the django docs.
class AddressForm(forms.ModelForm):
class Meta:
model = Address
fields = ['country']
widgets = {
"country": forms.ChoiceField(
choices = get_country(),
attrs={
"class": "form-control",
"id": "id_country"
}
),
}
labels = {
"country" : "Company Country Location"
}
I’m a beginner. I have tried everything in the Django E-commerce website course, but it does not work for me. I also tried documentation but I didn’t get any solution. I have this error when I go to /update_item/ and the data is not showing up in the terminal:
Expecting value: line 1 column 1 (char 0)
error screenshot
tutorial link
tutorial link
https://youtu.be/woORrr3QNh8
cart.js
var updateBtns = document.getElementsByClassName('update-cart')
for (i = 0; i < updateBtns.length; i++) {
updateBtns[i].addEventListener('click', function(){
var productId = this.dataset.product
var action = this.dataset.action
console.log('productId:', productId, 'Action:', action)
console.log('USER:', user)
})
}
function updateUserOrder(productId, action){
console.log('User is authenticated, sending data...')
var url = '/update_item/'
fetch(url, {
method:'POST',
headers:{
'Content-Type':'application/json',
'X-CSRFToken':csrftoken,
},
body:JSON.stringify({'productId':productId, 'action':action})
})
.then((response) => {
return response.json();
})
.then((data) => {
location.reload()
});
}
views.py
def updateItem(request):
data = json.loads(request.body)
productId = data['productId']
action = data['action']
print("Action",action)
print("Pordutcs:",productId)
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.quantitiy +1)
elif action == 'remove':
orderitem.quantity = (orderitem.quantity -1)
orderitem.save()
if orderitem.quantity <= 0:
orderitem.delete()
return JsonResponse("Item was added", safe=False)
store.html
{% extends 'store/main.html' %}
{% load static %}
{% block content %}
<div class="row">
{%for i in products %}
<!-- {{i.image.url}} -->
<div class="col-lg-4">
<!-- <img class="thumbnail" src="{{i.image.url}}" alt="sorry"> -->
<img class="thumbnail" src="static{{i.imageURL}}">
<!-- {% static 'my_app/example.jpg' %} -->
<div class="box-element product">
<h6><strong>{{i.name}}</strong></h6>
<hr>
<button data-product="{{i.id}}" data-action='add' class="btn btn-outline-secondary add-btn updatecart">Add
to Cart</button>
<a class="btn btn-outline-success" href="#">View</a>
<h4 style="display: inline-block; float:right"><strong>Rs {{i.price|floatformat:2}}</strong></h4>
</div>
</div>
{% endfor %}
<!-- <img src="static/images/robot.jpg"> -->
</div>
{% endblock content %}
I tried making a dummy django project with the code you provided to see if I counter such error.
Following JS code I used:
function updateUserOrder(){
console.log('User is authenticated, sending data...')
var url = '/update_item/'
fetch(url, {
method:'POST',
headers:{
'Content-Type':'application/json',
},
body:JSON.stringify({'productId':5, 'action':'Add'})
})
.then((response) => {
return response.json();
})
.then((data) => {
location.reload()
});
}
I gave dummy data to productId and action.
Then my views.py goes like this:
from django.shortcuts import render
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
#csrf_exempt
def updateItem(request):
data = json.loads(request.body)
productId = data['productId']
action = data['action']
print("Action",action)
print("Pordutcs:",productId)
return JsonResponse("Item was added", safe=False)
Not much with html part, it was just a click button to call the js code.
<button onclick="updateUserOrder()">Add</button>
And worked like a charm, following is the screenshot of my output in django server:
I would suggest you to try running with the same code.
If error is still there, try giving dummy data to productId and action in js code to make sure if there is a problem with the data in productId and action.
I assume you've solved this issue otherwise,...
if you're using Django version 4.0
change the url for the cart.js to update_item, cart.js should look like this
cart.js:
var updateBtns = document.getElementsByClassName('update-cart')
for (i = 0; i < updateBtns.length; i++) {
updateBtns[i].addEventListener('click', function(){
var productId = this.dataset.product
var action = this.dataset.action
console.log('productId:', productId, 'Action:', action)
console.log('USER:', user)
})
}
function updateUserOrder(productId, action){
console.log('User is authenticated, sending data...')
var url = 'update_item/'
fetch(url, {
method:'POST',
headers:{
'Content-Type':'application/json',
'X-CSRFToken':csrftoken,
},
body:JSON.stringify({'productId':productId, 'action':action})
})
.then((response) => {
return response.json();
})
.then((data) => {
location.reload()
});
}
then import csrf_exempt decorator , your views should look like this
views.py(after adding "from django.views.decorators.csrf import csrf_exempt" to the top of your file)
#csrf_exempt
def updateItem(request):
data = json.loads(request.body)
productId = data['productId']
action = data['action']
print("Action",action)
print("Pordutcs:",productId)
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.quantitiy +1)
elif action == 'remove':
orderitem.quantity = (orderitem.quantity -1)
orderitem.save()
if orderitem.quantity <= 0:
orderitem.delete()
return JsonResponse("Item was added", safe=False)
Then Clear Your Cache and try adding the item to cart again...it should work this time
I am new to Django and Javascript. I would like to create an edit section on a site, where people can edit a post that already exists. Similar to Facebook or Twitter.
When I click 'edit' on my post, in the console I am getting:
network.js:28 POST http://127.0.0.1:8000/edit_post/ 404 (Not Found)
I've tried many things but cannot get it to work. Any help is appreciated.
I think the issue might have to do with the use of 'post' and 'text.'
'text' is in my model, used to signify the text of the actual post.
views.py:
#login_required
#csrf_exempt
def edit_post(request):
if request.method == "POST":
post_id = request.POST.get('id')
new_post = request.POST.get('text')
try:
post = Post.objects.get(id=post_id)
if post.user == request.user:
post.text = new_post.strip()
post.save()
return JsonResponse({}, status=201)
except:
return JsonResponse({}, status=404)
return JsonResponse({}, status=400)
models.py
class User(AbstractUser):
pass
class Post(models.Model):
text = models.TextField(max_length=500, blank=True,
null=True)
username = models.ForeignKey('User',
on_delete=models.CASCADE, related_name='author',
null=True, blank=True)
timestamp = models.DateTimeField(auto_now_add=True)
like = models.ManyToManyField(
User, blank=True, related_name="liked_user")
def __str__(self):
return self.user.username
Javascript file:
edit = document.querySelectorAll(".edit");
text_area = document.querySelectorAll(".textarea");
edit.forEach((element) => {
element.addEventListener("click", () => {
edit_handeler(element);
});
});
text_area.forEach((element) => {
element.addEventListener("keyup", (e) => {
if (e.keyCode == 13 && e.shiftKey) return;
if (e.keyCode === 13) edit_handeler(element);
});
});
function edit_post(id, post) {
form = new FormData();
form.append("id", id);
form.append("text", text.trim());
fetch("/edit_post/", {
method: "POST",
body: form,
}).then((res) => {
document.querySelector(`#post-content-${id}`).textContent = post;
document.querySelector(`#post-content-${id}`).style.display =
"block";
document.querySelector(`#post-edit-${id}`).style.display = "none";
document.querySelector(`#post-edit-${id}`).value = text.trim();
});
}
function edit_handeler(element) {
id = element.getAttribute("data-id");
edit_btn = document.querySelector(`#edit-btn-${id}`);
if (edit_btn.textContent == "Edit") {
document.querySelector(`#post-content-${id}`).style.display =
"none";
document.querySelector(`#post-edit-${id}`).style.display =
"block";
edit_btn.textContent = "Save";
edit_btn.setAttribute("class", "text-success edit");
} else if (edit_btn.textContent == "Save") {
edit_post(id, document.querySelector(`#post-edit-${id}`).value);
edit_btn.textContent = "Edit";
edit_btn.setAttribute("class", "text-primary edit");
}
}
Part of html file:
{% if user1 == user2 %}
<span class="text-primary edit" data-id="{{i.id}}"
id="edit-btn-{{i.id}}">Edit</span>
<br><br>
{% endif %}
<span id="post-content-{{i.id}}" class="post"
{{i.post}}</span>
<textarea data-id="{{i.id}}" id="post-edit-{{i.id}}"
style="display:none;" class="form-control textarea" row="3">{{i.text}}</textarea>
urls.py
urlpatterns = [
path("", views.index, name="index"),
path("make_post", views.make_post, name="make_post"),
path("fol/<str:user>", views.fol, name="fol"),
path("following_list/<str:username>", views.following_list,
name='following_list'),
path('like/', views.like),
path('edit_post/', views.edit_post),
path("profile/<str:username>", views.profile, name="profile"),
path("login", views.login_view, name="login"),
path("logout", views.logout_view, name="logout"),
path("register", views.register, name="register"),
]
I have been working on a like system using django and ajax, this like system is very similar to instagram's one. After finishing with the code I started to get a Post matching query does not exist error which has been a pain. I dont see the wrong in my code but I think the problem is on the views.py file because the traceback is triggering a line there. How can i fix this error?
models.py
class Post(models.Model):
text = models.CharField(max_length=200)
user = models.ForeignKey(User, on_delete=models.CASCADE, default='username')
liked = models.ManyToManyField(User, default=None, blank=True, related_name='liked')
def __str__(self):
return str(self.id)
views.py (upload view uploades the form, home displays the uploaded form, like_post is the view in charged of liking and unliking posts and home_serialized os the one that contains the json so that the page doesnt reload when the like button is clicked)
def upload(request):
print("toro")
if request.method == 'POST':
print("caballo")
form = PostForm(request.POST)
if form.is_valid():
instance = form.save(commit=False)
instance.user = request.user
instance.save()
return redirect('home')
print('succesfully uploded')
else:
form = PostForm()
print('didnt upload')
return render(request, 'home.html', {'form': form})
def home(request):
contents = Post.objects.all()
args = {
'contents': contents,
}
return render(request, 'home.html', args)
def like_post(request):
user = request.user
if request.method == 'POST':
pk = request.POST.get('post_pk')
post_obj = Post.objects.get(pk=pk)
if user in post_obj.liked.all():
post_obj.liked.remove(user)
else:
post_obj.liked.add(user)
return HttpResponse()
def home_serialized(request):
data = list(Post.objects.values())
return JsonResponse(data, safe=False)
urls.py
urlpatterns = [
path('', views.home, name='home'),
path('upload', views.upload, name='upload'),
path('like/', views.like_post, name='like-post'),
path('serialized/', views.home_serialized, name='serialized-view'),
]
home.html
<form method='post' action="{% url 'upload' %}">
{% csrf_token %}
<input type="text" name="text" placeholder="Add a comment..." required="" id="id_text">
<button class="submit-button" type="submit">Save</button>
</form>
{% for content in contents %}
{% if content %}
<ul class="list-group">
<li class="list-group-item">{{ content.text }}</li>
<form action="{% url 'like-post' %}" class='like-form' method="POST" id={{content.id}}>
{% csrf_token %}
<input type='hidden' name="post_ok" value="{{ content.ok }}">
<button class='like-btn{{ content.id }}'>
{% if request.user in content.liked.all %}
Unlike
{% else %}
Like
{% endif %}
</button>
</form>
<strong>{{ content.liked.all.count }}</strong>
</ul>
{% endif %}
{% endfor %}
<script type='text/javascript'>
$(document).ready(function(){
$('.like-form').submit(function(e){
e.preventDefault()
console.log('works')
const post_id = $(this).attr('id')
console.log(this)
console.log(post_id)
const likeText = $(`.like-btn${post_id}`).text()
console.log(likeText)
const trim = $.trim(likeText)
console.log(trim)
const url = $('.like-form').attr('action')
console.log(url)
$.ajax({
type: 'POST',
url: url,
data : {
'csrfmiddlewaretoken': $('input[name=csrfmiddlewaretoken]').val(),
'post_pk': post_id,
},
success: function(error){
console.log('success')
$.ajax({
type: 'GET',
url: 'http://127.0.0.1:8000/serialized/',
success: function(response){
console.log(response)
$.each(response, function(index, element){
console.log(index)
console.log(element.content)
if (post_id == element.id) {
if(trim == 'Like') {
console.log('unlike')
$(`.like-btn${post_id}`).html('Unlike')
} else if (trim == 'Unlike') {
console.log('like')
$(`.like-btn${post_id}`).html('Like')
} else {
console.log('ups')
}
}
})
},
error: function(error){
console.log('error')
}
})
},
error: function(error){
console.log('error', error)
}
})
})
});
</script>
traceback
Traceback (most recent call last):
File "C:\Users\MaríaPaola\AppData\Local\Programs\Python\Python38-32\lib\site-packages\django\core\handlers\exception.py", line 34, in inner
response = get_response(request)
File "C:\Users\MaríaPaola\AppData\Local\Programs\Python\Python38-32\lib\site-packages\django\core\handlers\base.py", line 115, in _get_response
response = self.process_exception_by_middleware(e, request)
File "C:\Users\MaríaPaola\AppData\Local\Programs\Python\Python38-32\lib\site-packages\django\core\handlers\base.py", line 113, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "C:\Users\MaríaPaola\projects\nwpc\like\views.py", line 65, in like_post
post_obj = Post.objects.get(pk=pk).exists()
File "C:\Users\MaríaPaola\AppData\Local\Programs\Python\Python38-32\lib\site-packages\django\db\models\manager.py", line 82, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "C:\Users\MaríaPaola\AppData\Local\Programs\Python\Python38-32\lib\site-packages\django\db\models\query.py", line 415, in get
raise self.model.DoesNotExist(
like.models.Post.DoesNotExist: Post matching query does not exist.
I'm not sure what it says in the traceback. If you could provide that, maybe it'll make more sense. But I assume it's because of the like post_obj = Post.objects.get(pk=pk) in
def like_post(request) function.
Post with the given primary key does not exist. What you can do is to check if the pk exists.
if Post.objects.filter(pk=pk).exists():
# it exist
or you can do a try except method
try:
post_obj = Post.objects.get(pk=pk)
if user in post_obj.liked.all():
post_obj.liked.remove(user)
else:
post_obj.liked.add(user)
except:
# what happens if post does not exist
i am struggling with getting my User ID after i log in. The token is and already stored in localstorage
working on Django as backend and Vue.js as frontend
so a user is able to login and out but I can't seem to find the userId of the logged in user
in able to retrieve more data linked to the user.
Therefore i cannot post an product properly related to a user. besides that, if i manage to post and check via console on chrome, it says my category section null/empty
Whenever I try to link my category foreignfield in the product model
i keep getting this error below
{category: ["Invalid hyperlink - No URL match."]}
category: ["Invalid hyperlink - No URL match."]
0: "Invalid hyperlink - No URL match.
Thanks in advance
my model.py
from django.db import models
from django.contrib.auth.models import User
# class User(models.Model):
# id_user = models.DecimalField(max_digits=10, decimal_places=2, null=True)
# def __str__(self):
# return self.id_user
class Category(models.Model):
name = models.CharField(max_length = 200, null = True,)
def __str__(self):
return self.name
class State(models.Model):
STATE_CHOICES = [('Ordered', 'Ordered'), ('Pending', 'Pending'),
('Placed', 'Placed'), ('Reserved', 'Reserved')
]
state = models.CharField(max_length = 200, null = True,
choices = STATE_CHOICES)
def __str__(self):
return self.state
class Product(models.Model):
user = models.ForeignKey(User,null=True, on_delete=models.SET_NULL)
state = models.ForeignKey(State, null=True, on_delete=models.SET_NULL)
category = models.ForeignKey(Category, null=True, on_delete=models.SET_NULL)
title = models.CharField(max_length=200)
description = models.TextField(max_length=800, null=True)
price = models.DecimalField(max_digits=10, decimal_places=2, null=True)
#image = models.ImageField(upload_to='post_image', blank=True, width_field=None, height_field=None, max_length=100,)
date_created = models.DateTimeField(auto_now_add=True, null=True)
class Meta:
unique_together = (('user','title'),)
index_together = (('user','title'),)
# CATEGORY_CHOICES = (
# ('Books', 'Books'),
# ('eBooks','eBooks'),
# ('Writing material','Writing material'),
# )
# category = models.CharField(max_length=200, null=True, choices=CATEGORY_CHOICES)
SCHOOL_CHOICES = (
('Erasmushogeschool | EHB',(
('Campus Kaai', 'Campus Kaai'),
('Campus Bloemberg', 'Campus Bloemberg'),
)),
('Vrije Universiteit Brussel | VUB',(
('Campus Jette', 'Campus Jette'),
('Campus Schaarbeek', 'Campus Schaarbeek'),
)),
('Katholieke universiteit leuven | KUL',(
('KUL Gent', 'KUL Gent'),
('Campus Antwerpen', 'Campus Antwerpen'),
)),
)
school = models.CharField(max_length=50, choices=SCHOOL_CHOICES, null=True)
MAJOR_CHOICES = (
('IT','IT'),
('Marketing','Marketing'),
('DIFF','DIFF'),
)
major = models.CharField(max_length=200,choices=MAJOR_CHOICES, null=True)
SUBJECT_CHOICES = [
('Mathematics','Mathematics'),
('Algoritmes','Algoritmes'),
('Analyses','Analyses'),
]
subject = models.CharField(max_length=200,choices=SUBJECT_CHOICES, null=True)
CONDITION_CHOICES = [
('New','New'),
('Used','Used'),
]
condition = models.CharField(max_length=200,choices=CONDITION_CHOICES, null=True)
LOCATION_CHOICES = [
('Brussel','Brussel'),
('Leuven','Leuven'),
('Gent','Gent'),
('Antwerpen','Antwerpen'),
]
location = models.CharField(max_length=200,choices=LOCATION_CHOICES, null=True)
def __str__(self):
return self.title
serializer.py
from rest_framework import serializers
from .models import Product, State, Category
from django.contrib.auth.models import User
from rest_framework.authtoken.models import Token
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('id', 'username', 'password')
extra_kwargs = {'password':{'write_only':True,'required':True}}
def create(self, validated_data):
user = User.objects.create_user(**validated_data)
print(user)
Token.objects.create(user=user)
return user
class ProductSerializer(serializers.HyperlinkedModelSerializer):
category_name = serializers.CharField(source='category.name', read_only=True)
class Meta:
model = Product
fields = '__all__'
class CategorySerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Category
fields = ('id', 'url', 'name')
class StateSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = State
fields = '__all__'
urls.py
from django.contrib.auth.models import User
from rest_framework import routers, serializers, viewsets
from django.urls import path
from restapi.views import ProductViewSet, StateViewSet, UserViewSet, CategoryViewSet
# class UserSerializer(serializers.HyperlinkedModelSerializer):
# class Meta:
# model = User
# fields = ['id', 'url', 'username', 'email', 'is_staff']
# # ViewSets define the view behavior.
# class UserViewSet(viewsets.ModelViewSet):
# queryset = User.objects.all()
# serializer_class = UserSerializer
# Routers provide an easy way of automatically determining the URL conf.
router = routers.DefaultRouter()
router.register('users', UserViewSet)
router.register('product', ProductViewSet)
router.register('category', CategoryViewSet)
router.register('state', StateViewSet)
urlpatterns = [
path('', include(router.urls)),
path('api-auth/', include('rest_framework.urls', namespace='rest_framework')),
]
views.py
from django.shortcuts import render
from rest_framework import viewsets, status
from .models import Product, State, Category
from django.contrib.auth.models import User
from .serializer import ProductSerializer, UserSerializer, StateSerializer, CategorySerializer
from rest_framework.permissions import IsAuthenticated,AllowAny
from rest_framework.authentication import TokenAuthentication
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework.filters import SearchFilter, OrderingFilter
from rest_framework.response import Response
from rest_framework.authtoken.views import ObtainAuthToken
from rest_framework.authtoken.models import Token
class ProductViewSet(viewsets.ModelViewSet):
queryset = Product.objects.all()
serializer_class = ProductSerializer
authentication_classes = (TokenAuthentication,)
permission_calsses = (IsAuthenticated,)
filter_backends = (DjangoFilterBackend, SearchFilter, OrderingFilter)
search_fields = ('title', 'price', 'category__name')
# def delete(self,request,*args,**kwargs):
# response = {'message':'product cannot be updated like this'}
# return Response(response, status = statu.HTTP_400_BAD_REQUEST)
# def create(self,request,*args,**kwargs):
# response = {'message':'product cannot be created like this'}
# return Response(response, status = status.HTTP_400_BAD_REQUEST)
class CategoryViewSet(viewsets.ModelViewSet):
queryset = Category.objects.all()
serializer_class = CategorySerializer
permission_calsses = (IsAuthenticated,)
filter_backends = (DjangoFilterBackend, SearchFilter, OrderingFilter)
search_fields = ('name', 'id')
class StateViewSet(viewsets.ModelViewSet):
queryset = State.objects.all()
serializer_class = StateSerializer
permission_calsses = (IsAuthenticated,)
class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
authentication_classes = (TokenAuthentication,)
permission_classes = (AllowAny, )
# class CustomObtainAuthToken(ObtainAuthToken):
# def post(self, request, args, *kwargs):
# response = super(CustomObtainAuthToken, self).post(request, args, *kwargs)
# token = Token.objects.get(key=response.data['token'])
# return Response({'token': token.key, 'id': token.user_id})
my front end Vue.js login
<template>
<div class="login-form">
<b-form #submit.prevent="login" v-if="token==null">
<div class="sign-in-htm">
<div class="group">
<label for="user" class="label">Username</label>
<input id="user" type="text" class="input" required v-model="username">
</div>
<div class="group">
<label for="pass" class="label">Password</label>
<input
id="pass"
type="password"
class="input"
data-type="password"
v-model="password"
required>
</div>
some more code...
</template>
<script>
export default {
name: "login",
data() {
return {
username: '',
user_id : 0,
password: '',
repeat: '',
submitted: false,
token: null,
log_status: ''
}
},
methods: {
login() {
axios
.post("http://127.0.0.1:8000/auth/", {
username: this.username,
password: this.password
})
.then(res => {
this.token = res.data.token;
this.log_status = "Log out";
this.$root.$emit("logAndToken", this.log_status, this.token);
console.log(
"Login data:",
res,
this.username,
this.password,
this.token
);
localStorage.setItem("logAndToken", this.token);
localStorage.setItem("user_id", this.user_id);
});
this.$router.push({ name: "homepage" }).catch(err => {
localStorage.removeItem("logAndToken");
localStorage.removeItem("user_id");
console.log("error loginn", err);
});
},
register() {
console.log(this.username);
axios
.post("http://127.0.0.1:8000/auth/", {
username: this.username,
password: this.password
})
.then(res => console.log(res))
.catch(err => console.log(err));
this.submitted = true;
this.$validate()
.then(function(success) {
if (success) {
alert('Validation succeeded!');
}
});
this.$router.push({ name: "useradmin" });
},
submit: function () {
this.submitted = true;
this.$validate()
.then(function(success) {
if (success) {
alert('Validation succeeded!');
}
});
}
</script>
my navbar at the top | in this component i check whether i have an token or not with the v-for
<template>
<li class="nav-item dash">
<a class="nav-link pr-2 h5 font-weight-bold" type="button" #click.prevent="$router.push({ name: 'useradmin' }).catch(err => {})" v-if="this.token!=null">Dasboard</a>
</li>
<li class="nav-item">
<a class="nav-link pr-2 h5" type="button" #click.prevent="$router.push({ name: 'sdf' }).catch(err => {})" v-if="this.token!=null" v-on:click="logout()" >{{this.log_status}}</a>
</li>
<li class="nav-item">
<a class="nav-link pr-2 h5" type="button" #click.prevent="$router.push({ name: 'sdf' }).catch(err => {})" v-if="this.token==null">{{this.log_status}}</a>
</li>
// more code
</template>
<script>
var url_category = 'http://127.0.0.1:8000/category/'
export default {
name: "Menu",
components: {},
props: [],
data() {
return {
categories:[],
title: '',
token: null,
log_status: this.token?'log out':'log in',
};
},
mounted() {
this.$root.$on('logAndToken', (log_status, token) => {
this.token = token
this.log_status = log_status
console.log('message received from login + token' ,log_status, token);
})
},
methods: {
sendCategoryName(category_name){
this.$root.$emit('message', category_name)
},
logout(){
localStorage.removeItem('logAndToken');
this.token = null;
this.log_status = "Log in"
this.$root.$emit('logAndToken', this.log_status, this.token)
}
},
created() {
axios.get(url_category).then(res => (this.categories = res.data))
.catch(err => console.log("error", err));
/* To check if anything is coming trough, i console log the result:
.then(res => console.log(res))
My records were in the array 'results'
*/
// get the Records form the API use Vue detected tool extention via chrome.
}
};
</script>
You can fetch user_id from request object. request.user.id
If you want to store additional information, it's a good idea to utilize JWT tokens. When you send the token from the server you can encode additional information into the response payload.
For example your payload might look like this when its encoded.
{
token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"
}
When you decode it from your frontend app
{
"sub": "1234567890",
"name": "John Doe",
"iat": 1516239022
}
Take a look at https://jwt.io/
Right now, it seems like you don't encode any other additional information into your response.