Django Getting PK from Createview - python

I am creating a blog post with a specific primary key (pk). My other function requires to have the pk as an input (please check the views.py). I am trying to get the post id by getting it as an object id, although it indicated that object has no attribute 'id'.
Any ideas how to get pk as a variable?
Thanks,
Ted
#The template
{% extends "Blog/base.html" %}
{% load crispy_forms_tags %}
{% block content%}
<div class="content-section">
<form method = "POST">
{% csrf_token %}
<fieldset class="form-group">
<legend class="border-bottom mb-4"> Blog Post </legend>
{{ form|crispy }}
</fieldset>
<div class="form-group">
<button class="btn btn-outline-info" type="submit">Post</button>
</div>
</form>
</div>
{% endblock content%}
#urls.py
from django.urls import path
from .views import PostListView, PostDetailView, PostCreateView, PostUpdateView, PostDeleteView
from . import views
urlpatterns = [
path('post/<int:pk>/', PostDetailView.as_view(), name='post-detail'),
path('post/new', PostCreateView.as_view(), name='post-create'),
]
#views.py
from django.shortcuts import render
from django.views.generic import (
ListView,
DetailView,
CreateView,
UpdateView,
DeleteView
)
from .models import Post
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
from .latex import tex
from django.http import FileResponse, Http404
from django.urls import reverse
class PostCreateView(LoginRequiredMixin, CreateView):
model = Post
fields = ['first_name', 'last_name', 'titles' ,'title', 'content', 'billing']
def form_valid(self, form):
form.instance.author = self.request.user # Use this to get the information from the form.
pk = self.object.id
self.external(pk)
return super().form_valid(form),
#Error which I am getting
'NoneType' object has no attribute 'id'

You can obtain the object through the instance wrapped in the form. But as long as the object is not saved, it has no primary key.
class PostCreateView(LoginRequiredMixin, CreateView):
model = Post
fields = ['first_name', 'last_name', 'titles' ,'title', 'content', 'billing']
def form_valid(self, form):
form.instance.author = self.request.user
response = super().form_valid(form)
pk = form.instance.pk
self.external(pk)
return response

Related

Page not found (404) No comment found matching the query

