Creating an admin panel for Django site - python

What I would like to have is an admin panel that I create where only users with permissions set to "admin" in the UserLevel model can edit certain aspects of the website. However, while I think I have everything coded out properly it isn't working. The way I'm trying to implement this already work on the main content section of my site. My best guess is that since I'm trying to cross-use views between apps something got mixed up, although that may be wrong. Also please keep in mind that while I definitely started with clean code which emulated the code from the working parts of the site this code may not so clean because I have been playing around with it so much that I'm just flat out confused... so any help would be much appreciated.
To be clear, there's no error with the site which is why I think the code is written correctly. However, I made a test widget which is not displaying on the home page at all (it's supposed to), nor will it display on the admin panel page I setup (which is supposed to display any widgets there may be), and I can't get the form for adding a new widget to display on the admin panel page either (it gives me a button to go to another page that has the form on it).
Project urls.py:
"""colors URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/1.11/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: url(r'^$', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.conf.urls import url, include
2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls'))
"""
from django.conf.urls import url
from django.contrib import admin
from django.conf.urls import include
from accounts import views
from colorsets import views
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^$',views.PostListView.as_view(),name='index'),
url(r'^accounts/',include('accounts.urls',namespace='accounts')),
url(r'^colorsets/',include('colorsets.urls',namespace='colorsets')),
url(r'^adminpanel/',include('adminpanel.urls',namespace='adminpanel')),
]
Adminpanel app urls.py:
from django.conf.urls import url
from adminpanel import views
app_name = 'adminpanel'
urlpatterns = [
url(r'^settings/',views.SettingsListView.as_view(),name='settings'),
url(r'^new/$',views.CreateWidgetView.as_view(),name='create-widget'),
url(r'^delete/$',views.DeleteWidget.as_view(),name='delete-widgets'),
]
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):
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)
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 (Where I started mixing things):
from django.shortcuts import render
from colorsets.forms import ColorForm
from colorsets import models
from colorsets.models import ColorSet
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.
#def index(request):
# return render(request,'index.html')
class PostListView(ListView):
model = ColorSet
model = Widget
def get_queryset(self):
return ColorSet.objects.filter(published_date__lte=timezone.now()).order_by('-published_date')
return Widget.objects.filter(order_by('widget_order'))
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 models.py:
from django.db import models
# Create your models here.
class Widget(models.Model):
name = models.CharField(max_length=50)
widget_order = models.IntegerField(default=0)
body = models.TextField(max_length=500)
def __str__(self):
return self.name
widget_list.html:
{% extends "base.html" %}
{% block content %}
<div class="container">
<div class="content">
{% for widget in widget_list %}
<p>{{ widget.body }}</p>
{% endfor %}
</div>
</div>
{% endblock %}
_post.html:
<div class="post media">
<div class="media-body">
<strong>{{ colorset.user.username }}</strong>
<div class="media-footer">
{% if user.is_authenticated and UserLevels.access_level == 'admin' %}
<a href="{% url 'colorsets:delete' pk=colorset.pk %}" title="delete" class="btn btn-simple">
Delete
</a>
{% endif %}
</div>
</div>
</div>
widget_form.html:
{% 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 %}
settings.html:
{% extends "base.html" %}
{% block content %}
<div class="container">
<h2>Settings:</h2>
</div>
{% endblock %}
widget_confirm_delete.html:
{% extends 'base.html' %}
{% block content %}
<h3>Are you sure you want to delete this widget?</h3>
<div class="posts">
{% include "adminpanel/_post.html" with post=object hide_delete=True %}
</div>
<form method="POST">
{% csrf_token %}
<input type="submit" value="Confirm Delete" class="btn btn-danger btn-large" />
<a class="btn btn-simple btn-large" href="{% url 'adminpanel/settings'%}">Cancel</a>
</form>
{% endblock %}
I know not everything is being used by things but this is everything I have.

Related

How to get to another page after saving form by CreateView

