How to render template inside of template with angular and django - python

Question I want to be able to add a multiple Dimensions(Dimension Class) to my Sheet Class. What I would like to do is pass it into angular then back to Django if possible I just need help/guidance on how to do this I have looked a countless blogs and still can't come up with correct way of doing so any help would be greatly appreciated.
Here is my sheet model and dimension model (model.py)
class Sheet(models.Model):
drawing_number = models.CharField(max_length=255)
drawing_revision = models.CharField(max_length=255)
heat_number = models.CharField(max_length=255)
note = models.CharField(max_length=255)
valc = models.CharField(max_length=255)
class Dimension(models.Model):
description = models.CharField(max_length=255)
style = models.CharField(max_length=255)
target = models.IntegerField()
upper_limit = models.IntegerField()
lower_limit = models.IntegerField()
Here is my view.py with sheet_from_create method and my test method for adding a dim that isn't working.
def sheet_form_create(request):
if request.method == 'GET':
sheet_form = SheetForm()
else:
sheet_form = SheetForm(request.POST)
cust_int = Customer.objects.latest('id').id
cust_int_plus = int(cust_int) + 1
c_date = datetime.now()
u_date = datetime.now()
if sheet_form.is_valid():
drawing_number = sheet_form.cleaned_data['drawing_number']
drawing_revision = sheet_form.cleaned_data['drawing_revision']
heat_number = sheet_form.cleaned_data['heat_number']
note = sheet_form.cleaned_data['note']
valc = sheet_form.cleaned_data['valc']
try:
get_cust = Customer.objects.filter(customer_name=customer_name).exists()
except:
get_cust = False
if get_cust == True:
c = Customer.objects.get(customer_name=customer_name)
c_id = c.customer_id
else:
creat_cust = Customer.objects.create(id=cust_int_plus, customer_id=cust_int_plus, customer_name=customer_name)
c_minus = cust_int_plus
c = Customer.objects.get(id=c_minus)
c_id = c.customer_id
sheet = Sheet.objects.create(
drawing_number=drawing_number,
drawing_revision=drawing_revision,
heat_number=heat_number,
note=note,
valc=valc,
customer_id=c_id)
return render(request, 'app/sheet.html')
return render(request, 'app/sheet_form_create.html', {
'sheet_form': sheet_form,
'title':'New Sheet',
})
I tried this with ajax no luck It will not render my dim.html
def add_dimensions(request):
data = {}
if request.method == 'POST':
dim_form = DimForm(request.POST)
if dim_form.is_valid():
dim = Dimension()
description = dim_form.cleaned_data.get['description']
style = dim_form.cleaned_data.get['style']
target = dim_form.cleaned_data.get['target']
upper_limit = dim_form.cleaned_data.get['upper_limit']
lower_limit = dim_form.cleaned_data.get['lower_limit']
dim.save()
data['description'] = dim.description;
data['style'] = dim.style;
data['state'] = "ok";
return HttpResponse(json.dumps(data), mimetype="application/json")
else:
data = 'fail'
return render(request, 'app/sheet_form_create.html')
else:
dim_form = DimForm()
return render(request, 'app/dim.html', {'dim_form': dim_form})
Here is my sheet_form_create.html this is where I want my dim.html to render inside of as well
{% extends "app/layout.html" %}
{% load crispy_forms_tags %}
{% block content %}
<br />
<br />
<br />
<div class="row" >
{% crispy sheet_form %}
</div>
<body ng-app="dim_app">
<!-- render my dim.html here somehow -->
<div ng-controller="DimCtrl">
<div class="data">
</div>
<button ng-click="save()">Click</button>
</div>
</body>
{% endblock %}
Here is my dim.html
{% extends "app/layout.html" %}
{% load crispy_forms_tags %}
{% block content %}
<br />
<br />
<br />
<div class="row" >
{% crispy dim_form %}
</div>
{% endblock %}
Last but not least my angular code that I have so far for testing purposes here is where I am most confused
dim_app = angular.module('dim_app', []);
dim_app.controller('DimCtrl', ['$scope', function($scope) {
$scope.num = 0;
$scope.save = function () {
$(".data").html("click:" + $scope.num);
//some how load dim.html in here how ever many times its clicked example they click 5 times render dim.html five times and save each on as a child record of sheet
$scope.num += 1;
};
}]);
This is an example of what I would like it to look like

