NoReverseMatch at post when I add href link - python-3.x

I am building a "game" website where clues are given and individuals will make guesses.
I have added home.html, new_game.html, game_detail.html, base.html, and now edit_game.html. All is working correctly to create a new, list (in home.html), and display details. Now I am adding the function to edit the game in edit_game.html.
When I add the html link `Edit Game in game_detail.html, I get the error (below) when I click on any of the games in the list, which should display the game_detail page. In other words, it will not display the game_detail.html. Here is the error:
NoReverseMatch at /post/2/
Reverse for 'edit_game' with arguments '('',)' not found. 1 pattern(s) tried: ['post/(?P<pk>[0-9]+)/edit/$']
It is clearly passing the ID of the post. But it is not picking up the "/edit/". Here is the detail page code:
<!-- templates/game_detail.html -->
{% extends 'base.html' %}
{% block content %}
<div class="post-entry">
<h2>{{object.title}}</h2>
<p>{{ object.body }}</p>
</div>
Edit Game
{% endblock content %}
Here is the urls code:
from django.urls import path
from .views import (
GameListView,
GameDetailView,
GameCreateView,
GameUpdateView,
)
urlpatterns = [
path('post/<int:pk>/edit/', GameUpdateView.as_view(), name='edit_game'),
path('post/<int:pk>/', GameDetailView.as_view(), name='game_detail'),
path('post/new/', GameCreateView.as_view(), name='new_game'),
path('', GameListView.as_view(), name='home'),
]
The Views code:
from django.views.generic import ListView, DetailView
from django.views.generic.edit import CreateView, UpdateView
from .models import Game
class GameListView(ListView):
model = Game
template_name = 'home.html'
class GameDetailView(DetailView):
model = Game
template_name = 'game_detail.html'
class GameCreateView(CreateView):
model = Game
template_name = 'new_game.html'
fields = ['title', 'author', 'body']
class GameUpdateView(UpdateView):
model = Game
template_name = 'edit_game.html'
fields = ['title', 'body']

The object is passed as object and game to the template, you can thus construct the link with:
{% url 'edit_game' game.pk %}
or:
{% url 'edit_game' object.pk %}

Related

Redirecting user to another page after submitting the form using get_absolute_url() method

I'm new to django and I'm following a tutorial trying to create a blog. I'm currently working on a page to add posts to the blog and I want the user to be automatically directed to the post page after submitting the form. I tried using get_absolute_url method but got this error:
NoReverseMatch at /my_blog/add_post/
Reverse for 'post-detail' not found. 'post-detail' is not a valid view function or pattern name.
I checked my code to see if I have done anything wrong but I couldn't notice. I appreciate any help in advance.
models.py
from django.db import models
from django.contrib.auth.models import User
from django.urls import reverse
class Post(models.Model):
STATUS = [
(0, 'Drafted'),
(1, 'Published'),
]
title = models.CharField(max_length=200, unique=True)
slug = models.SlugField(max_length=200, unique=True)
author = models.ForeignKey(User, on_delete=models.CASCADE)
created_on = models.DateTimeField(auto_now_add=True)
published_on = models.DateTimeField(auto_now=True)
content = models.TextField()
status = models.IntegerField(choices=STATUS, default=0)
class Meta:
ordering = ['-created_on']
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('post-detail', args=(str(self.id)))
urls.py
from django.urls import path
from .views import PostListView, PostDetailView, AddPostView, UpdatePostView
app_name = 'my_blog'
urlpatterns = [
path('', PostListView.as_view(), name='posts'),
path('post/<int:pk>', PostDetailView.as_view(), name='post-detail'),
path('add_post/', AddPostView.as_view(), name='add-post'),
path('post/edit/<int:pk>', UpdatePostView.as_view(), name='update-post'),
]
views.py
from django.shortcuts import render
from django.views.generic import ListView, DetailView, CreateView, UpdateView
from .models import Post
class PostListView(ListView):
model = Post
template_name = 'post_list.html'
context_object_name = 'latest_post_list'
class PostDetailView(DetailView):
model = Post
template_name = 'my_blog/post_detail.html'
class AddPostView(CreateView):
model = Post
template_name = 'my_blog/add_post.html'
fields = ('__all__')
class UpdatePostView(UpdateView):
model = Post
template_name = 'my_blog/update_post.html'
fields = ['title', 'content']
This is my add post file in the template directory
add_post.html
{% extends 'base.html' %} {% block content %}
<h1>Add post...</h1>
<form method="post">
{% csrf_token %} {{ form.as_p }}
<input type="submit" value="Submit" />
</form>
{% endblock %}
You used an app_name, so you should specify this namespace with:
class Post(models.Model):
# …
def get_absolute_url(self):
return reverse('my_blog:post-detail', args=(self.pk,))
The primary key is also passed in a (singleton) tuple, so (self.pk,), not (self.pk).

Best way to filter on data belonging to the logged in user (Django)

First of all; I'm fairly new to Django.
Right now, I'm trying to create a very simple webpage with links (just to learn). The idea right now is, that a user (which is logged in) can add links to the database/model, and only see the links of which he has added.
I'm strugling to figure out what the best practice is for that - is it to store the user.username in the model, and then make a .filter(username=user) each time or..? I would assume Django has some (faster way) of handling this.
I have the following
models.py
from django.db import models
from django.contrib.auth.models import User
class links(models.Model):
link = models.URLField()
#user = <something_here>
views.py
def add_link(request):
if request.method == "POST":
form = add_link_form(request.POST)
if form.is_valid():
messages.success(request, "Link is added!")
form.save()
return redirect("my_links")
else:
form = add_link_form()
context = {
"links":links.objects.all(),
"form":form
}
return render(request, "django_project/my_links.html",context=context)
my_links.html
{% extends "django_project/base.html" %}
{% load crispy_forms_tags %}
{% block content %}
<div class="content-section">
<form method="POST">
{% csrf_token %}
{{form|crispy}}
<div class="form-group">
<button class="btn btn-outline-info" type="submit">Add link</button>
</div>
</form>
{% for l in links%}
{{l.link}}
{% endfor%}
{% endblock content %}
You can define Link as:
class Link(models.Model):
link = models.URLField()
user = models.ForeignKey(settings.AUTH_USER_MODEL, related_name="links")
where, when adding you could do:
logged_in_user.links.create(...)
or if adding an already existing link:
logged_in_user.links.add(link)
or if you know that links will forever remain as as strings without any other data related to it, and you use postgresql as your DB, you could add this field to the user model:
from django.contrib.postgres.fields import ArrayField
from django.db import models
class UserModel(models.Model):
...
links = ArrayField(models.URLField(), default=list)
and when adding, treat it exactly as you would do with an array:
logged_in_user.links.append("google.com")
logged_in_user.save()
Both of these approaches, in essence, provide you a filtered list when calling logged_in_user.links, but in the first case it is a queryset of Link objects, whereas the second is an array of strings.

Django author Form not saving to database

models.py
class Blog(models.Model):
title = models.CharField(max_length=100, unique=True)
slug = models.CharField(max_length=100, unique=True)
post_pic = models.ImageField(upload_to ='media/post_pics/', default =None )
body = models.TextField()
posted = models.DateTimeField(db_index=True, auto_now_add=True)
#author = must be logged in, populate from login details
forms.py
class postForm(forms.Form):
title = forms.CharField(max_length=100)
slug = forms.CharField(max_length=100)
post_pic = forms.ImageField()
body = forms.CharField(widget=SummernoteWidget())
views.py
def write_detail(request):
template_name = 'blog/write.html'
if request.method == 'POST':
post_form = postForm(request.POST)
if post_form.is_valid():
new_post = Blog(title=title,slug=slug,post_pic=post_pic,body=body)
new_post.save()
return HttpResponseRedirect(blog.get_absolute_url())
else:
post_form = postForm()
return render(request, template_name, {'post_form': post_form})
write.html
{% extends 'blog/base.html' %}
{% load static %}
{% block back-img %}'{% static 'blog/assets/img/intro.jpg' %}'{% endblock back-img %}
{% block titdes %}Write{% endblock titdes %}
{% block title %}Write{% endblock title %}
{% block pagedes %}A django powered community blog{% endblock pagedes %}
{% block body%}
<form method = "POST">
{{ post_form.as_p }}
{% csrf_token %}
<button type="submit" class="btn btn-primary">Publish</button>
</form>
{% endblock %}
I have set up this form so that authors can write articles to the blog without accessing the admin panel and I believe it should work but it isn't saving to the database.
I have tried to work on the views over and over but don't know what else to do. Please don't delete my question just ask any question that can help you help me.
in your forms.py
try
from .models import Blog
class postForm(forms.Form):
title = forms.CharField(max_length=100)
slug = forms.CharField(max_length=100)
post_pic = forms.ImageField()
body = forms.CharField(widget=SummernoteWidget())
class Meta:
model = Blog
fields = ('title', 'slug', 'post_pic', 'body')
PS. Iam new to Django, i hope this help you.
It looks like you just need to save the form, but you're creating a new Blog object with values that we can't see defined anywhere.
new_post = Blog(title=title,slug=slug,post_pic=post_pic,body=body)
title, slug, etc don't get defined.
What you should do, is change it to a ModelForm so that django does all the hard work;
class postForm(forms.ModelForm):
class Meta:
model = Blog
fields = ('title', 'slug', 'post_pic', 'body')
widgets = {
'body': SummernoteWidget(),
}
Then in your view you just need to do;
def write_detail(request):
template_name = 'blog/write.html'
if request.method == 'POST':
post_form = postForm(request.POST)
if post_form.is_valid():
post_form.save()
return HttpResponseRedirect(blog.get_absolute_url())
else:
# GET request
post_form = postForm()
return render(request, template_name, {'post_form': post_form})
The summernote docs for forms (and modelforms) is here
Don't forget, that when using a widget like this that comes with media, you need to add the form's media to the template.
You can access it in the HTML using either {{ form.media }} to get all CSS and JS, or individually as {{ form.media.js }} and {{ form.media.css }}
You can see how they do it in the summernote app playground
class postForm(forms.ModelForm):
class Meta:
model = Blog
fields = ('title', 'slug', 'post_pic','body')
widgets = {
'body':SummernoteWidget(),
}
Sorry guys you can actually use django summer note with a model form. I used it before but the editor was not appearing so I changed it to the one I previously posted but after reading another answer on stack overflow. I found out that I didn't add this code below to my HTML files or just inside my base.html
<!-- include summernote css/js-->
<link href="http://cdnjs.cloudflare.com/ajax/libs/summernote/0.8.3/summernote.css" rel="stylesheet">
<script src="http://cdnjs.cloudflare.com/ajax/libs/summernote/0.8.3/summernote.js"></script>
Thanks guys

Django Error: Error during template rendering

I'm learning Django framework and I have in the extend templates part, I'm trying to add a new template when I click in the title of the post in my blog to redirect to an page with the post details (date/author/etc),so I create a new view in views.py and a new url to in urls.py,But when I adc the path of the url in the 'href' desirable of the .html file ,as you will see, I receive the follow error when I reload the page:
NoReverseMatch at /
Reverse for 'blog.views.post_detail' with arguments '()' and keyword
arguments '{'pk': 2}' not found. 0 pattern(s) tried: []
And
Error during template rendering
In template
/home/douglas/Documentos/Django/my-first-blog/blog/templates/blog/post_list.html,
error at line 9
So, when I erase the href to back the default value all works well...I am almost sure that something is wrong in the href line but I will post all template related files for you to check, if you need to check anything else let me know:
firs the html file: post_list.html
{% extends 'blog/base.html' %}
{% block content %}
{% for post in posts %}
<div class="post">
<div class="date">
{{ post.published_date }}
</div>
<h1>{{ post.title }}</h1>
<p>{{ post.text|linebreaksbr }}</p>
</div>
{% endfor %}
{% endblock content %}
urls.py:
from django.conf.urls import url
from . import views
from .models import Post
urlpatterns = [
url(r'^$', views.post_list),
url(r'^post/(?P<pk>[0-9]+)/$', views.post_detail),
]
views.py
from django.shortcuts import render
from django.shortcuts import render, get_object_or_404
from .models import Post
from django.utils import timezone
def post_list(request):
#posts = Post.objects.filter(published_date__lte=timezone.now()).order_by('published_date')
posts = Post.objects.all()
return render(request, 'blog/post_list.html', {'posts': posts})
def post_detail(request, pk):
post = get_object_or_404(Post, pk=pk)
return render(request, 'blog/post_detail.html', {'post': post})
Well guys, I think is that, I hope I have not forgotten any details about my question...
Thank you in advance,any help is welcome!!
You need to define a name for your url. It's better.
urlpatterns = [
url(r'^$', views.post_list, name='post_list'),
url(r'^post/(?P<pk>[0-9]+)/$', views.post_detail, name='post_detail'),
]
Like this, in your template, you can use this name on url tag
<h1>{{ post.title }}</h1>
First info (with name define for url)
The first argument is a url() name. It can be a quoted literal or any
other context variable.
Second info (In your case, url without name)
If you’d like to retrieve a namespaced URL, specify the fully
qualified name:
{% url 'myapp:view-name' %}
More information here

Cannot load Haystack custom form

I want to build a custom search form. Below is my code. My app is called "viewer". I keep getting a "NameError at /viewer/search/...name 'CustomSearchForm' is not defined". Please help. I know it is a simple error somewhere.
From viewer/urls.py:
from django.conf.urls import *
from viewer import views, forms
from haystack.views import SearchView
urlpatterns = patterns('',
#viewer urls
...
url(r'^search/$', SearchView(form_class=CustomSearchForm), name='haystack_search')
)
From viewer/forms.py:
from django import forms
from haystack.forms import ModelSearchForm
from haystack.query import SearchQuerySet
class CustomSearchForm(ModelSearchForm):
...
Here is the solution I found, using a different approach:
urls.py:
url(r'^search/', 'viewer.views.search'),
views.py:
def search(request):
from .forms import CustomSearchForm
form = CustomSearchForm(request.GET)
searchresults = form.search()
return render(request, 'viewer/search.html', {'form' : form})
in viewer/search.html:
{% extends 'base.html' %}
{% block content %}
<form type="get" action=".">
{{form}}
<button type="submit">Search</button>
</form>
{% endblock %}
Had the same problem but with "NameError at /viewer/search/...name 'SearchForm' is not defined" trying to follow the guide here:
http://django-haystack.readthedocs.io/en/v2.6.0/views_and_forms.html
Just upgrading to Django 1.11.0 did the trick for me. Maybe it would work for you too.

Resources