I built a small Django Blog application with a comment section. Users are required to login before making a post or comment. I want to return the full name of my CustomUser in both the Blog posts and comments in my templates. After a Blog post, the full name returns as expected, but the author of the comment returns the value of the username field of my CustomUser model i.e None. Please help. Here is my code.
CustomUser model
from django.contrib.auth.models import AbstractUser
from django.db import models
from . manager import CustomUserManager
class CustomUser(AbstractUser):
email = models.EmailField(verbose_name = 'email address', unique=True)
username = None
first_name = models.CharField(verbose_name = 'first_name', blank = True, max_length = 30)
last_name = models.CharField(verbose_name = 'last_name', blank = True, max_length = 30)
bio = models.CharField(max_length = 150, null = True, blank = True)
avatar = models.ImageField(upload_to = 'avatars', null = True, blank = True)
date_joined = models.DateTimeField(auto_now_add = True)
last_login = models.DateTimeField(auto_now_add = True)
def __str__(self):
return self.first_name + " " + self.last_name
objects = CustomUserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
Blog model
from django.conf import settings
from django.db import models
from django.urls import reverse
from django.contrib.auth import get_user_model
class Post(models.Model):
title = models.CharField(max_length=200)
slug = models.SlugField(max_length = 200, unique = True)
body = models.TextField()
created_on = models.DateTimeField(auto_now_add=True)
author = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
related_name = 'blog_posts',
)
post_picture = models.ImageField(upload_to = 'post_picture', null = True, blank = True)
approved_comment = models.BooleanField(default=True)
def approve(self):
self.approved_comment = True
self.save()
class Meta:
ordering = ['created_on']
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('post_detail', args=[str(self.id)])
def approved_comments(self):
return self.comments.filter(approved_comment = True)
class Comment(models.Model):
post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='comments')
author = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
related_name = 'blog_comments',
null = True,
)
text = models.CharField(max_length = 300,)
created_date = models.DateTimeField(auto_now_add = True)
approved_comment = models.BooleanField(default=True)
def approve(self):
self.approved_comment = True
self.save()
def __str__(self):
return self.text
View
from django.views.generic import ListView, DetailView, CreateView
from django.views.generic.edit import UpdateView, DeleteView, FormView
from django.contrib.auth.mixins import LoginRequiredMixin
from django.urls import reverse_lazy
from . models import Post, Comment
from .forms import PostForm, CommentForm
from django.shortcuts import get_object_or_404, render, redirect
from django.contrib.auth.decorators import login_required
class PostCreateView(LoginRequiredMixin, CreateView):
model = Post
template_name = 'post_new.html'
fields = ['title', 'body',]
login_url = 'login'
def form_valid(self, form):
form.instance.author = self.request.user
return super().form_valid(form)
class PostListView(ListView):
model = Post
template_name = 'post_list.html'
def get_queryset(self):
return Post.objects.order_by('created_on').reverse()
class PostDetailView(DetailView):
model = Post
template_name = 'post_detail.html'
class PostUpdateView(LoginRequiredMixin, UpdateView):
model = Post
fields = ['title', 'body', ]
template_name = 'post_edit.html'
login_url = 'login'
class PostDeleteView(LoginRequiredMixin, DeleteView):
model = Post
template_name = 'post_delete.html'
success_url = reverse_lazy('post_list')
login_url = 'login'
def add_comment_to_post(request, pk):
post = get_object_or_404(Post, pk=pk)
if request.method == "POST":
form = CommentForm(request.POST)
if form.is_valid():
comment = form.save(commit=False)
comment.post = post
comment.save()
return redirect('post_detail', pk=post.pk)
else:
form = CommentForm()
return render(request, 'add_comment_to_post.html', {'form': form})
#login_required
def comment_approve(request, pk):
comment = get_object_or_404(Comment, pk=pk)
comment.approve()
return redirect('post_detail', pk=comment.post.pk)
#login_required
def comment_remove(request, pk):
comment = get_object_or_404(Comment, pk=pk)
comment.delete()
return redirect('post_detail', pk=comment.post.pk)
Template
{% extends 'blog_template.html' %}
{% load static %}
{% load widget_tweaks %}
{% block blog_center %}
<div class="post-entry">
<h2>{{ object.title }}</h2>
<p>by {{ object.author }} | {{ object.date }}</p>
<p>{{ object.body }}</p>
</div>
<p>Back to All Posts.</p>
{% if user.is_authenticated %}
<a class="" href="{% url 'add_comment_to_post' pk=post.pk %}">Add comment</a>
{% else %}
Log In
{% endif %}
{% for comment in post.comments.all %}
{% if user.is_authenticated or comment.approved_comment %}
<div class="">
<div class="">
{{ comment.created_date }}
{% if not comment.approved_comment %}
<a class="btn btn-default" href="{% url 'comment_remove' pk=comment.pk %}"><span class="glyphicon glyphicon-remove"></span></a>
<a class="btn btn-default" href="{% url 'comment_approve' pk=comment.pk %}"><span class="glyphicon glyphicon-ok"></span></a>
{% endif %}
</div>
<p>{{ comment.author }}</p>
<p>{{ comment.text|linebreaks }}</p>
</div>
{% endif %}
{% empty %}
<p>No comments here yet :</p>
{% endfor %}
{% endblock blog_center %}
I could't figure out what was causing it, but i implemented another way, which worked.
I first created a CharField in my comment model.
Then i assigned request.user to that field in my views, upon validation of the form. I then saved it to the database.
Then i returned the value in my template.
Here is my updated code.
models.py
from django.conf import settings
from django.db import models
from django.urls import reverse
from django.contrib.auth import get_user_model
class Post(models.Model):
title = models.CharField(max_length=200)
slug = models.SlugField(max_length = 200, unique = True)
body = models.TextField()
created_on = models.DateTimeField(auto_now_add=True)
author = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
related_name = 'blog_posts',
)
post_picture = models.ImageField(
upload_to = 'post_picture',
null = True,
blank = True,
)
approved_comment = models.BooleanField(default=True)
def approve(self):
self.approved_comment = True
self.save()
class Meta:
ordering = ['created_on']
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('post_detail', args=[str(self.id)])
def approved_comments(self):
return self.comments.filter(approved_comment = True)
class Comment(models.Model):
post = models.ForeignKey(
Post,
on_delete=models.CASCADE,
related_name='comments'
)
comment_author = models.CharField(max_length = 200, null = True)
text = models.CharField(max_length = 300,)
created_date = models.DateTimeField(auto_now_add = True)
approved_comment = models.BooleanField(default=True)
def approve(self):
self.approved_comment = True
self.save()
def __str__(self):
return self.text
views.py
from django.views.generic import ListView, DetailView, CreateView
from django.views.generic.edit import UpdateView, DeleteView, FormView
from django.contrib.auth.mixins import LoginRequiredMixin
from django.urls import reverse_lazy
from . models import Post, Comment
from .forms import PostForm, CommentForm
from django.shortcuts import get_object_or_404, render, redirect
from django.contrib.auth.decorators import login_required
class PostCreateView(LoginRequiredMixin, CreateView):
model = Post
template_name = 'post_new.html'
fields = ['title', 'body',]
login_url = 'login'
def form_valid(self, form):
form.instance.author = self.request.user
return super().form_valid(form)
class PostListView(ListView):
model = Post
template_name = 'post_list.html'
def get_queryset(self):
return Post.objects.order_by('created_on').reverse()
class PostDetailView(DetailView):
model = Post
template_name = 'post_detail.html'
class PostUpdateView(LoginRequiredMixin, UpdateView):
model = Post
fields = ['title', 'body', ]
template_name = 'post_edit.html'
login_url = 'login'
class PostDeleteView(LoginRequiredMixin, DeleteView):
model = Post
template_name = 'post_delete.html'
success_url = reverse_lazy('post_list')
login_url = 'login'
def add_comment_to_post(request, pk):
post = get_object_or_404(Post, pk=pk)
if request.method == "POST":
form = CommentForm(request.POST)
if form.is_valid():
comment = form.save(commit=False)
comment.post = post
comment.comment_author = request.user
comment.save()
return redirect('post_detail', pk=post.pk)
else:
form = CommentForm()
return render(request, 'add_comment_to_post.html', {'form': form})
#login_required
def comment_approve(request, pk):
comment = get_object_or_404(Comment, pk=pk)
comment.approve()
return redirect('post_detail', pk=comment.post.pk)
#login_required
def comment_remove(request, pk):
comment = get_object_or_404(Comment, pk=pk)
comment.delete()
return redirect('post_detail', pk=comment.post.pk)
template
{% extends 'blog_template.html' %}
{% load static %}
{% load widget_tweaks %}
{% block blog_center %}
<div class="post-entry">
<h2>{{ object.title }}</h2>
<p>by {{ object.author }} | {{ object.created_on }}</p>
<p>{{ object.body }}</p>
</div>
<p>Back to All Posts.</p>
{% if user.is_authenticated %}
<a class="" href="{% url 'add_comment_to_post' pk=post.pk %}">Add comment</a>
{% else %}
Log In
{% endif %}
{% for comment in post.comments.all %}
{% if user.is_authenticated or comment.approved_comment %}
<div class="">
<div class="">
{{ comment.created_date }}
{% if not comment.approved_comment %}
<a class="btn btn-default" href="{% url 'comment_remove' pk=comment.pk %}"><span class="glyphicon glyphicon-remove"></span></a>
<a class="btn btn-default" href="{% url 'comment_approve' pk=comment.pk %}"><span class="glyphicon glyphicon-ok"></span></a>
{% endif %}
</div>
{{ comment.comment_author }}
{{ comment.text|linebreaks }}
</div>
{% endif %}
{% empty %}
<p>No comments here yet :</p>
{% endfor %}
{% endblock blog_center %}
Related
I have a system that requires a homeowner to submit a form about their guest's details. When they submit a form, each will be assigned a unique 6-digit code. This code will be hashed with SHA-256. In the admin's view, there is a list of all submitted forms. I want to do a search function where when I enter the code, the system will look through the hashed code and check if it exists or not.
This is my GuestController:
public function index()
{
//returns admin's view
$guest = Guest::all();
return view('pages.guest.index', compact('guest'));
}
public function store(Request $request)
{
$guest = new Guest;
$guest->code = random_int(100000, 999999);
$guest->hash = hash('sha256', $guest['code']);
$guest->owner_id = Auth::user()->id;
$guest->owner = Auth::user()->name;
$guest->unit = Auth::user()->unit;
$guest->guestname = $request->input('guestname');
$guest->guestphone = $request->input('guestphone');
$guest->guestic = $request->input('guestic');
$guest->guestcar = $request->input('guestcar');
$guest->numberofguests = $request->input('numberofguests');
$guest->datevisit = $request->input('datevisit');
$guest->timevisit = $request->input('timevisit');
$guest->save();
return redirect('show-pass')->with('status', 'Guest Added Successfully');
}
public function search(Request $request)
{
//Get the search value from the request
$search = $request->input('search');
//Search in the code from the list
$guest = Guest::query()
->where('code', 'LIKE', "%{$search}%")
->get();
//Return the search view with the results compacted
return view('pages.guest.search', compact('guest'));
}
This is my search result blade:
<div class="card-body">
#if($guest->isNotEmpty())
#foreach ($guest as $item)
<div class="post-list">
<p>Owner : {{ $item->owner }}</p>
<p>Unit : {{ $item->unit }}</p>
<p>Guest Name : {{ $item->guestname }}</p>
<p>Guest Phone Number : {{ $item->guestphone }}</p>
<p>Guest IC Number : {{ $item->guestic }}</p>
<p>Guest Car Number : {{ $item->guestcar }}</p>
<p>Date : {{ $item->datevisit }}</p>
<p>Time : {{ $item->timevisit }}</p>
</div>
#endforeach
#else
<div>
<h4>No guests with the code was found</h4>
</div>
#endif
</div>
Is what I'm trying to do possible? If yes, how can I edit my search method to be able to do so? May I get some help?
models.py
class Log(models.Model):
product = models.ForeignKey(ProductInfo,on_delete=models.PROTECT,default=0,verbose_name='کالا')
number = models.IntegerField(null=False,blank=False,default=0,verbose_name='تعداد')
date_to_recived = jmodels.jDateTimeField(verbose_name='تاریخ دریافت محصول')
sender_name = models.CharField(max_length=100,default=None,verbose_name='نام و نام خانوادگی فرستنده')
sender_phone = models.CharField(max_length=30,default=None,verbose_name='شماره تلفن فرستنده')
sender_melli_code = models.CharField(max_length=100, default=None,verbose_name='شماره ملی فرستنده')
sender_sign = models.ImageField(blank=True, null=True, upload_to=image_saving,verbose_name='امضای فرستنده')
reciver_name = models.CharField(max_length=100,default=None,verbose_name='نام و نام خانوادگی گیرنده')
reciver_phone = models.CharField(max_length=30,default=None,verbose_name='شماره تلفن گیرنده')
reciver_melli_code = models.CharField(max_length=100, default=None,verbose_name='شماره ملی گیزنده')
reciver_sign = models.ImageField(blank=True, null=True, upload_to=image_saving,verbose_name='امضای گیرنده')
def __str__(self):
return f'{self.product.title} , number of log = {self.id}'
serializers.py
class LogSerializer(serializers.ModelSerializer):
class Meta:
model = Log
fields = '__all__'
views.py
class LogViewSet(viewsets.ModelViewSet):
queryset = Log.objects.all().order_by('-id')
serializer_class = LogSerializer
permission_classes = [IsAdminUser]
filter_backends = (filters.SearchFilter,)
search_fields = ['product__title','product__owner__username','reciver_name',
'sender_name']
def retrieve(self, request, pk=None):
obj = get_object_or_404(self.queryset, pk=pk)
serializer_class = LogSerializer(obj)
return Response(serializer_class.data)
def update(self, request, pk):
obj = Log.objects.get(pk=pk)
serializer = LogSerializer(obj, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
i'll be thankfull if you help me.
this is my imagefield when i wanna update my data.
and my imageFields and datefields are blank.
Form in forms.py when rendering HTML have required attr but in form don't have. Fields in models.py can be null execpt primary key and foreign key. I want delete required attr in HTML
models.py
class UserInfor(models.Model):
GENDERS = (
('nam', "Nam"),
('nữ', "Nữ"),
('khác', "Khác")
)
user = models.OneToOneField(User, on_delete=models.CASCADE)
date_of_birth = models.DateField(null=True)
gender = models.CharField(choices=GENDERS, max_length=10, null=True)
address = models.CharField(max_length=255, null=True)
phone_number = models.CharField(max_length=10, null=True)
def __str__(self):
return self.user.username
forms.py
class ProfileForm(ModelForm):
class Meta:
model = UserInfor
fields = ['date_of_birth', 'gender', 'address', 'phone_number']
widgets = {
'date_of_birth': forms.DateInput(attrs={'placeholder': 'Date of Birth', 'class': 'form-control'}),
'address': forms.TextInput(attrs={'type': 'text', 'placeholder': 'Address', 'class': 'form-control'}),
'phone_number': forms.TextInput(attrs={'type': 'text', 'placeholder': 'Phone Number', 'class': 'form-control'}),
}
labels = {
'date_of_birth': "Ngày sinh",
'gender': "Giới tính",
'address': "Địa chỉ",
'phone_number': "Số điện thoại",
}
profile.html
<div class="col-lg-10">
<div class="form-group">
<label for="id_date_of_birth"><h6>Ngày sinh</h6></label>
<input type="text" name="date_of_birth" value="1998-09-26" placeholder="Date of Birth" class="form-control" required id="id_date_of_birth">
</div>
</div>
You should only need to set blank=true on your ModelForms fields:
models.py
class UserInfor(models.Model):
GENDERS = (
('nam', "Nam"),
('nữ', "Nữ"),
('khác', "Khác")
)
user = models.OneToOneField(User, on_delete=models.CASCADE)
date_of_birth = models.DateField(null=True, blank=true)
gender = models.CharField(choices=GENDERS, max_length=10, null=True, blank=true)
address = models.CharField(max_length=255, null=True, blank=true)
phone_number = models.CharField(max_length=10, null=True, blank=true)
def __str__(self):
return self.user.username
I have three model. Product, ShoppingCart and CartDetails. when i add a product to cart i want to save data in ShoppingCart and CartDetails.ShoppingCart (id) is related with CartDetails (cart_id).And CartDetails (product_id) is related with Product(id). Now when i am posting data it shows the error "Column 'product_id' cannot be null". I think i am missing a silly thing. But cannot find out the silly thing. I am new to django rest framework.I am using angular for front end. I don't understand what i am doing wrong.Thanks in advance.
models.py
class Product(models.Model):
product_name = models.CharField(max_length=200)
cat_id = models.ForeignKey('Category', on_delete=models.CASCADE, db_column='cat_id')
description = models.TextField()
image_url = models.ImageField(upload_to='images/product_name/%Y/%m/%d/')
sell_price = models.IntegerField()
cost_price = models.IntegerField()
discount_price = models.IntegerField()
active = models.BooleanField()
create_date = models.DateTimeField(default=datetime.now)
def __str__(self):
return self.product_name
class Meta:
db_table = "products"
class ShoppingCart(models.Model):
create_date = models.DateTimeField(default=datetime.now)
amount = models.IntegerField(default=0)
def __int__(self):
return self.id
class Meta:
db_table = "shopping-cart"
class CartDetails(models.Model):
cart = models.ForeignKey(ShoppingCart, related_name='cart_details', on_delete=models.CASCADE)
product = models.ForeignKey(Product, on_delete=models.CASCADE)
qty = models.IntegerField(default=0)
amount = models.IntegerField(default=0)
create_date = models.DateTimeField(default=datetime.now)
def __int__(self):
return self.id
class Meta:
db_table = "cart-details"
serializers.py
class ProductSerializer(serializers.ModelSerializer):
image_url = Base64ImageField(max_length=None, use_url=True)
class Meta:
model = Product
fields = ('id', 'product_name', 'description', 'image_url', 'sell_price', 'cost_price',
'discount_price', 'active', 'cat_id')
class CartDetailSerializer(serializers.ModelSerializer):
class Meta:
model = CartDetails
fields = ('product', 'qty', 'amount')
class ShoppingCartSerializer(serializers.ModelSerializer):
cart_details = CartDetailSerializer()
class Meta:
model = ShoppingCart
fields = ('id', 'amount', 'cart_details')
def create(self, validated_data):
carts_data = validated_data.pop('cart_details')
# cart = ShoppingCart.objects.create(**validated_data)
# for data in carts_data:
# CartDetails.objects.create(cart=cart, **carts_data)
return validated_data
views.py
class ProductViewSet(viewsets.ModelViewSet):
queryset = Product.objects.all()
serializer_class = ProductSerializer
class ShoppingCartViewSet(viewsets.ModelViewSet):
queryset = ShoppingCart.objects.all()
serializer_class = ShoppingCartSerializer
class CartDetailsViewSet(viewsets.ModelViewSet):
queryset = CartDetails.objects.all()
serializer_class = CartDetailSerializer
This is angular service to post data
private create(product) {
const cart = {
amount: product.sell_price,
cart_details: {
qty: 1,
product: product.id,
amount: product.sell_price
}
};
return this.http.post(this.globalService.baseUrl + 'shopping-cart/', cart);
}
If i am not wrong, problem is here
product_id = ProductSerializer(read_only=True, source='product.id')
as you make this as read_only field, so product_id is not writing on instance creation. read_only should be removed.
product_id = ProductSerializer(source='product.id')
I try this method to get image dimensions:
{% set image_width = fields.sec_port_image.width %}
{% set image_height = fields.sec_port_image.height %}
<a href="{{ fields.sec_port_image|media }}" width="{{ image_width }}" height="{{ image_height }}">
but without success. I Also tried:
{% set image_width = fields.sec_port_image.width|media %}
and
{% set image_width = fields.sec_port_image|media.width %}
but also without success.
Is there a way on Octobercms to get image dimensions using twig?
Extend twig in order to get the original size of your image. Something like this should work (not tested but you'll get the idea)
First create a registration class, see here for a reference.
<?php
class Registration {
public function registerMarkupTags()
{
return [
'filters' => [
// A global function, i.e str_plural()
'image_width' => [$this, 'getImageWidth'],
'image_height' => [$this, 'getImageHeight'],
],
];
}
private $images = [];
public function getImageWidth($url) {
return $this->getImageSize($url) ? $this->getImageSize($url)['width'] : null;
}
public function getImageHeight($url) {
return $this->getImageSize($url) ? $this->getImageSize($url)['height'] : null;
}
private function getImageSize($url) {
if (!isset($this->images[$url])) {
$data = #getimagesize($url);
if ($data) {
$this->images[$url] = [
'width' => $data[0],
'height' => $data[1],
];
}else{
$this->images[$url] = false;
}
}
}
return $this->images[$url];
}
If done correctly you then could use the new filters inside your template like this
{% set source = fields.sec_port_image|media %}
<a href="{{ source }}" width="{{ source|image_width }}" height="{{ source|image_height }}">