I wan't to get to order_list page after adding new order.
Was trying both reverse and reverse_lazy method also just to set page adres value to success_url directly like success_url = 'orders/order_list' or sucess url = 'order_list' but it always returns me Http 405 error.
views.py
django.shortcuts import render
from django.urls import reverse_lazy
from django.views import View
from django.views.generic import ListView, DetailView, CreateView
from django.http import HttpResponse, HttpResponseRedirect
from django.contrib.auth.mixins import PermissionRequiredMixin, LoginRequiredMixin
from .models import Order
from .forms import CreateOrder
from django.contrib.auth.decorators import login_required
# Create your views here.
class OrderCreateView(LoginRequiredMixin, PermissionRequiredMixin, CreateView):
login_url = '/login_required'
permission_required = 'orders.add-order'
model = Order
success_url = reverse_lazy('orders:order_list')
fields = ['airport', 'direction', 'adress', 'client', 'telephone', 'flight_number', 'plane', 'pick_up', 'gate', 'driver']
urls.py
from django.contrib import admin
from django.urls import path
from django.contrib.auth import views as auth_views
from orders.views import OrderCreateView, OrderListView, AboutView, LoginRequiredView
urlpatterns = [
path('admin/', admin.site.urls),
path('add_order/', OrderCreateView.as_view(template_name="orders/add_order.html"), name="add_order"),
path('order_list/', OrderListView.as_view(), name="order_list"),
path('login/', auth_views.LoginView.as_view(template_name="pages/login.html"), name="login"),
path('logout/', auth_views.LogoutView.as_view(template_name="pages/logout.html"), name="logout"),
path('about/', AboutView.as_view(), name="about"),
path('login_required/', LoginRequiredView.as_view(), name='login_required')
]
add_order.html
{% extends 'base.html' %}
{% load static %}
{% load crispy_forms_tags %}
{% block content %}
<div class="container" style="width: 40%; height: 80%;">
<div class="page header">
<h1>Add new order</h1>
</div>
<form action="/order_list/" method="post">
{% csrf_token %}
{{ form|crispy }}
<button type="submit" class="btn btn-success">Save order</button>
</form>
</div>
{% endblock %}
Any ideas what am I doing wrong ?
Change:
success_url = reverse_lazy('orders:order_list')
To:
success_url = reverse_lazy('order_list')
And change:
<form action="/order_list/" method="post">
To:
<form action="/add_order/" method="post">
Note: You are using hardcoded URL which is not recommended. Use the url template tag.

How does Django choose template name for CreateView when I don’t specify it

How does the CreatePostView in views.py link to the post_form.html.
It does not have "template_name" in it still how does the createpostview links to the post_form.html?
Please look into the following codes that i have added below, and let me know if you can help, Thankyou!
Views.py
from django.shortcuts import render, get_object_or_404, redirect
from django.contrib.auth.decorators import login_required
from django.utils import timezone
from .models import Post, Comment
from .forms import PostForm, CommentForm
from django.views.generic import (TemplateView,ListView,
DetailView,CreateView,
UpdateView,DeleteView)
from django.urls import reverse_lazy
from django.contrib.auth.mixins import LoginRequiredMixin
class CreatePostView(LoginRequiredMixin,CreateView):
login_url = '/login/'
redirect_field_name = 'blog/post_detail.html'
form_class = PostForm
model = Post
urls.py
from django.urls import path
from . import views
urlpatterns = [
path('post/new/', views.CreatePostView.as_view(), name='post_new'),
]
post_form.html
{% extends 'blog/base.html' %}
{% block content %}
<h1>New post</h1>
<form method="POST" class="post-form">
{% csrf_token %}
{{form.as_p}}
<button type="submit" class="save btn btn-default">Save</button>
</form>
<script>var editor = new MediumEditor('.editable');</script>
{% endblock %}
Please help me understand this.
For a model Post in app myapp, the CreateView will use the template myapp/post_form.html.
This is just the documented behaviour of CreateView.
You might find it useful to look at the get_template_names method on the ccbv website to understand how the code works.

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)

Why won't my server start running?