I figured it out.
Here is my angular code
dim_app = angular.module('dim_form', [])
.controller('dim_ctrl', ['$scope', '$compile', function ($scope, $compile) {
$scope.show_dim = function () {
var comp = $compile("<div </div>")($scope);
$("#id").append(comp);
};
}])
.directive('myDim', function () {
return {
templateUrl: '/sheet/sheet_form_create.html/_dim'
};
});
Here is my sheet_form_create.html
{% extends "app/layout.html" %}
{% load crispy_forms_tags %}
{% block content %}
<br />
<br />
<br />
<div class="row" >
{% crispy sheet_form %}
</div>
<body ng-app="dim_form">
<div ng-controller="dim_ctrl">
show
<div id="d"></div>
</div>
</body>
{% endblock %}

Related

Django display data from two different models

I have two seperated models. One with two text fields and one for multiple images. Now I want to display the entire data in one html div. What do I have to change in the projects view and in projects.html?
models.py
class Project(models.Model):
title = models.CharField(max_length=200)
describtion = models.TextField(null=True, blank=True)
class ProjectImage(models.Model):
project = models.ForeignKey(Project, on_delete=models.CASCADE)
image = models.FileField(upload_to="products/")
forms.py
class ProjectForm(forms.ModelForm):
class Meta:
model = Project
fields = ['title', 'describtion']
class ProjectImageForm(forms.ModelForm):
class Meta:
model = ProjectImage
fields = ['image']
widgets = {
'image': ClearableFileInput(attrs={'multiple': True}),
}
views.py
def createProject(request):
form = ProjectForm()
form2 = ProjectImageForm()
if request.method == 'POST':
form = ProjectForm(request.POST)
form2 = ProjectImageForm(request.POST, request.FILES)
images = request.FILES.getlist('image')
if form.is_valid() and form2.is_valid():
title = form.cleaned_data['title']
describ = form.cleaned_data['describtion']
project_instance = Project.objects.create(
title=title, describtion=describ)
for i in images:
ProjectImage.objects.create(project=project_instance, image=i)
context = {'form': form, 'form2': form2}
return render(request, 'projects/project_form.html', context)
def projects(request):
projects = Project.objects.all()
context = {"projects":projects}
return render(request, 'projects/projects.html', context)
projects.html
{% for project in projects %}
<div class="column">
<div class="card project">
<img class="project__thumbnail" src="{{project.image.url}}" alt="project thumbnail" />
<div class="card__body">
<h3>{{project.title}}</h3>
<h2>{{project.describtion}}</h2>
</div>
</a>
</div>
</div>
{% endfor %}
You don't need to change anything.
You should be able to access the reverse with project.project_image_set attribute in the template:
<div class="card__body"
<h3>{{project.title}}</h3>
<h2>{{project.describtion}}</h2>
{% for image in project.project_image_set.all %}
{{ image.image }}
{% endfor %}
</div>
Docs: https://docs.djangoproject.com/en/4.0/topics/db/examples/many_to_one/
I don't really understand the question here but i see a problem in your template considering you are using foreign key in ProjectImage. And update the question
{% for project in projects %}
<div class="column">
<div class="card project">
{% for j in project.projectimage_set.all %}
<img class="project__thumbnail" src="{{j.image.url}}" alt="project thumbnail" />
{% endfor %}
<div class="card__body">
<h3>{{project.title}}</h3>
<h2>{{project.describtion}}</h2>
</div>
</a>
</div>
</div>
{% endfor %}
I would change FileField to ImageField and add function:
#property
def get_photo_url(self):
if self.image and hasattr(self.image, 'url'):
return self.image.url
else:
return ''
If createProject function works( I would rename it to create_project) then in projects.html:
{% for project in projects %}
<div class="column">
<div class="card project">
<div class="card__body">
<h3>{{project.title}}</h3>
<h2>{{project.describtion}}</h2>
{% for img in project.projectimage_set.all %}
<img class="project__thumbnail" src="{{img.get_photo_url}}" alt="project thumbnail" />
{% endfor %}
</div>
</a>
</div>
</div>
{% endfor %}

checking which decimal is bigger django