views.py
class CommentCreatView(LoginRequiredMixin, CreateView):
model = Comment
fields = ['text']
template_name = 'home/add-comment.html'
success_url = 'homepage'
def form_valid(self,form):
form.instance.user = self.request.user
post = self.get_object()
form.instance.post = post
return super().form_valid(form)
urls.py
from django.urls import path
from . import views
from django.conf import settings
from django.conf.urls.static import static
from .views import PostCreateView, PostsListView, PostDetailView, CommentCreatView
urlpatterns = [
path('', PostsListView.as_view(), name='homepage'),
path('post/<int:pk>/', PostDetailView.as_view(), name='post-and-comments'),
path('post/<int:pk>/comment', CommentCreatView.as_view(), name='add-comment'),
path('creat', PostCreateView.as_view(), name='creat-post')
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
add-comment.html
{% extends "home/base.html" %}
{% load crispy_forms_tags %}
<!-- allow us to use crispy filter on any of our forms -->
{% block content %}
<div class="content-section">
<form method="POST">
<!--this method post is to protect our form fromcertain attacks -->
{% csrf_token %}
{{form|crispy}}
<button class="btn btn-outline-danger mt-1 mb-1 mr-1 ml-1" type="submit">Add Comment</button>
</div>
</form>
</div>
{% endblock content %}
So I opens it home/post/6/comment , I see the form and when I submit it. I get this error and the comment isnt saved error screenshot
The .get_object(…) [Django-doc] method will try to find a Comment with as primary key the one you specified in the path (here 6). You do not want to find a comment but the Post with that primary key. You thus should rewrite this to:
class CommentCreatView(LoginRequiredMixin, CreateView):
model = Comment
fields = ['text']
template_name = 'home/add-comment.html'
success_url = 'homepage'
def form_valid(self,form):
form.instance.user = self.request.user
form.instance.post_id = self.kwargs['pk']
return super().form_valid(form)

ValueError at /create_entry/

Can someone help me to solve this error?
ValueError at /create_entry/
Cannot assign "<SimpleLazyObject: <django.contrib.auth.models.AnonymousUser object at 0x000000B7BBF1BFC8>>": "Entry.entry_author" must be a "User" instance.
urls.py
from django.urls import path
from .views import HomeView, EntryView, CreateEntryView
urlpatterns = [
path('', HomeView.as_view(), name = 'blog-home'),
path('entry/<int:pk>/', EntryView.as_view(), name = 'entry-detail'),
path('create_entry/', CreateEntryView.as_view(success_url='/'), name = 'create_entry')
]
views.py
from django.shortcuts import render
from django.views.generic import ListView, DetailView, CreateView
from .models import Entry
class HomeView(ListView):
model = Entry
template_name = 'entries/index.html'
context_object_name = "blog_entries"
class EntryView(DetailView):
model = Entry
template_name = 'entries/entry_detail.html'
class CreateEntryView(CreateView):
model = Entry
template_name = 'entries/create_entry.html'
fields = ['entry_title', 'entry_text']
def form_valid(self,form):
form.instance.entry_author = self.request.user
return super().form_valid(form)
models.py
from django.db import models
from django.contrib.auth.models import User
class Entry(models.Model):
entry_title=models.CharField(max_length=50)
entry_text=models.TextField()
entry_date=models.DateTimeField(auto_now_add=True)
entry_author=models.ForeignKey(User, on_delete=models.CASCADE)
class Meta:
verbose_name_plural = "entries"
def __str__(self):
return f'{self.entry_title}'
create_entry.html
{% extends "entries/base.html" %}
{% block content %}
<div class="col-md-8"><br><br>
<!-- Blog Post -->
<div class="card mb-4">
<div class="card-header">
Create Blog Post
</div>
<div class="card-body">
<form class="form-conrol" action="" method="post">
{% csrf_token %}
{{form.as_p}}
<button type="submit" class="btn btn-primary">Post Entry</button>
</form>
</div>
</div>
</div>
{% endblock %}
I need your help for this
small project.
You are not logged in, so self.request.user is not a real user. You can use the LoginRequiredMixin [Django-doc] to restrict access to a view such that you can only post (and retrieve) the view when the user has logged in:
from django.contrib.auth.mixins import LoginRequiredMixin
class CreateEntryView(LoginRequiredMixin, CreateView):
model = Entry
template_name = 'entries/create_entry.html'
fields = ['entry_title', 'entry_text']
def form_valid(self,form):
form.instance.entry_author = self.request.user
return super().form_valid(form)

FieldError at /post/new/ on executing url: <http://localhost:8000/post/new/>

I'm using Django 3.0.8
in Python version 3.8.2
I'm getting an FieldError at /post/new/
Exception Type: FieldError
Exception Value: Unknown field(s) (content) specified for Post
PostCreateView is a class-based view in my views.py of under the blog app of my current project
My blog/views.py is here:-
from django.shortcuts import render
from .models import Post
from django.views.generic import (
ListView,
DetailView,
CreateView,
)
# Create your views here.
def home(request):
context = {
'posts': Post.objects.all()
}
return render(request, 'blog/home.htm', context)
def about(request):
return render(request, 'blog/about.htm', {'title': 'About'})
# return HttpResponse('<h1> Blog - About page that we want you to see </h1>')
def order(request):
return render(request, 'blog/order.htm')
class PostListView(ListView):
model = Post
template_name = 'blog/home.htm' # <app>/<model>_<viewtype>.html
context_object_name = 'posts'
ordering = ['-date_posted']
class PostDetailView(DetailView):
model = Post
class PostCreateView(CreateView):
model = Post
fields = ['title', 'content']
My blog/urls.py is here:
from django.urls import path
from . import views
from .views import (
PostListView,
PostDetailView,
PostCreateView
)
urlpatterns = [
path('about/', views.about, name='blog-about'),
path('order/', views.order, name='blog-order'),
path('', PostListView.as_view(), name='blog-home' ),
path('post/<int:pk>/', PostDetailView.as_view(), name='post-detail' ),
path('post/new/', PostCreateView.as_view(), name='post-create' ),
]
My blog/templates/blog/post_form.html is here:-
{% extends "blog/base.htm" %}
{% load crispy_forms_tags %}
{% block content %}
<div class="context-section">
<form method="POST">
{% csrf_token %} <!-- for security perpose -->
<fieldset class="form-group">
<legend class="boder-bottom mb-4">Blog Post</legend>
{{ form|crispy }}
</fieldset>
<div class="form-group">
<button class="btn btn-outline-info" type="submit">Post</button>
</div>
</form>
</div>
{% endblock content %}
What wrong is with the code, Please help!!!
I am new to Django and I am completely lost-in here?
I will be very much thankful for your suggestions!!
Thanks and Wellcome

Getting forms to display in HTML with Django

so I've gotten forms to display correctly before, I'm just a little lost as to why I am using certain words when doing so, and I'm wondering why I've used different words to get different forms to display.
In this first example (colorist_form.html) I am using {{ form }} which does get the form to display
{% extends "base.html" %}
{% block content %}
<div class="colorset-base">
<h2>Create new post</h2>
<p class="hint">Add hex codes for each color you would like to include.</p>
<form id="postForm" action="{% url 'colorsets:new_color' %}" method="POST">
{% csrf_token %}
{{ form }}
<button type="submit" class="submit btn btn-primary btn-large">Add Color Set</button>
</form>
</div>
{% endblock %}
However, in this example (widget_form.html) I am using the same {{ form }} but now the form does not display
{% block content %}
<div class="colorset-base">
<h2>Create new widget</h2>
<form id="postForm" action="{% url 'adminpanel:create-widget' %}" method="POST">
{% csrf_token %}
{{ form }}
<button type="submit" class="submit btn btn-primary btn-large">Add Widget</button>
</form>
</div>
{% endblock %}
Also in my register.html I am using {{ user_form }} which does get the form to display.
{% extends "base.html" %}
{% block content %}
<div class="form-base">
{% if registered %}
<h1>Thank you for registering!</h1>
{% else %}
<h2>Register</h2>
<form method="POST">
{% csrf_token %}
{{ user_form }}
<input type="submit" value="Register" />
</form>
{% endif %}
</div>
{% endblock %}
Why do I use the keyword "form" vs some other word such as "user_form" or "widget_form"? And why won't the widget_form.html display the form?
Here is my code for the forms and views respectively:
adminpanel app views.py:
from django.shortcuts import render
from adminpanel.forms import WidgetForm
from adminpanel.models import Widget
from django.utils import timezone
from django.contrib.auth import authenticate,login,logout
from django.http import HttpResponseRedirect, HttpResponse
from django.core.urlresolvers import reverse,reverse_lazy
from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin
from braces.views import SelectRelatedMixin
from django.views.generic import (TemplateView,ListView,
DetailView,CreateView,
UpdateView,DeleteView)
# Create your views here.
class CreateWidgetView(LoginRequiredMixin,CreateView):
login_url = '/login/'
redirect_field_name = 'index.html'
form_class = WidgetForm
model = Widget
def form_valid(self,form):
self.object = form.save(commit=False)
self.object.save()
return super().form_valid(form)
class SettingsListView(ListView):
model = Widget
def get_query(self):
return Widget.object.filter(order_by('widget_order'))
class DeleteWidget(LoginRequiredMixin,SelectRelatedMixin,DeleteView):
model = Widget
select_related = ('Widget',)
success_url = reverse_lazy('settings')
def get_queryset(self):
queryset = super().get_query()
return queryset.filter(user_id=self.request.user.id)
def delete(self):
return super().delete(*args,**kwargs)
colorsets app views.py:
from django.shortcuts import render
from colorsets.forms import ColorForm
from colorsets import models
from colorsets.models import ColorSet
from django.utils import timezone
from django.contrib.auth import authenticate,login,logout
from django.http import HttpResponseRedirect, HttpResponse
from django.core.urlresolvers import reverse,reverse_lazy
from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin
from braces.views import SelectRelatedMixin
from django.views.generic import (TemplateView,ListView,
DetailView,CreateView,
UpdateView,DeleteView)
# Create your views here.
#def index(request):
# return render(request,'index.html')
class PostListView(ListView):
model = ColorSet
def get_queryset(self):
return ColorSet.objects.filter(published_date__lte=timezone.now()).order_by('-published_date')
class CreateColorSetView(LoginRequiredMixin,CreateView):
login_url = '/login/'
redirect_field_name = 'index.html'
form_class = ColorForm
model = ColorSet
def form_valid(self,form):
self.object = form.save(commit=False)
self.object.user = self.request.user
self.object.save()
return super().form_valid(form)
class DeletePost(LoginRequiredMixin,SelectRelatedMixin,DeleteView):
model = models.ColorSet
select_related = ('user',)
success_url = reverse_lazy('index')
def get_queryset(self):
queryset = super().get_queryset()
return queryset.filter(user_id=self.request.user.id)
def delete(self,*args,**kwargs):
return super().delete(*args,**kwargs)
adminpanel app forms.py:
from django import forms
from adminpanel.models import Widget
class WidgetForm(forms.ModelForm):
class Meta():
model = Widget
fields = ('name','widget_order','body')
widgets = {
'name':forms.TextInput(attrs={'class':'text-input'}),
'body':forms.Textarea(attrs={'class':'text-area'}),
}
colorsets app forms.py:
from django import forms
from colorsets.models import ColorSet
class ColorForm(forms.ModelForm):
class Meta():
model = ColorSet
fields = ('name','color_one','color_two','color_three','color_four','color_five')
widgets = {
'name':forms.TextInput(attrs={'class':'colorset-name'}),
'color_one':forms.TextInput(attrs={'class':'colorset-color'}),
'color_two':forms.TextInput(attrs={'class':'colorset-color'}),
'color_three':forms.TextInput(attrs={'class':'colorset-color'}),
'color_four':forms.TextInput(attrs={'class':'colorset-color'}),
'color_five':forms.TextInput(attrs={'class':'colorset-color'}),
}
Not sure that all that code was needed for this problem but figured it couldn't hurt.
I'm a little lost (even though I've gotten this to work in the past) so any help would be most appreciated.
If you use create view you don't have to write the form, automatically Django generate the modelform so should be something like:
class CreateWidgetView(LoginRequiredMixin,CreateView):
login_url = '/login/'
redirect_field_name = 'index.html'
model = Widget
fields = ['field', 'field2']
def form_valid(self,form): #I Think this part is not neccesary
self.object = form.save(commit=False)
self.object.save()
return super().form_valid(form)

