Django - Inline formset - How to set current user - python

-Objective-
I need to set, in a Inline Formset, the current user as automatic content of a field of the form. (Currently not working)
Version
Python 3.9.2 - Django 3.2
Context:
I've created a List, where I have some objects(Headers).
From the list I can create new headers and access to the detail-page(Detailview)for each of these by using a foreign-key(called by PK-primarykey).
In this page I can see more informations about 1 specific header.
Each header can have multiple lines of informations that need to be linked to it.
The lines are created or updated with (max 4 different) specific Inline Formsets.
-Issue and Error-
I created the forms that are correctly rendered, but I need to set for each line, a field that automatically gets "current user" as its content.
I can't save and receive instead"User cannot be null".
I'm unable to find a solutions and tried many things but stuck with this error.
Would kindly appreciate any help on how to solve this problem.
Thanks in advance,
Below some code:
URLS.PY
from django.urls import path, re_path
from fttlapp import views
app_name= 'fttlapps'
urlpatterns = [
path('fttlapphome2/', views.Fttlapphome2View.as_view(), name='fttlapphome2'),
path('fttlogheader/', views.HeadfttlogListView.as_view(), name='headfttlogs'),
path('fttlogheader/add/', views.HeadfttlogCreateView.as_view(), name='headfttlogcreate'),
path('fttlogheader/<int:pk>/', views.HeadfttlogDetailView.as_view(), name='headfttlogdetail'),
path('fttlogheader/<int:pk>/flights/edit/', views.HeadfttlogDeafttlogEditView.as_view(), name='head_flight_edit'),
]
FORMS.PY
from django import forms
from django.contrib.auth.models import User
from django.db.models.fields import CharField, DateField
from django.forms import ModelForm, widgets
from django.forms.fields import ChoiceField
from django.forms.models import ModelChoiceField
from django.utils import timezone
# Load necessary to manage Form in Form
from django.forms.models import inlineformset_factory
# Load Tables
from fttlapp.models import Headfttlog, Deafttlog, Debfttlog
###############################################################################
# Forms for Headfttlog #
###############################################################################
class HeadfttlogcreateForm(ModelForm):
class Meta:
model = Headfttlog
exclude = ['hea_creator', 'hea_modifier']
widgets = {
'hea_fttldate' : forms.TextInput(attrs={'type': 'date'}),
'hea_nxtcheckdate' : forms.TextInput(attrs={'type': 'date'}),
'hea_transfereddate' : forms.TextInput(attrs={'type': 'date'}),
}
## Calendar widget to work both with Create and Update needs to be TextInput with type date
## Calendar widget not compatible with localized_fields !
###############################################################################
# Forms for Headfttlog with Deafttlog details view Management #
###############################################################################
HeadfttlogDeafttlogFormset = inlineformset_factory(Headfttlog, Deafttlog,
fields=('dea_linetype', 'dea_fttlcode', 'dea_airportfrom', 'dea_airportto',
'dea_instrtimestart', 'dea_instrtimeend', 'dea_instrtimetot',
'dea_blocktimestart', 'dea_blocktimeend', 'dea_blocktimetot',
'dea_flighttimestart', 'dea_flighttimeend', 'dea_flighttimetot',
'dea_approach', 'dea_landing', 'dea_external', 'dea_fuel', 'dea_oil',
'dea_lessonnotes', 'dea_preflightsignature', 'dea_invoiceaccount',
'dea_transfered', 'dea_transfereddate',
'dea_reccanceled', 'dea_creator', 'dea_modifier'),
widgets={
'dea_instrtimestart' : forms.TimeInput(format= '%H:%M', attrs={'type': 'time'}),
'dea_instrtimeend' : forms.TimeInput(format= '%H:%M', attrs={'type': 'time'}),
'dea_instrtimetot' : forms.TimeInput(format= '%H:%M', attrs={'type': 'time'}),
'dea_blocktimestart' : forms.TimeInput(format= '%H:%M', attrs={'type': 'time'}),
'dea_blocktimeend' : forms.TimeInput(format= '%H:%M', attrs={'type': 'time'}),
'dea_blocktimetot' : forms.TimeInput(format= '%H:%M', attrs={'type': 'time'}),
'dea_flighttimestart' : forms.TimeInput(format= '%H:%M', attrs={'type': 'time'}),
'dea_flighttimeend' : forms.TimeInput(format= '%H:%M', attrs={'type': 'time'}),
'dea_flighttimetot' : forms.TimeInput(format= '%H:%M', attrs={'type': 'time'}),
'dea_reccanceled' : forms.HiddenInput,
'dea_creator' : forms.HiddenInput,
'dea_modifier' : forms.HiddenInput,
}, extra=1, max_num=8)
VIEWS.PY
from django.shortcuts import render
from django.http import HttpResponseRedirect
from django.urls import reverse
# Load necessary view
from django.views.generic import (
TemplateView, ListView, CreateView, DetailView, FormView)
from django.views.generic.detail import SingleObjectMixin
# Load for security and access management
from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth.mixins import PermissionRequiredMixin
# Load functions and tools for search bar management
from fttlapp.filters import HeadfttlogFilter
import operator
from functools import partial, reduce
from django.db.models import Q
# Load functions for messages management
from django.contrib import messages
# Load Tables & Forms
from fttlapp.models import Headfttlog
from fttlapp.forms import HeadfttlogcreateForm
from fttlapp.forms import HeadfttlogDeafttlogFormset
###############################################################################
# FTTL home page management #
###############################################################################
#login_required
def fttlapphome(request):
context = {}
return render(request, 'fttlapp/fttlapphome.html', context)
###############################################################################
# FTTL home page 2 management #
###############################################################################
class Fttlapphome2View(TemplateView, LoginRequiredMixin):
template_name = 'fttlapp/fttlapphome2.html'
###############################################################################
# Headfttlog - List view Management #
###############################################################################
class HeadfttlogListView(ListView, LoginRequiredMixin, PermissionRequiredMixin):
permission_required = 'fttlapp.view_headfttlog'
model = Headfttlog
template_name = 'fttlapp/headfttlog_list.html'
paginate_by = 10
def get_context_data(self, *args, **kwargs):
context = super().get_context_data(*args, **kwargs)
context['myFilter'] = HeadfttlogFilter(
self.request.GET, queryset=self.get_queryset())
return context
# Following redefintion necessary to obtain correct pagination after Filter plugin
def get_queryset(self):
queryset = super().get_queryset()
return HeadfttlogFilter(self.request.GET, queryset=queryset).qs
###############################################################################
# Headfttlog - Create view Management Headfttlog #
###############################################################################
class HeadfttlogCreateView(LoginRequiredMixin, PermissionRequiredMixin, CreateView):
permission_required = 'fttlapp.add_headfttlog'
model = Headfttlog
template_name = 'fttlapp/headfttlogcreate_form.html'
form_class = HeadfttlogcreateForm
def form_valid(self, form):
form.instance.hea_creator = self.request.user
form.instance.hea_modifier = self.request.user
messages.add_message(
self.request,
messages.SUCCESS,
'The LOG has been created'
)
return super().form_valid(form)
###############################################################################
# Headfttlog - Detail view Management Headfttlog #
###############################################################################
class HeadfttlogDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView):
permission_required = 'fttlapp.view_headfttlog'
model = Headfttlog
template_name = 'fttlapp/headfttlogdetail.html'
###############################################################################
# Headfttlog with Deafttlog details view Management #
###############################################################################
class HeadfttlogDeafttlogEditView(LoginRequiredMixin, PermissionRequiredMixin, SingleObjectMixin, FormView):
permission_required = ('fttlapp.add_headfttlog','fttlapp.change_headfttlog',
'fttlapp.add_deafttlog', 'fttlapp.change_deafttlog')
model = Headfttlog
template_name = 'fttlapp/head_flight_edit.html'
### 1. Identification of the single Headfttlog we will work with
def get(self, request, *args, **kwargs):
self.object = self.get_object(queryset=Headfttlog.objects.all())
return super().get(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
self.object = self.get_object(queryset=Headfttlog.objects.all())
return super().post(request, *args, **kwargs)
### 2. FormSet creation - instance is the link to the above data.
def get_form(self, form_class=None):
return HeadfttlogDeafttlogFormset(**self.get_form_kwargs(), instance=self.object)
def formset_valid(self, form):
form.dea_creator = self.request.user
form.dea_modifier = self.request.user
form.save()
messages.add_message(
self.request,
messages.SUCCESS,
'Changes were saved.'
)
return HttpResponseRedirect(self.get_success_url())
def get_success_url(self):
return reverse('fttlapps:headfttlogdetail', kwargs={'pk': self.object.pk})
###############################################################################
# End of view Management #
###############################################################################
HTML
{% extends 'base/dibase3.html' %}
{% load static %}
{% load crispy_forms_tags %}
{% crispy formset %}
{% block title %}Editing Flights and Instructions for {{ headfttlog.fttlcode }}{% endblock %}
{% block content %}
<style>
.box{
max-width: fit-content;
margin: auto;
}
</style>
</div>
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<div class="container-fluid">
<div class="text-start">
<a class="btn btn-outline-info " href="{% url 'fttlapps:headfttlogdetail' pk=headfttlog.pk %}">Back to Detail</a>
</div>
</div>
</nav>
<hr>
<div class="container">
<form action="" method="post" enctype="multipart/form-data">
{% for hidden_field in form.hidden_fields %}
{{ hidden_field.errors }}
{{ hidden_field }}
{% endfor %}
{% csrf_token %}
{{ form.management_form }}
{{ form.non_form_errors }}
<h3>Update Collection</h3>
{% for deafttlog_form in form.forms %}
<hr>
<h5>
{% if deafttlog_form.instance.id %}
Deafttlog: {{ deafttlog_form.instance.dea_linetype }}
{% else %}
{% if form.forms|length > 1 %}
Add another deafttlog
{% else %}
Add a deafttlog
{% endif %}
{% endif %}
</h5>
{% for hidden_field in deafttlog_form.hidden_fields %}
{{ hidden_field.errors }}
{% endfor %}
<table>
{{ deafttlog_form }}
</table>
{% endfor %}
<hr>
<p>
<button type="submit" value="Update Flight" class="btn btn-primary w-100 mb-3">Update Flight</button>
Return
</p>
</form>
{% endblock content %}

For audit fields like creator and modifier model fields I will usually set blank=True, null=True in the model field definition. Just by doing that your code will work, because you are already handling setting of dea_creator and dea_modifier in your views.
If you want to enforce this in the database like you are doing now, you will have to pass the request.user to your formset and set it as the initial value for the dea_creator field when initializing the forms.
Edit:
The alternative way I mentioned above, in your HeadfttlogDeafttlogFormset, instead of setting fields and widgets, create an actual form to use, for example DeafttlogForm, and set the fields and widgets there. Then in your formset, you set form=DeafttlogForm.
In the newly created DeafttlogForm, initialize the dea_creator field:
def __init__(self, *args, **kwargs):
user = kwargs.pop('user', None)
super(DeafttlogForm, self).__init__(*args, **kwargs)
instance = getattr(self, 'instance', None)
if not instance.id and user:
self.initial['dea_creator'] = user
Then in HeadfttlogDeafttlogEditView, add a get_form_kwargs method:
def get_form_kwargs(self):
kwargs = super(HeadfttlogDeafttlogEditView, self).get_form_kwargs()
kwargs['user'] = self.request.user
return kwargs

Related

Associate a Django Bool FormField with a submit button in a ModelForm and CBV

The view has a Boolean Field which will define if a question is OK or needs correction.
The template will load two buttons to act as submit to the form, "Question is OK" and "Question needs correction".
I need to pass the value of this button as the Boolean Field value.
I found the answer when using Function-based views, but I'm using Class-based views, so I don't know how to pass the request.POST values.
Here's my views.py and forms.py:
views.py
class QuestionValidation(PermissionRequiredMixin, UpdateView):
permission_required = 'users.validator'
model = Question
form_class = ValidationForm
template_name = 'question_validation.html'
def get_context_data(self, *args, **kwargs):
context = super().get_context_data(**kwargs)
context['question'] = Question.objects.filter(
question_order=self.kwargs['order']).get(id_by_order=self.kwargs['id_by_order'])
context['order'] = self.kwargs['order']
context['id_by_order'] = self.kwargs['id_by_order']
return context
def get_object(self, *args, **kwargs):
question_order = Q(question_order__id=self.kwargs['order'])
question_id = Q(id_by_order__contains=self.kwargs['id_by_order'])
q = Question.objects.get(question_order & question_id)
return get_object_or_404(Question, pk=q.id)
def get_success_url(self, *args, **kwargs):
view_name = "order-detail"
return reverse(view_name, kwargs={'pk': self.kwargs['order']})
forms.py
class ValidationForm(forms.ModelForm):
class Meta:
model = Question
fields = ['revision_report', 'revision_approval']
widgets = {
'revision_report': forms.HiddenInput(),
'revision_approval': forms.HiddenInput(),
}
and part of the template that this code will be loaded:
<form action="" method="POST">{% csrf_token %}
{{ form.as_p }}
<button class="btn btn-success" name="question_approved">Questão aprovada</button>
<button class="btn btn-danger" name="question_refused">Questão não foi aprovada</button>
</form>
<br><br>
<script src="{% static 'js/hoverValidatorTextbox.js' %}"></script>
{% endblock %}
As Ene P told in the comments the following link solves it.
https://docs.djangoproject.com/en/3.2/topics/class-based-views/intro/#handling-forms-with-class-based-views

Automatically join the user who created the group

I have a project called social clone project in this project you can only post if you are in a group. What i want to happen is if the user created a group the user should automatically in the group, in this case if i created a group i still need to join the group to join my own group. I tried to search this on google but i get no result and i hope someone will help me and btw i'm just new here in programming and i'm currently learning django.
models.py
##########################
## GROUPS VIEWS.PY FILE ##
##########################
from django.contrib.auth import get_user_model
from django import template
from django.db import models
from django.utils.text import slugify
from misaka import html
from django.urls import reverse
User = get_user_model()
register = template.Library()
class Group(models.Model):
name = models.CharField(max_length=255, unique=True)
slug = models.SlugField(allow_unicode=True, unique=True)
description = models.TextField(blank=True, default="")
description_html = models.TextField(editable=False, blank=True, default="")
members = models.ManyToManyField(User, through='GroupMember')
def __str__(self):
return self.name
def save(self, *args, **kwargs):
self.slug = slugify(self.name)
self.description_html = html(self.description)
super().save(*args, **kwargs)
def get_absolute_url(self):
return reverse('groups:single', kwargs={'slug': self.slug})
class Meta:
ordering = ['name']
class GroupMember(models.Model):
user = models.ForeignKey(User, related_name='user_groups', on_delete=models.CASCADE)
group = models.ForeignKey(Group, related_name='memberships', on_delete=models.CASCADE)
def __str__(self):
return self.user.username
class Meta:
unique_together = ('user', 'group')
views.py
##########################
## GROUPS VIEWS.PY FILE ##
##########################
from django.contrib.auth.mixins import LoginRequiredMixin
from django.views import generic
from groups.models import Group, GroupMember
from django.urls import reverse
from django.shortcuts import get_object_or_404
from django.db import IntegrityError
from django.contrib import messages
class CreateGroup(LoginRequiredMixin, generic.CreateView):
model = Group
fields = ('name', 'description')
class SingleGroup(generic.DetailView):
model = Group
class ListGroups(generic.ListView):
model = Group
class JoinGroup(LoginRequiredMixin, generic.RedirectView):
def get_redirect_url(self, *args, **kwargs):
return reverse('groups:single', kwargs={'slug': self.kwargs.get('slug')})
def get(self, request, *args, **kwargs):
group = get_object_or_404(Group, slug=self.kwargs.get('slug'))
try:
GroupMember.objects.create(user=self.request.user, group=group)
except IntegrityError:
messages.warning(self.request, (f"Warning, already a group member of {group.name} group."))
else:
messages.success(self.request, (f"You are now a member of {group.name} Group."))
return super().get(request, *args, **kwargs)
class LeaveGroup(LoginRequiredMixin, generic.RedirectView):
def get_redirect_url(self, *args, **kwargs):
return reverse('groups:single', kwargs={'slug': self.kwargs.get('slug')})
def get(self, request, *args, **kwargs):
try:
membership = GroupMember.objects.filter(
user=self.request.user,
group__slug=self.kwargs.get('slug')
).get()
except GroupMember.DoesNotExist:
messages.warning(self.request, ("You can't leave this group because you aren't in it!"))
else:
membership.delete()
messages.success(self.request, ("You have successfully left this group."))
return super().get(request, *args, **kwargs)
group_form.html
{% extends 'groups/group_base.html' %}
{% load bootstrap4 %}
{% block group_content %}
<div class="container">
<h4>Create New Group</h4>
<form id="groupForm" action="{% url 'groups:create' %}" method="POST">
{% csrf_token %}
{% bootstrap_form form %}
{% buttons %}
<button type="submit" class="btn btn-large btn-primary">Create</button>
{% endbuttons %}
</form>
</div>
{% endblock %}
group_detail.html
{% extends 'groups/group_base.html' %}
{% block pregroup %}
<div class="container">
<h1>{{ group.name }}</h1>
<h2>Member Count: {{ group.members.count }}</h2>
<div class="content">
{% if user in group.members.all %}
<a class="btn btn-lg btn-warning" href="{% url 'groups:leave' slug=group.slug %}"><span class="fa fa-times-circle-o"></span>Leave</a>
{% else %}
<a class="btn btn-lg btn-warning" href="{% url 'groups:join' slug=group.slug %}"><span class="fa fa-check-circle-o"></span>Join</a>
{% endif %}
</div>
</div>
{% endblock %}
{% block group_content %}
<div class="col-md-8">
{% if group.posts.count == 0 %}
<h2>No Post In This Group Yet!</h2>
{% else %}
{% for post in group.posts.all %}
{% include 'posts/_post.html' %}
{% endfor %}
{% endif %}
</div>
{% endblock %}
Override the form_valid method on your CreateGroup view, here you can perform some additional logic after the object has been saved
class CreateGroup(LoginRequiredMixin, generic.CreateView):
model = Group
fields = ('name', 'description')
def form_valid(self, form):
result = super().form_valid(form)
GroupMember.objects.create(user=self.request.user, group=self.object)
return result
ccbv.co.uk is fantastic for inspecting the available methods there are to override for the built-in class based views

Trying to make comments editable in django

I have a blog app and the comments can be added on the detail page of the blog, im having trouble implementing a way for users to edit comments they have already made. I have it so a url shows up on comments where only the person signed in can click the link to edit their comments on the post however im getting this error when I try to load the detail page now. Any help would be appreciated thank you
Reverse for 'update_comment' with arguments '(None,)' not found. 1 pattern(s) tried: ['posts(?P[0-9]+)/(?P[0-9]+)/(?P[0-9]+)/(?P[-a-zA-Z0-9_]+)/(?P<comment_id>[0-9]+)/update$']
edit:
I corrected my detail.html file and now im getting this error:
update_comment() missing 1 required positional argument: 'id'
models.py
from django.db.models.signals import pre_save
from Date.utils import unique_slug_generator
from django.db import models
from django.utils import timezone
from django.contrib.auth.models import User
from django.urls import reverse
from django.conf import settings
class PublishedManager(models.Manager):
def get_queryset(self):
return super(PublishedManager,
self).get_queryset()\
.filter(status='cleared')
class Post(models.Model):
STATUS_CHOICES = (
('cleared','Cleared'),('UnderReview','Being Reviewed'),('banned','Banned'),)
title = models.CharField(max_length = 300)
slug = models.SlugField(max_length = 300, unique_for_date='publish')
author = models.ForeignKey(User, on_delete=models.SET_NULL, related_name='forum_posts',null=True)
body = models.TextField()
publish = models.DateTimeField(default=timezone.now)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
status = models.CharField(max_length=12,choices=STATUS_CHOICES,default='cleared')
objects = models.Manager()
cleared = PublishedManager()
class Meta:
ordering =('-publish',)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('posts:post_detail', args=[self.publish.year, self.publish.month, self.publish.day, self.slug])
def slug_generator(sender, instance, *args, **kwargs):
if not instance.slug:
instance.slug = unique_slug_generator(instance)
pre_save.connect(slug_generator, sender=Post)
class Comment(models.Model):
post = models.ForeignKey(Post, on_delete=models.SET_NULL, related_name='comments',null=True)
name = models.ForeignKey(User, on_delete=models.SET_NULL,null=True)
body = models.TextField()
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
active = models.BooleanField(default=True)
class Meta:
ordering = ('created',)
def __str__(self):
return f'Comment by {self.name} on {self.post}'
urls.py
from . import views
from django.urls import path, include
from django.contrib.auth import views as auth_views
from .views import PostListView, PostCreateView,PostUpdateView
app_name = 'posts'
urlpatterns = [
path('', views.PostListView.as_view(), name='post_list'),
#path('<int:year>/<int:month>/<int:day>/<slug:post>/',views.PostDetailView.as_view(),name='post_detail'),
path('<int:year>/<int:month>/<int:day>/<slug:post>/',views.post_detail,name='post_detail'),
path('post/new/',PostCreateView.as_view(), name='post-create'),
path('<int:year>/<int:month>/<int:day>/<slug:post>/update/',PostUpdateView.as_view(), name='post-update'),
path('<int:year>/<int:month>/<int:day>/<slug:post>/<int:comment_id>/update',views.update_comment, name='update_comment'),
]
views.py
from django.shortcuts import render, get_object_or_404
from .models import Post, Comment
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from django.views.generic import ListView, CreateView, UpdateView
from .forms import CommentForm, PostForm
from django.contrib.auth.models import User
from django.http import HttpResponseRedirect
from django.contrib.auth.decorators import login_required
from django.shortcuts import redirect, render
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
from django.contrib import messages
from django.urls import reverse
class PostListView(ListView):
queryset = Post.cleared.all()
context_object_name = 'posts'
paginate_by = 3
template_name = 'posts/post/list.html'
"""class PostDetailView(DetailView, Post):
queryset = Post.cleared.all()
model = Post
fields = ['title','body']
template_name = 'posts/post/detail.html'
form_class = CommentForm
def get_object(self, *args, **kwargs):
return get_object_or_404(
Post,
publish__year=self.kwargs['year'],
publish__month=self.kwargs['month'],
publish__day=self.kwargs['day'],
slug=self.kwargs['post'],
)
return post
def get_context_data(self, *args, **kwargs):
context = super().get_context_data(*args, **kwargs)
context['comment'] = Comment.objects.all()
context['comment_form'] = CommentForm()
return context
def post(self, request, *args, **kwargs):
post = get_object_or_404(Post , slug=post, status='cleared',publish__year=year,publish__month=month,publish__day=day)
comment_form = self.form_class(request.POST)
if comment_form.is_valid():
return HttpResponseRedirect( post.get_absolute_url() )
return render(request, self.template_name, {'comment_form': comment_form})"""
class PostCreateView(LoginRequiredMixin, CreateView):
model = Post
fields = ['title','body']
def form_valid(self, form):
form.instance.author = self.request.user
return super().form_valid(form)
class PostUpdateView(LoginRequiredMixin, UpdateView):
model = Post
fields = ['title','body']
template_name = 'posts/post-update.html'
def get_object(self, *args, **kwargs):
return get_object_or_404(
Post,
publish__year=self.kwargs['year'],
publish__month=self.kwargs['month'],
publish__day=self.kwargs['day'],
slug=self.kwargs['post'],
author=self.request.user
)
def get_success_url(self):
return reverse('posts:post_detail',
args=[
self.object.publish.year,
self.object.publish.month,
self.object.publish.day,
self.object.slug
]
)
def form_valid(self, form):
form.instance.author = self.request.user
return super().form_valid(form)
def post_detail(request, year, month, day, post, comment_id = None):
post = get_object_or_404(Post , slug=post, status='cleared',publish__year=year,publish__month=month,publish__day=day)
comments = post.comments.filter(active=True)
if request.method == 'POST':
comment_form = CommentForm(data=request.POST)
if comment_form.is_valid():
comment_form.instance.post = post
comment_form.instance.name = request.user
comment_form.save()
return HttpResponseRedirect( post.get_absolute_url() )
else:
comment_form = CommentForm()
return render(request,'posts/post/detail.html', {'post':post , 'comments': comments,'comment_form': comment_form, 'comment_id':comment_id })
def update_comment(request, year, month, day, post,id, comment_id = None):
post = get_object_or_404(Post , slug=post, status='cleared',publish__year=year,publish__month=month,publish__day=day, id=id)
comments = post.comments.filter(active=True)
comment_form = CommentForm
if comment_id:
comment_form = CommentForm(instance=Comment.objects.get(id=comment_id), data=request.POST)
if request.method == 'POST':
comment_form = CommentForm(data=request.POST)
if comment_form.is_valid():
comment_form.instance.post = post
comment_form.instance.name = request.user
comment_form.save()
return HttpResponseRedirect( post.get_absolute_url() )
else:
comment_form = CommentForm()
return render(request,'posts/update_comment.html', {'post':post , 'comments': comments,'comment_form': comment_form, 'comment_id':comment_id })
forms.py
from django import forms
from .models import Comment,Post
class CommentForm(forms.ModelForm):
class Meta:
model = Comment
fields = ('body',)
class PostForm(forms.ModelForm):
class Meta:
model = Post
fields =('title','body',)
detail.html
{% extends "Main/Base.html" %}
{% block title %}{{ post.title }}{% endblock %}
{% block content %}
<h1>{{ post.title }}<h1>
<p class="date">
Published {{ post.publish }} by {{ post.author }}
</p>
{{ post.body|linebreaks }}
{% if user.is_authenticated and user == post.author %}
<h3>Update your post</h3>
{% endif %}
{% with comments.count as total_comments %}
<h2>
{{ total_comments }} comment{{ total_comments|pluralize }}
</h2>
{% endwith %}
{% for comment in comments %}
<div class="comment">
<p class="info">
Comment by {{comment.name }}
{{ comment.created }}
</p>
{{ comment.body|linebreaks}}
{% if user.is_authenticated and user == comment.name %}
<p>edit</p>
{% endif %}
</div>
{% empty %}
<p>There are no comments yet.</p>
{% endfor %}
{% if new_comment %}
<h2>Your comment has been added.</h2>
{% else %}
{% if request.user.is_authenticated %}
<h2>Add a new comment</h2>
<form method="post">
{{ comment_form.as_p }}
{% csrf_token %}
<p><input type="submit" value="Add comment"></p>
</form>
{% else %}
<h3>You need to be logged in to make a comment please log-in if you dont have an account register here now</h3>
{% endif %}
{% endif %}
{% endblock %}
update_comment.html
{% extends "Main/Base.html" %}
{% block content %}
<form method="POST" action="{% url 'posts:update_comment' post.publish.year post.publish.month post.publish.day post.slug comment.id %}">
{{ comment_form.as_p }}
{% csrf_token %}
<p><input type="submit" value="Add comment"></p>
</form>
{% endblock %}
Ive been trying a bunch of this to try and make it work so my code is a bit of a mess, there aren't many tutorials on making editable comments with django.

How do you display a views.py's variable linked to annotated queryset in a django template?

How do you display a views.py's variable linked to annotated queryset in a django template? I know the annotated queryset returns correct data when I printed it out, but somehow the template for loop is not retrieving the data on the html page. Can someone please advise me on how to fix this issue? Thanks.
VIEWS.PY
from django.shortcuts import render
from django.views.generic import (TemplateView,ListView,
DetailView,CreateView,
UpdateView,DeleteView)
from django.urls import reverse_lazy
from myapp.models import Pastry
from myapp.forms import PastryForm
from django.db.models import F
This line ps = Pastry.objects.values('pastry').annotate(total=Count('pastry')) returns correct data:
{'pastry': 'Brownie', 'total': 1}
{'pastry': 'Cake', 'total': 1}
{'pastry': 'Cupcake', 'total': 1}
{'pastry': 'Fruit Tart', 'total': 1}
{'pastry': 'Muffin', 'total': 2}
class PollsListView(ListView):
model = Pastry
def get_queryset(self):
return Pastry.objects.all()
class PollsDetailView(DetailView):
model = Pastry
class PollsCreateView(CreateView):
success_url = reverse_lazy('pastry_list')
form_class = PastryForm
model = Pastry
class PollsUpdateView(UpdateView):
success_url = reverse_lazy('pastry_list')
form_class = PastryForm
model = Pastry
class PollsDeleteView(DeleteView):
model = Pastry
success_url = reverse_lazy('pastry_list')
pastry_list.html (template)
{% extends "base.html" %}
{% block content %}
<div class="jumbotron">
New Poll
<h1>Voting for the favorite pastry</h1>
Somehow this code here is not displaying any data.
{% for p in ps %}
{% for k, v in p.items %}
{{k}}{{v}}
{% endfor %}
{% endfor %}
{% for pastry in pastry_list %}
<div class="pastry">
<h3><a href="{% url 'pastry_detail' pk=pastry.pk %}">
{{ pastry.pastry }}</a></h3>
</div>
{% endfor %}
</div>
{% endblock %}
More info can be found in the Documentation
Basically, you can send more variables to template via get_context_data() method
Sample:
class PollsListView(ListView):
model = Pastry
def get_queryset(self):
return Pastry.objects.all()
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['ps'] = = Pastry.objects.values('pastry').annotate(total=Count('pastry'))
return context
With get_context-data(), your variable ps is available in the template pastry_list.html

"This field is required" when field is populated on Django modelForm

After clicking the upload button on a form I get a bullet point beneath the 'Job ID' field stating "This field is required." even though I have values enterred into the field. Here is my code:
forms.py:
class UploadFileForm(forms.ModelForm):
class Meta:
model = Job
fields = ['jobID',
'original_file']
labels = { 'jobID': _('Job ID'),
'original_file': _('File'),}
error_messages = {
'jobID': {'max_length': _("Job ID is limited to 50 characters."),
},
NON_FIELD_ERRORS: {
'unique_together': "%(model_name)s's %(field_labels)s are not unique.",
}
}
models.py:
from __future__ import unicode_literals
from django.db import models
from django.utils import timezone
class Job(models.Model):
user = models.ForeignKey('auth.User')
original_file = models.FileField()
jobID = models.CharField(max_length=50)
rev = models.IntegerField()
create_date = models.DateTimeField(default = timezone.now)
def save(self):
"Get last value of rev considering jobID and User and increment"
"see https://stackoverflow.com/questions/1065089/auto-increment-a-value-in-django-with-respect-to-the-previous-one"
last_rev = Job.objects.filter(user=self.user).filter(jobID=self.jobID).order_by('-rev')
if last_rev:
rev = last_rev[0].rev + 1
else:
rev = 1
super(Job,self).save()
def __unicode__(self):
return self.jobID + " rev " + str(self.rev)
class Meta:
indexes = [
models.Index(fields=['user','jobID']),
]
unique_together = ("user","jobID","rev")
ordering = ['-create_date']
views.py
from __future__ import unicode_literals
from django.shortcuts import render
from django.http import HttpResponseRedirect
from .forms import UploadFileForm
from .models import Job
# Create your views here.
def upload(request):
if request.method == 'POST':
form = UploadFileForm(request.POST, request.FILES)
if form.is_valid():
form.save()
return render(request,'precheck/prestage.html')
else:
form = UploadFileForm()
return render(request, 'precheck/upload.html',{'form': form})
def success(request):
return render(request, 'precheck/prestage.html')
upload.html
{% extends 'base.html' %}
{% block content %}
<h2>Upload File</h2>
{% if error %}
{{ error }}
<br />
<br />
{% endif %}
<form method = "POST" action="{% url 'precheck:upload' %}">
{% csrf_token %}
{{ form.as_p }}
<br />
<input type="submit" class="btn btn-primary" value="Upload">
</form>
{% endblock %}
I tried manually building the form (ie not using a modelform) with the same results. Thanks for the help.
EDIT:
Changing the form to include enctype="multipart/form-data" did the trick:
<form method = "POST" action="{% url 'precheck:upload' %}" enctype="multipart/form-data">
The error is not for jobID, but for original_file. This is because you are not using the enctype="multipart/form-data" attribute on the form element.

Categories