Im having problem with one line of code... Im trying to check which decimal is greater, i checked few answers from stackoverflow and they didnt work (probably cuz they were from 7 years ago :P) anyways here is my view:
auction = all_auctions.objects.get(id= my_id)
comment_num = auction.comments.all().count()
all_comments = auction.comments.all()
context = {
"auction": auction,
"bid_auction": auction.bid.all(),
"comment_num": comment_num,
"all_comments": all_comments
}
if request.method == "POST" and "bid" in request.POST:
if request.user.is_authenticated:
highest_bid = request.POST["bid"]
if not Decimal(highest_bid) <= Decimal(int(auction.bid.all().reverse()[0])):
all_bid = bids.objects.create(bid = highest_bid)
auction.bid.add(all_bid)
if request.method == "POST" and "watch"in request.POST:
if request.user.is_authenticated:
if auction not in request.user.watchlist.all():
request.user.watchlist.add(auction)
else:
request.user.watchlist.remove(auction)
if request.method == "POST" and "comment" in request.POST:
comment = request.POST["comment"]
if request.user.is_authenticated:
comment_now = comments.objects.create(comment = comment)
auction.comments.add(comment_now)
return render(request, "auctions/dynamic_auction.html", context)
and there is the problematic line:
if not Decimal(highest_bid) <= Decimal(int(auction.bid.all().reverse()[0])):
in models:
from django.contrib.auth.models import AbstractUser
from django.db import models
class comments(models.Model):
comment = models.TextField(blank=False)
class bids(models.Model):
bid = models.DecimalField(decimal_places = 2, max_digits = 100000)
class all_auctions(models.Model):
category = models.CharField(max_length= 14, default = "none")
title = models.CharField(max_length= 14)
description = models.TextField(blank=False)
photo_url = models.CharField(max_length= 500000)
bid = models.ManyToManyField(bids, blank = True, related_name = "bid_auction")
comments = models.ManyToManyField(comments, blank = True, related_name = "comments")
class User(AbstractUser):
created = models.ManyToManyField(all_auctions, blank = True, related_name = "created")
watchlist = models.ManyToManyField(all_auctions, blank = True, related_name = "watchlist")
user_bid = models.ManyToManyField(bids, blank = True, related_name = "user_bid")
and in the template where i can place bids and view them:
{% extends "auctions/layout.html" %}
{% block body %}
<div>
<h2>{{auction.title}}</h2>
<div style = "width: 1400px; padding: 10px; margin: 10px;" class = auction_class>
<img src="{{auction.photo_url}}" alt="no image">
<div>
{{auction.description}}
<p></p>
{% for bid in bid_auction %}
{% if forloop.last %}
bid:{{bid.bid}}
{% endif %}
{% endfor %}
<p></p>
{{auction.category}}
<p></p>
{% if user.is_authenticated %}
<form method = "POST"> {% csrf_token %}
<input class="btn btn-primary" type="submit" name = "watch" value="Add to watchlist">
</form>
<form method = "POST"> {% csrf_token %}
<div>
<input style = "margin:10px;" class="form-control" name = "bid" type="text" placeholder= "Bid...">
<input class="btn btn-primary" type="submit" value="Place Bid">
</div>
</form>
<form method = "POST"> {% csrf_token %}
<div>
<input style = "margin:10px;" class="form-control" name = "comment" type="text" placeholder= "Comment...">
</div>
</form>
{% endif %}
<p></p>
comments:
<p></p>
{% if comment_num == 0 %}
no comments
{% endif %}
<p></p>
<p></p>
{% for com in all_comments %}
{{ com.comment }}
<p></p>
{% endfor %}
</div>
</div>
</div>
{% endblock %}
and yes i made it so the last object of the bids queryset is shown, i have no idea how to show the biggest one, so also i would appreciate help with that . thanks :D
I guess this:
if not Decimal(highest_bid) <= Decimal(int(auction.bid.all().reverse()[0].bid)):
should work (note .bid in the end).
And why you can't use [-1]?
Although I haven't worked with django alot but since you want to compare decimals you could technically create a class which inherits the class Decimal() and then return a float and compare that float. Although I think this won't work (I haven't tried it because I don't like django in particular) but this could be a possibility.
EDIT:
Use a function to return a float from the class.
Example Code:
class DecimalNumber(Decimal):
def __init__(self, value, par2...):
self.value = value
...
def return_float(self):
float = self.value
return float

When i want to add a product to my cart i have a keyerror