Django form not passing is_valid() test

In my Django app in a Createview class it never enters the is_valid(): statement and I can not seem to find any errors:
models.py
from django.db import models
from django.core.urlresolvers import reverse
from django.contrib.auth.models import User
from django.conf import settings
from .validators import validate_file_extension
import zipfile
class Post(models.Model):
title = models.CharField(max_length=140)
body = models.TextField(max_length=250)
date = models.DateTimeField(auto_now=True, auto_now_add=False)
album_image = models.FileField(validators=[validate_file_extension])
user = models.ForeignKey(User, default=1)
face = models.IntegerField(default=1)
def get_absolute_url(self):
return reverse('photos:detail',kwargs={'pk':self.pk})
def __str__(self):
return self.title
views.py
This is my view folder that contains a list view a detailed view and create view. Although the form doesnt pass the valid test, it still gets uploaded and is viewable by the user
from django.http import Http404
from django.http import HttpResponse
from django.shortcuts import render, get_object_or_404
from django.core.urlresolvers import reverse
from .forms import PostForm
from .models import Post
from django.contrib.auth.models import User
from django.template import loader
from django.views import generic
from django.views.generic.edit import CreateView
import cognitive_face as CF
import json
class IndexView(generic.ListView):
template_name='photos/post.html'
def get_queryset(self):
return Post.objects.filter(user=self.request.user)
class DetailView(generic.DetailView):
model = Post
template_name = 'photos/detail.html'
class PostCreate(generic.CreateView):
form = PostForm()
model = Post
if form.is_valid():
print('valid')
instance = form.save(commit=False)
username = form.cleaned_data['username']
album_image = form.cleaned_data['album_image']
instance.save()
if not form.is_valid():
print('not')
post_form.html
<html>
<body>
{% if request.user.is_authenticated%}
<h3>Hello {{request.user.username}}, please upload your image as either a .JPEG, .GIF or .PNG</h3>
{% endif %}
<div class="container-fluid">
<div class="row">
<div class="col-sm-12 col-md-7">
<div class="panel panel-default">
<div class="panel-body">
{% if request.user.is_authenticated %}
<form class="form-horizontal" role="form" action="" method="post" enctype="multipart/form-data">
{% csrf_token %}
{{form.as_p}}
{{ form.errors }}
{{ form.non_field_errors }}
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-success">Submit</button>
</div>
</div>
</form>
{% else %}
<p>You must be logged in to upload a file</p>
{% endif %}
</div>
</div>
</div>
</body>
</html>
urls.py
from django.conf.urls import url, include
from django.views.generic import ListView, DetailView
from photos.models import Post
from . import views
app_name = 'photos'
urlpatterns = [
url(r'^$',views.IndexView.as_view(), name='index'),
url(r'^(?P<pk>[0-9]+)/$',views.DetailView.as_view(), name='detail'),
url(r'post/add/$', views.PostCreate.as_view(), name='post-add'),
]
You are writing function based view code inside a class based view, which is incorrect.
You shouldn't need to instantiate the form, or manually check whether it is valid. Just set form_class for the view, then override form_valid or form_invalid if you need to change the behaviour when the form is valid or invalid. Since you have {{ form.errors }} in your template, it should show any errors when you submit the form.
class PostCreate(generic.CreateView):
form_class = PostForm
model = Post
See the docs on form handling with class based views for more information. You might find it easier to write a function based view to begin with, since the flow of the code is easier to follow.

Categories