I have built a blog project and I can't access the PostCreateView for some unknown reason.
I keep getting Page 404 error although I have in the urls patterns
I am also getting the error raised by
score.views.PostDetailView
Here is the views.py
class PostCreateView(LoginRequiredMixin, SuccessMessageMixin, CreateView):
model = Post
fields = ['title', 'design']
template_name = "post_form.html"
success_url = "/score/"
success_message = "Your Post has been submitted"
def form_valid(self, form):
form.instance.designer = self.request.user
return super().form_valid(form)
here is the PostDetail Views.py
class PostDetailView(DetailView):
model = Post
template_name = "post_detail.html"
def get_context_data(self, *args, **kwargs):
context = super(PostDetailView, self).get_context_data()
post = get_object_or_404(Post, slug=self.kwargs['slug'])
total_likes = post.total_likes()
liked = False
if post.likes.filter(id=self.request.user.id).exists():
liked = True
context["total_likes"] = total_likes
context["liked"] = liked
return context
Here is the Urls.py
app_name = 'score'
urlpatterns = [
path('', PostListView.as_view(), name='score'),
path('<slug:slug>/', PostDetailView.as_view(), name='post-detail'),
path('new/', PostCreateView.as_view(), name='post-create'),
path('user/<str:username>', UserPostListView.as_view(), name='user-posts'),
]
here is the nav bar html that is taking me to the page
<a class="nav-link waves-effect" href="{% url 'score:post-create' %}" >Upload Post</a>
here is the post_form template
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
<fieldset class="form-group">
<legend class="border-bottom mb-4" style="padding-top: 20px;">Upload Your Post</legend>
{{ form|crispy }}
</fieldset>
<div class="form-group">
<button class="btn btn-outline-info ml-0" type="submit">Upload</button>
</div>
</form>
The problem is that your <slug:slug> will capture values like new as well. So that path will "fire", and the view will find out that there is no Post object with 'new' as slug.
You can swap the path(…)s, but then you can never access a Post with as slug new. As a rule of thumb it is better to make path(…)s that are not overlapping, for example:
app_name = 'score'
urlpatterns = [
path('', PostListView.as_view(), name='score'),
path('post/<slug:slug>/', PostDetailView.as_view(), name='post-detail'),
path('new/', PostCreateView.as_view(), name='post-create'),
path('user/<str:username>', UserPostListView.as_view(), name='user-posts'),
]
Related
I'm working on Django blog, and I'm working on register form. I got error Page not found at /register/ like you can see on image. But it say that error was raised by post_detail - Raised by: my_blog.views.post_detail
This is register.html
{% extends "base.html" %}
{% load static %}
{% block content %}
{% load crispy_forms_tags %}
<!--Register-->
<div class="container py-5">
<h1>Register</h1>
<form method="POST">
{% csrf_token %}
{{ register_form|crispy }}
<button class="btn btn-primary" type="submit">Register</button>
</form>
<p class="text-center">If you already have an account, login instead.</p>
</div>
{% endblock %}
Views.py
def register_request(request):
if request.method == "POST":
form = NewUserForm(request.POST)
if form.is_valid():
user = form.save()
login(request, user)
messages.success(request, "Registration successful." )
return redirect("main:homepage")
messages.error(request, "Unsuccessful registration. Invalid information.")
form = NewUserForm()
return render (request=request, template_name="register.html", context={"register_form":form})
def post_detail(request, slug):
latest_posts = Post.objects.filter(created_at__lte=timezone.now()).order_by('created_at')[:9]
post = get_object_or_404(Post, slug=slug)
context = {'post': post, 'latest_posts': latest_posts}
return render(request, 'post_detail.html', context)
blog/urls.py
from . import views
from django.urls import path
urlpatterns = [
path('', views.home, name='home'),
path('<slug:slug>/', views.post_detail, name='post_detail'),
path('category/<slug:slug>/', views.category_detail, name='category_detail'),
path('register/', views.register_request, name='register'),
]
forms.py
class NewUserForm(UserCreationForm):
email = forms.EmailField(required=True)
class Meta:
model = User
fields = ("username", "email", "password1", "password2")
def save(self, commit=True):
user = super(NewUserForm, self).save(commit=False)
user.email = self.cleaned_data['email']
if commit:
user.save()
return user
I got this error and I don't understand why I get this error. Any ideas?
Thanks in advance!
"register" is a valid slug so the post_detail url is matching the incoming path as it's before your register url in urlpatterns.
The first option is to change post_detail to include a prefix so that it doesn't match your other urls
urlpatterns = [
path('', views.home, name='home'),
path('post/<slug:slug>/', views.post_detail, name='post_detail'),
path('category/<slug:slug>/', views.category_detail, name='category_detail'),
path('register/', views.register_request, name='register'),
]
Or you could put post_detail last so that other urls are matched first
urlpatterns = [
path('', views.home, name='home'),
path('category/<slug:slug>/', views.category_detail, name='category_detail'),
path('register/', views.register_request, name='register'),
path('<slug:slug>/', views.post_detail, name='post_detail'),
]
i want to create a todolist app with django.
i created a form for list model but when the user click on submit to submit a list, the form is'nt saved, why?
this is views.py
i have created an instance of the form and set the user field to it and then save the instance but fact it does'nt
def index(request):
if request.user.is_authenticated:
user_ = User.objects.get(username=request.user.username)
lists = user_.user.all()
form = listForm()
if request.method == "POST":
form = listForm(request.POST)
if form.is_valid():
instance = form.save(commit=False)
instance.user = request.user
instance.save()
return HttpResponseRedirect(reverse("index"))
context = {'lists':lists, 'form':form}
return render(request, 'todolists/index.html', context)
else:
return render(request, 'todolists/login.html')
this is index template
{% extends "todolists/layout.html" %}
{% block body %}
{% if user.is_authenticated %}
<div class="center-column">
<form method="POST" action="{% url 'index' %}">
{% csrf_token %}
{{form.title}}
<input type="submit" class="btn btn-info">
</form>
<div class="todo-list">
{% for list in lists %}
<div class="item-row">
<a class="btn btn-sm btn-info" href="{% url 'update' list.id %}">update</a>
<a class="btn btn-sm btn-danger" href="{% url 'update' list.id %}">delete</a>
<span>{{list}}</span>
</div>
{% endfor %}
</div>
</div>
{% endif %}
{% endblock %}
this is urls.py
from django.urls import path
from .import views
urlpatterns = [
path('', views.index, name='index'),
path('update/<str:id>/', views.update, name='update'),
path("login", views.login_view, name="login"),
path("logout", views.logout_view, name="logout"),
path("register", views.register, name="register"),
]
this is models.py
from django.db import models
from django.contrib.auth.models import AbstractUser
# Create your models here.
class User(AbstractUser):
pass
class list(models.Model):
title = models.CharField(max_length=200)
finished = models.BooleanField(default=False)
timestamps = models.DateTimeField(auto_now_add=True)
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="user")
def __str__(self):
return self.title
here is the form code
class listForm(forms.ModelForm):
title= forms.CharField(label=mark_safe("<span style='color:white;'>Title:</span>"),
widget= forms.TextInput(attrs={'placeholder':'Add new task...', 'class':'form-control'}))
finished= forms.BooleanField(label=mark_safe("<span style='color:white;'>Finished:</span>"),
widget= forms.CheckboxInput(attrs={'style':'width:25px;'}))
class Meta:
model = list
fields = '__all__'
Try updating your template file {{ form.title }} to {{ form }} as mentioned in django docs here is the link
Update your forms.py file if want only title field in the HTML
class listForm(forms.ModelForm):
title= forms.CharField(label=mark_safe("<span style='color:white;'>Title:</span>"),
widget= forms.TextInput(attrs={'placeholder':'Add new task...', 'class':'form-control'}))
class Meta:
model = list
fields = ('title', )
I am trying to use Ajax to submit a like button without getting the page refreshing, I have been getting several errors previously but now I am getting this error:
django.urls.exceptions.NoReverseMatch: Reverse for 'like_post' with arguments '('',)' not found. 1 pattern(s) tried: ['score/like/(?P<pk>[0-9]+)$']
I am not sure what is the reason. Need help to identify the error.
Here is the view:
class PostDetailView(DetailView):
model = Post
template_name = "post_detail.html"
def get_context_data(self, *args, **kwargs):
context = super(PostDetailView, self).get_context_data()
stuff = get_object_or_404(Post, id=self.kwargs['pk'])
total_likes = stuff.total_likes()
liked = False
if stuff.likes.filter(id=self.request.user.id).exists():
liked = True
context["total_likes"] = total_likes
context["liked"] = liked
return context
def LikeView(request, pk):
# post = get_object_or_404(Post, id=request.POST.get('post_id'))
post = get_object_or_404(Post, id=request.POST.get('id'))
like = False
if post.likes.filter(id=request.user.id).exists():
post.likes.remove(request.user)
like = False
else:
post.likes.add(request.user)
like = True
context["total_likes"] = total_likes
context["liked"] = liked
if request.is_ajax:
html = render_to_string('like_section.html', context, request=request)
return JsonResponse({'form': html})
Here is the url.py updated:
urlpatterns = [
path('user/<str:username>', UserPostListView.as_view(), name='user-posts'),
path('', PostListView.as_view(), name='score'),
path('who_we_Are/', who_we_are, name='who_we_are'),
path('<int:pk>/', PostDetailView.as_view(), name='post-detail'),
path('like/<int:pk>', LikeView, name='like_post'),
path('new/', PostCreateView.as_view(), name='post-create'),
path('<int:pk>/update/', PostUpdateView.as_view(), name='post-update'),
path('<int:pk>/delete/', PostDeleteView.as_view(), name='post-delete')
]
Here is the template:
<form class="mt-0" action="{% url 'score:like_post' post.pk %}" method='POST'>
{% csrf_token %}
<strong> Likes: {{total_likes}} </strong>
{% if user.is_authenticated %}
{% if liked %}
<button id='like' type='submit' name='post_id' class= "btn btn-danger btn-sm"
value="{{post.id}}"> Unlike </button>
{% else %}
<button id='like' type='submit' name='post_id' class= "btn btn-primary btn-sm"
value="{{post.id}}"> Like </button>
{% endif %}
{% else %}
<p><small> Login to Like </small></p>
{% endif %}
</form>
here is the ajax
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script type="text/javascript">
$(document).ready(function(event){
$(document).on('click','#like', function(event){
event.preventDefault();
$var pk= $(this).attr('value');
$.ajax({
type:'POST',
url:'{% url "score:like_post" post.pk %}', <---- Error in this line
data:{'id': pk, 'csrfmiddlewaretoken':'{{csrf_token}}'},
dataType:'json',
success:function(response){
$('#like-section').html(response['form'])
console.log($('#like-section').html(response['form']));
},
error:function(rs, e){
console.log(rs.responseText);
},
});
});
});
</script>
You need to send the post object in as context.
class PostDetailView(DetailView):
model = Post
template_name = "post_detail.html"
def get_context_data(self, *args, **kwargs):
context = super(PostDetailView, self).get_context_data()
post = get_object_or_404(Post, id=self.kwargs['pk'])
content["post"] = post
total_likes = post.total_likes()
liked = False
if post.likes.filter(id=self.request.user.id).exists():
liked = True
context["total_likes"] = total_likes
context["liked"] = liked
return context
I have a pretty simple contact us form but the success_url is not working. The page isn't getting redirected to home after successful form submission.
I've followed the documentation available here https://docs.djangoproject.com/en/1.10/topics/class-based-views/generic-editing/
class ContactFormView(SuccessMessageMixin, FormView):
form_class = ContactForm
template_name = 'contact.html'
success_message = 'Thank you!'
success_url = reverse_lazy('home')
def form_valid(self, form):
form.send_email()
return super(ContactFormView, self).form_valid(form)
form_valid is being called but redirection to sucess_url doesn't happen and there are no errors.
Thanks for your help.
-------------UPDATED-----------------
forms.py
class ContactForm(forms.Form):
name = forms.CharField(widget = TextInput(attrs={'placeholder': 'Your Name'}))
email = forms.CharField(widget = EmailInput(attrs={'placeholder': 'Email'}))
phone = forms.CharField(widget = TextInput(attrs={'placeholder': 'Phone'}))
comment = forms.CharField(widget = forms.Textarea(attrs={'placeholder': 'Please write a comment'}))
def send_email(self):
# send email using the self.cleaned_data dictionary
print("email sent!")
urls.py
import web.views
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^contact/', web.views.ContactFormView.as_view(), name='contact'),
url(r'^$', web.views.home, name='home')
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
contact.html
<div class="as-form">
<form method="post" class="myform" action="{% url 'contact' %}">
{% csrf_token %}
{% if form.errors %}{{ form.errors }}{% endif %}
<p> {{form.name}} </p>
<p> {{form.phone}} </p>
<p> {{form.email}} </p>
<p class="as-comment"> {{form.comment}} </p>
<hr>
<p class="as-submit"> <input type="submit" value="Submit" class="as-bgcolor"> </p>
</form>
</div>
I don't know how you set it up but the below works brilliantly (Django 1.10, Python 3.5)
# urls.py
urlpatterns = [
url(r'^$', home_view, name='home'),
url(r'^form/$', ContactFormView.as_view(), name='contact')
]
# forms.py
class ContactForm(forms.Form):
name = forms.CharField(max_length=20)
def send_email(self):
print('Email sent!')
# views.py
# Your ContactFormView as is
# contact.html
<form action="" method="post">{% csrf_token %}
{% if form.errors %}{{ form.errors }}{% endif %}
{{ form.as_p }}
</form>
I am trying to upload files (specifically images) to a database. When I try to POST my form in profile_photo.html (attached below), it gives me an error saying:
MultiValueDictKeyError at /user_profile/login/upload_profile_photo/
profile_photo.html:
<body>
<div id="blue_background_with_fibers">
<form class="pull-center white form-signin" role="form" action="" method="POST" enctype="multipart/form-data">
{% csrf_token %} {{ form.as_p }}
<button class="aqua button2" type="submit" value="OK">Upload</button>
</form>
</div>
detail.html that uses profile_photo.html:
<div class="modal fade" id="profile" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title">Upload Profile Picture</h4>
</div>
<div class="modal-body">
<form>
<!--Insert form here-->
<iframe src="upload_profile_photo/" allowTransparency="true" scrolling="yes" frameborder="0" width="560px" height="175px"></iframe>
</form>
</div>
<div class="modal-footer">
<span>Ekho © 2016</span>
</div>
</div>
</div>
</div>
I believe that I am messing up in my views.py (specifically under the EditProfileView class). Below is my views.py:
class EditProfileView(View):
form_class = EditProfileForm
def get(self, request):
form = self.form_class(None);
return render(request, 'ekho/profile_photo.html', {'form': form})
def post(self, request):
if not request.user.is_authenticated():
return render(request, 'ekho/login.html')
else:
form = EditProfileForm(request.POST or None, request.FILES or None)
if form.is_valid():
user = form.save(commit=False)
user.user = request.user
user.profile_photo = request.FILES['profile_photo']
file_type = user.profile_photo.url.split('.')[-1]
file_type = file_type.lower()
if file_type not in IMAGE_FILE_TYPES:
context = {
'user': user,
'form': form,
'error_message': 'Image file must be PNG, JPG, or JPEG',
}
return render(request, 'ekho/detail.html', context)
user.save()
return render(request, 'ekho/login.html', {'user': user})
return render(request, 'ekho/detail.html', {"form": form,})
Models.py:
from django.db import models
from django.contrib.auth.models import User
class UserProfile(models.Model):
user = models.OneToOneField(User, related_name='profile');
background = models.FileField(upload_to = 'user_profile/media/', blank=True, null=True);
profile = models.FileField(upload_to = 'user_profile/media/', blank=True, null=True);
about = models.TextField(default='', blank=True);
reviews = models.TextField(default='', blank=True);
def __str__(self):
return self.user.username
And finally urls.py:
from django.conf.urls import url
from . import views
app_name = 'user_profile'
urlpatterns = [
# /user_profile/
url(r'^$', views.index, name='index'),
# /user_profile/username
url(r'^user_profile/detail/$', views.detail, name='detail'),
# user_profile/register/
url(r'^register/$', views.RegisterFormView.as_view(), name='register'),
# user_profile/login/
url(r'^login/$', views.LoginFormView.as_view(), name='login'),
url(r'^login/upload_profile_photo/$', views.EditProfileView.as_view(), name='edit_profile')
]
This but be the problem
In your views.py file you are trying to access 'profile_photo' which should have been in 'profile' according to your models.py
views.py
user.profile_photo = request.FILES['profile_photo']
This error MultiValueDictKeyError occurs when you try to access the key that is not available in Dict
I guess this should work
views.py
user.profile_photo = request.FILES['profile']
PyMentor has a grate tutorial to post form with image in django.
http://pymentor.in/upload-image-file-using-django/
For your second problem: UNIQUE constraint failed: user_profile_userprofile.user_id
You can't use form.save to retrieve the UserProfile instance. It will create another user profile object after calling form.save, so you will get UNIQUE constraint error.
Try to replace form.save with:
user = User.objects.get(pk=request.user.pk).profile