When i click add to cart i have the following error in views.py:
"In updateItem, productId = data['productId'] KeyError: 'productId' "
views.py line 70 where i have my error:
def updateItem(request):
data = json.loads(request.body)
productId = data['productId']
action = data['action']
print('Action:', action)
print('productId:', 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.quantity +1)
elif action == 'remove':
orderItem.quantity = (orderItem.quantity -1)
orderItem.save()
if orderItem.quantity <=0:
orderItem.delete()
return JsonResponse('El item fue agregado', safe=False)
carrito.js:
function updateUserOrder(productId, action){
console.log('Usuario logeado y enviando 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) =>{
console.log('data:', data)
location.reload()
})
}
My template carrito.html:
When i click on the button Add to cart i have the issue.
{% extends 'tienda/index.html' %}
{% load static %}
{% block content %}
</div>
{% for item in items %}
<div class="cart-row">
<div style="flex:2"><img class="row-image" src="{{item.product.imageURL}}"></div>
<div style="flex:2"><p>{{item.product.name}}</p></div>
<div style="flex:1"><p>{{item.product.price|floatformat:2}}</p></div>
<div style="flex:1">
<p class="quantity">{{item.quantity}}</p>
<div class="quantity">
<img data-product={{item.product.id}} data-action="add" class="chg-quantity update-cart" src="{% static 'images/arrow-up.png' %}">
<img data-product={{item.product.id}} data-action="remove" class="chg-quantity update-cart" src="{% static 'images/arrow-down.png' %}">
</div>
</div>
<div style="flex:1"><p>${{item.get_total}}</p></div>
</div>
{% endfor %}
</div>
</div>
</div>
{% endblock %}
The above block of code is where i have the buttons with the actions.
The json.loads() function accepts only unicode strings.
So first try to decode the request body with request.body.decode('utf-8') and next to load it with json.loads().
decoded_data = request.body.decode('utf-8')
data = json.loads(decoded_data)
There you can read the docs about json.loads

Displaying comments for questions only when they exist