Why am I getting an error when trying to run my server to access the database to see if my code works? While in my projects folder in Terminal, I ran sudo python manage.py runserver to try to run the server but it doesn't work because of the aforementioned error. I've looked around SO but can't find one directly related to my problem.
I'm guessing my if() statement is the problem.
The error I'm getting says:
RuntimeError: maximum recursion depth exceeded while calling a Python object
Here's my views.py file:
from .models import Album
from django.shortcuts import render, redirect
from django.contrib.auth import authenticate, login
from django.core.urlresolvers import reverse_lazy
from django.views import generic
from django.views.generic import View
from django.views.generic.edit import CreateView, UpdateView, DeleteView
from .forms import UserForm
class IndexView(generic.ListView):
template_name = 'music/index.html'
context_object_name = 'all_albums'
def get_queryset(self):
return Album.objects.all()
class DetailView(generic.DeleteView):
model = Album
template_name = 'music/detail.html'
class AlbumCreate(CreateView):
model = Album
fields = ['artist', 'album_title', 'genre', 'album_logo']
class AlbumUpdate(UpdateView):
model = Album
fields = ['artist', 'album_title', 'genre', 'album_logo']
class AlbumDelete(DeleteView):
model = Album
success_url = reverse_lazy('music:index')
class UserFormView(View):
form_class = UserForm
template_name = 'music/registration_form.html'
# display blank form
def get(self, request):
form = self.form_class(None)
return render(request, self.template_name, {'form': form})
def post(self):
form = self.form_class(request.POST)
if form.is_valid():
user = form.save(commit=False)
#cleaned normalized data
username = form.cleaned_data['username']
password = form.cleaned_data['password']
user.set_password(password)
user.save()
Here's the error:
File "/Library/Python/2.7/site-packages/Django-1.11.2-py2.7.egg/django/urls/resolvers.py", line 255, in check
warnings.extend(check_resolver(pattern))
File "/Library/Python/2.7/site-packages/Django-1.11.2-py2.7.egg/django/core/checks/urls.py", line 26, in check_resolver
return check_method()
File "/Library/Python/2.7/site-packages/Django-1.11.2-py2.7.egg/django/urls/resolvers.py", line 172, in check
warnings = self._check_pattern_startswith_slash()
File "/Library/Python/2.7/site-packages/Django-1.11.2-py2.7.egg/django/urls/resolvers.py", line 140, in _check_pattern_startswith_slash
regex_pattern = self.regex.pattern
Here's my forms.py file:
from django.contrib.auth.models import User
from django import forms
class UserForm(forms.ModelForm): # UserForm inherits from forms.
passwords = forms.CharField(widget=forms.PasswordInput)
class Meta: # Information about your class.
model = User # whenevr a creates sign up to your site it's gonna go in same table
fields = ['username', 'email', 'password']
Here's my urls.py file:
from django.conf.urls import include, url
from django.contrib import admin
from django.conf import settings
from django.conf.urls.static import static
app_name = 'music'
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^music/', include('music.urls'))
]
if settings.DEBUG:
urlpatterns += static(settings.STATIC_URL, document_root = settings.STATIC_ROOT)
urlpatterns += static(settings.STATIC_URL, document_root=settings.MEDIA_ROOT)
Here's my album_form.html file:
{% extends 'music/base.html' %}
{% block title %}Add a New Album{% endblock %}
{% block album_active %}active{% endblock %}
{% block body %}
<div class="container-fluid">
<div class="row">
<div class="col-sm-12 col-md-7">
<div class="panel panel-default">
<div class="panel-body">
<form class="horizontal" action="" method="post" enctype="multipart/form-data">
{% csrf_token %}
{% include 'music/form-template.html' %}
<div class="form-group">
<div class="col-sum-offset-2 col-sm-10">
<button type="submit" class="btn btn-success">Submit</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
Here's my index.html file:
{# loads path to static file #}
{% extends 'music/base.html' %}
{% block body %}
<ul>
{% for album in all_albums %}
<li>{{ album.album_title }}</li>
{% endfor %}
</ul>
{% endblock %}
I suspect you have a recursive reference from your include in music.urls to urls.py since the error that django throws is specific to URL resolver.
Your if statement has no error. 'music:index' refers to namespaced url names and still need named url statements in urls.py. Since in simple projects, there is only one application, the namespace is redundant. So in most cases, 'index' should be used instead, just like what I have show below.
In your urls.py, there is a include to music.urls, and it seems to be recursive reference to itself. 'music.urls' refers to the file urls.py in music directory.
If you do not have a valid python object for 'music.urls', then your include statement is wrong.
I do not use include urls in my project, so there will need to be a statement for each view defined in views.py. To test whether your server starts correctly, I would try the following urlpatterns. Don't forget to import IndexView and DetailView. Add more url statements for you other views after testing out 1 or 2 first.
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^music/index/$', IndexView.as_view() , name='Index'),
url(r'^music/detail/(?P<pk>[0-9]+)/$', DetailView.as_view() , name='Detail'),
]
I use named url, and the statement in index.html should be written as follows:
{{ album.album_title }}
The namespace 'music:' is omitted since it is implicit and will look simpler. You should leave it out for simple applications as it may be confusing for beginners.

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