I need to display messages on a Django template. Each message can have 0 to many comments. I need to display the comments for each message. However, if a message has no comments, then it is 'None' and I can't iterate over it. The problem is occurring in Django templates.
#models.py
class User(models.Model):
firstName = models.CharField(max_length = 255)
lastName = models.CharField(max_length = 255)
email = models.CharField(max_length = 255)
birthDate = models.DateField()
password = models.CharField(max_length = 255)
createdAt = models.DateTimeField(auto_now_add = True)
updatedAt = models.DateTimeField(auto_now = True)
objects = UserManager()
class Message(models.Model):
content = models.TextField()
user = models.ForeignKey(User, related_name = "messages")
createdAt = models.DateTimeField(auto_now_add = True)
updatedAt = models.DateTimeField(auto_now = True)
objects = UserManager()
class Comment(models.Model):
content = models.TextField()
message = models.ForeignKey(Message, related_name = "comments", default = [])
createdAt = models.DateTimeField(auto_now_add = True)
updatedAt = models.DateTimeField(auto_now = True)
objects = UserManager()
#views.py
#Main wall page
#Renders wall.html
def wall(request):
wallDict = {
"message" : Message.objects.all()
}
return render(request, "loginRegApp/wall.html", wallDict)
#wall.html
<!DOCTYPE html>
<html lang="en">
<head>
<title></title>
<meta charset="utf-8">
</head>
<body>
<div class="container">
Log out
<form action="message/create" method="post">
{% csrf_token %}
<h4>Post a message</h4>
<textarea name="message"></textarea>
<input type="submit" value="Post a message">
</form>
{% for message in messages %}
<div>
<h6>{{message.user.firstName}} {{message.user.lastName}} - {{message.createdAt}}</h6>
<p>{{message.content}}</p>
{% if message.comments %}
{% for comment in message.comments %}
<h6>Comment: {{message.user.firstName}} {{message.user.lastName}} - {{comment.createdAt}}</h6>
<p>{{comment.content</p>
{% endfor %}
{% endif %}
<form action="comment/{{message.id}}/create" method="post">
{% csrf_token %}
<textarea name="comment"></textarea>
<input type="submit" value="Post a comment">
</form>
</div>
{% endfor %}
</div>
</body>
</html>
I am trying to get all comments to display, whether 0 or 100.
You should use .all in your template to have access to the QuerySet that contains the comments. There is no need to use {% if ... %} and {% endif %}:
{% for comment in message.comments.all %}
<h6>Comment: {{message.user.firstName}} {{message.user.lastName}} - {{comment.createdAt}}</h6>
<p>{{comment.content</p>
{% endfor %}
In your view, you might want to use .prefetch_related(..) [Django-doc] here to avoid making an extra query per message to fetch the related comments, like:
def wall(request):
wallDict = {
'message' : Message.objects.prefetch_related(
'comments', 'comments__user'
).all()
}
return render(request, 'loginRegApp/wall.html', wallDict)

How to make infinite threaded comments

My current code allows me to render a queryset of Comments (parent comments) as well as replies to those comments. But i'm unable to render replies to those replies. My goal is to have an infinite reply system. Here's my code:
class Comment(models.Model):
user = models.ForeignKey(User, blank=True, null=True)
destination = models.CharField(default='1', max_length=12, blank=True)
parent_id = models.IntegerField(default=0)
parent_comment = models.ForeignKey('self', related_name='replies', related_query_name='replies', blank=True, null=True)
comment_text = models.TextField(max_length=350, blank=True, null=True)
timestamp = models.DateTimeField(default=timezone.now, blank=True)
children = models.IntegerField(default=0)
def __str__(self):
return str(self.comment_text)
my parent comment view:
def user_comment(request):
if request.is_ajax():
comment = CommentForm(request.POST or None)
ajax_comment = request.POST.get('text')
id = request.POST.get('id')
comment_length = len(str(ajax_comment))
if comment.is_valid() and request.user.is_authenticated:
comment = Comment.objects.create(comment_text=ajax_comment, destination=id, user=request.user)
username = str(request.user)
return JsonResponse({'text': ajax_comment, 'text_length': comment_length,
'username': username, 'id': comment.id})
else:
return HttpResponse()
and my reply view:
def comment_reply(request):
if request.is_ajax():
comment = CommentForm(request.POST or None)
reply_text = request.POST.get('reply_text')
id = request.POST.get('id')
parent_id = request.POST.get('parent_id')
parent = Comment.objects.get(id=parent_id)
parent.children += 1
parent.save()
if comment.is_valid() and request.user.is_authenticated:
comment = Comment.objects.create(comment_text=reply_text, destination=id, user=request.user, parent_id=parent_id, parent_comment=parent)
username = str(request.user)
return JsonResponse({'reply_text': reply_text, 'username': username})
else:
return HttpResponse()
ajax calls
var str = window.location.href.split('?')[0];
var path = str.split("/")[4];
$('.comment_form').on('submit', function(e) {
e.preventDefault();
var c = $(this).find('.comment_text').val()
console.log('this:', c);
$.ajax({
type: 'POST',
url: '/user_comment/',
data: {
text: $(this).find('.comment_text').val(),
id: path,
csrfmiddlewaretoken: $("input[name='csrfmiddlewaretoken']").val(),
},
success: function(data) {
if(data.text == '') {
console.log('Cannot submit blank comment');
} else {
//console.log('')
$('.commentsContainer hr').prepend("<div class='comment_div'><div class='left_comment_div'>" +
"<div class='username_and_votes'><h3><a class='username_foreign'>" + data.username +
"</a></h3></div><br><p>" + data.text +
"</p></div></div>");
}}
});
});
// reply comment
$(document).on('submit', '.reply_comment_form', function(e) {
e.preventDefault();
parent_id = $('.reply_comment_form').data('comment_id');
$.ajax({
type: 'POST',
url: '/comment_reply/',
data: {
reply_text: $(this).find('.comment_text').val(),
parent_id: parent_id,
id: path,
csrfmiddlewaretoken: $("input[name='csrfmiddlewaretoken']").val(),
},
success: function(data) {
$('.reply_comment_form').replaceWith("<div class='comment_div new_comment' style='display: inline-block;'><div class='left_comment_div'>" +
"<div class='username_and_votes'><h3><a href='#' class='username_foreign'>" + data.username +
"</a></h3><br><p>" + data.reply_text +
"</p></div></div>");
}
});
});
and the comments html
<div class="commentsContainer">
<form action="" class="comment_form">{% csrf_token %}
{{ comment.comment_text|add_class:"comment_text" }}
{{ comment.id }}
<input type="submit" value="Comment" class="comment_submit">
</form>
<hr>
{% for i in comment_list %}
<div class='comment_div' data-comment_id="{{ i.id }}">
<div class="left_comment_div">
<div class="username_and_votes">
<h3><a class='username_foreign'>{{ i.user }}</a></h3>
</div>
<br>
<p>{{ i.comment_text }}</p>
</div>
</div>
{% for reply in i.replies.all %}
<div class='comment_div new_comment' data-comment_id="{{ reply.id }}">
<div class="left_comment_div">
<div class="username_and_votes">
<h3><a class='username_foreign'>{{ reply.user }}</a></h3>
</div>
<br>
<p>{{ reply.comment_text }}</p>
</div>
</div>
{% endfor %}
{% endfor %}
</div>
If someone could give me advice how to implement endless replies from the code I currently have that would be great.
You need to turn your comments loop into a separate template
{% for i in comments %}
<div class='comment_div' data-comment_id="{{ i.id }}">
<div class="left_comment_div">
<div class="username_and_votes">
<h3><a class='username_foreign'>{{ i.user }}</a></h3>
</div>
<br>
<p>{{ i.comment_text }}</p>
</div>
</div>
{% include 'comments_template.html' with comments=i.replies.all %}
{% endfor %}
Then you just call this where you need it with
{% include 'comments_template.html' with comments=comment_list %}

Categories