URL is not jumping to right number in Django - python

models.py
from django.db import models
class Profile(models.Model):
name=models.CharField(max_length=20 )
age=models.IntegerField()
def __str__(self):
return self.name
class Like(models.Model):
user=models.ForeignKey(Profile,on_delete=models.CASCADE)
choice_text = models.CharField(max_length=200)
like=models.IntegerField(default=0)
def __str__(self):
return self.choice_text
views.py
from django.shortcuts import render
from .models import Profile, Like
# Create your views here.
def index(request):
all_name=Profile.objects.all()
context={'all_name':all_name}
return render(request, 'database/index.html',context)
def detail(request, profile_id):
all_likes=Like.objects.get(pk=profile_id)
return render(request, 'database/detail.html', {'all_likes':all_likes})
index.html
<h1>hey</h1>
{% for name in all_name %}
<li>{{ name.name }}</li>
{% endfor %}
detail.html
{{all_likes}}
urls.py
from django.urls import path
from . import views
app_name='database'
urlpatterns = [
path('index/', views.index, name='index'),
path('<int:profile_id>/', views.detail, name='detail'),
]
now http://127.0.0.1:8000/database/index/ produces two list item,
but when I click on both, i am redirecting to http://127.0.0.1:8000/database/1/ .
http://127.0.0.1:8000/database/2/ is working manually but not when I click. Couldn't figure out the error in the code.

You pass all objects to HTML:
all_name = Profile.objects.all()
and on for loop in HTML you used
{% for name in all_name %}
Here:
<li>{{ name.name }}</li>
you are using user.id instead of name.id.
Use:
<li>{{ name.name }}</li>
Then it will use the id of the object in for loop and will hit the correct URL.

Related

NoReverseMatch at /add_post

I have been working on a blog site using django and I made a way to add post within the home page without going to the admin page but when I post using the new way I get this error
This is my models.py file
from django.db import models
from django.contrib.auth.models import User
from django.urls import reverse
class Post(models.Model):
title = models.CharField(max_length=255)
title_tag = models.CharField(max_length=255)
author = models.ForeignKey(User, on_delete=models.CASCADE)
body = models.TextField(max_length=3500)
def __str__(self):
return (self.title + " | " + str(self.author))
def get_absolute_url(self):
return reverse("article-view", args=(str(self.id)))
This is the views.py file
from django.views.generic import ListView, DetailView, CreateView
from .models import Post
class HomeView(ListView):
model = Post
template_name = "home.html"
class ArticleDetailView(DetailView):
model = Post
template_name = "detail_view.html"
class AddPostView(CreateView):
model = Post
template_name = "add_post.html"
fields = "__all__"
This is the polls/urls.py
from django.urls import path
from .views import HomeView, ArticleDetailView, AddPostView
urlpatterns = [
path('', HomeView.as_view(), name='home'),
path('article/<int:pk>', ArticleDetailView.as_view(), name='article-view'),
path('add_post/', AddPostView.as_view(), name='add_post'),
]
This is the add_post.html file
{% extends 'base.html' %}
{% block content %}
<head>
<title>Adding Post</title>
</head>
<h1>Add Blog Posts</h1>
<form method="POST">
{% csrf_token %}
{{ form.as_p }}
<button class="btn btn-secondary">Post</button>
</form>
{% endblock %}
Thank you.
Okay, so it looks like this is caused by the model's get_absolute_url reverse args=(). I changed the below code in models.py from:
def get_absolute_url(self):
return reverse("article-view", args=(str(self.id)))
Into
def get_absolute_url(self):
return reverse("article-view", args=[self.id])
The problem seems to be args=(), it is iterating over the str(self.id). So id=10 would actually be returned as a tuple (1,0). I also removed the str() around the self.id since the URL takes in an int.

How to get data out of a Django Model and in to the HTML Template?

I'm trying to display information from my model Administrateur into my HTML Template login.html, but nothing is happening.
This my Model:
from django.db import models
class Administrateur(models.Model):
nom = models.CharField(max_length=30)
prenom = models.CharField(max_length=30)
mdp = models.CharField(max_length=30)
mail = models.CharField(max_length=30)
def _str_(self):
return self.name
This is my view:
def Pseudo(request):
administrateurs = Administrateur.objects.all()
context={'administrateurs':administrateurs}
return render(request, "login.html",context)
This is my HTML:
{% extends "base.html" %}
{% load static %}
{% block content %}
{% for n in administrateurs %}
{{ n.nom }}
{{ n.prenom }}
{% endfor %}
{% endblock %}
I'm not sure what to do with urls.py
Do this step if you have not done it yet:
Add this to the file urls.py in the project's base directory:
from django.urls import include
urlpatterns = [
# your urls
path('login/', include('appname.urls')), #change appname to your app's name
]
now in your app make a new file called urls.py and add this to the file:
from django.urls import path
from .views import Pseudo
urlpatterns = [
path('', Pseudo, name="pseudo"),
]
then check when you go to login page (in url bar) what happens

How to put a delete button beneath each post?

The goal here is to add a delete button beneath every post, and once it is clicked, the corresponding row will be deleted from the table in the database.
views.py
from django.shortcuts import render, redirect
from .forms import CreatePostForm
from django.contrib import messages
from .models import CreatePost
def create_post(request):
if request.method == 'POST':
form = CreatePostForm(request.POST)
if form.is_valid():
post = form.save(commit = False)
post.save()
messages.success(request, f'The post has been created.')
return redirect('home_page')
else:
form = CreatePostForm()
return render(request, 'post/create_post.html', {'form': form})
def view_post(request):
context = CreatePost.objects.order_by('-dateCreated')
return render(request, 'post/view_post.html', {'context': context})
So far, there is one page, create_post.html, that allows users to create a post. There is a second page, view_post.html, that allows users to see all posts with the most recently added first. I want to put a delete button beneath every post in view_post.html.
view_post.html
{% extends "home_page/base.html" %}
{% load crispy_forms_tags %}
{% block content %}
<h1>Volunteer Opportunities</h1>
{% for x in context %}
<h4>
{{ x.task }}
<small class="text-muted">Date Required: {{ x.dateRequired }}</small>
</h4>
<blockquote>
<p>{{ x.description }}</p>
<p>Date Posted: {{ x.dateCreated }}</p>
</blockquote>
<hr>
{% endfor %}
{% endblock content %}
I'm not sure if this is necessary, but below are models.py and the project urls.py file.
models.py
from django.db import models
class CreatePost(models.Model):
dateCreated = models.DateTimeField(auto_now_add = True)
task = models.CharField(max_length = 1000)
description = models.TextField()
dateRequired = models.DateField(null = True)
urls.py
from django.contrib import admin
from django.urls import path, include
from home_page.views import home
from post.views import create_post, view_post
urlpatterns = [
path('admin/', admin.site.urls),
path('', home, name = 'home_page'),
path('create_post/', create_post, name = "create_post"),
path('view_post/', view_post, name = "view_post"),
]
Try this.
In your url
path('delete/<int:id>', view_post.destroy),
In Your html inside for
Delete
views.py
def destroy(request, id):
post = CreatePost.objects.get(id=id)
post.delete()
return redirect("/yourhtml")

Adding UUIDs to my Django app yields a NoReverseMatch error

I have a books app using a UUID with a listview of all books and detailview of individual books. I keep getting the following error message:
NoReverseMatch at /books/
Reverse for 'book_detail' with arguments '('/books/71fcfae7-bf2d-41b0-abc8-c6773930a44c',)' not found. 1 pattern(s) tried: ['books/(?P<pk>[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$']
Here is the models.py file:
# books/models.py
import uuid
from django.db import models
from django.urls import reverse
class Book(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
title = models.CharField(max_length=200)
author = models.CharField(max_length=200)
price = models.DecimalField(max_digits=6, decimal_places=2)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('book_detail', args=[str(self.id)])
The urls.py file where I'm using to convert the id from the model to a uuid.
# books/urls.py
from django.urls import path
from .views import BookListView, BookDetailView
urlpatterns = [
path('', BookListView.as_view(), name='book_list'),
path('<uuid:pk>', BookDetailView.as_view(), name='book_detail'),
]
The top-level urls.py file looks like this and adds a books/ route.
# urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('books/', include('books.urls')),
The views.py file:
from django.views.generic import ListView, DetailView
from .models import Book
class BookListView(ListView):
model = Book
context_object_name = 'book_list'
template_name = 'books/book_list.html'
class BookDetailView(DetailView):
model = Book
context_object_name = 'book'
template_name = 'books/book_detail.html'
And the relevant templates file.
<!-- templates/book_detail.html -->
{% extends '_base.html' %}
{% block content %}
{% for book in book_list %}
<div>
<h2>{{ book.title }}</h2>
</div>
{% endfor %}
{% endblock content %}
I believe I'm implementing this correctly but the URL is not liking my UUID. What is amiss?
The problem is not "adding uuid". The problem is that you are doing the URL reversal twice: once in get_absolute_url and once in the {% url %} tag. Use one or the other, not both.
Either:
{{ book.title }}
Or:
{{ book.title }}

Django - NoReverseMatch after simple changes in code

So,long story short,I started learning Django basics this week and followed a simple poll creating tutorial,which worked fine,but then I started trying to make a few changes to the code,and due to my inexperience in Django(and to be honest,also in HTML),I ended up getting this NoReverseMatch error. What I basically did was try to change the name of a class and it's uses in the app,and it's objects along the project(class TText).
Then the errors started showing up at both the /polls/* ( * being respective id number for a TText) and /polls/*/results in the localhost web page.
The first one gives the following error at detail.html,line 5:
Reverse for 'vote' with arguments '('',)' and keyword arguments '{}' not found. 1 pattern(s) tried: [u'polls/(?P<text_id>[0-9]+)/vote/$']
And the second at results.html,line 9:
Reverse for 'detail' with arguments '('',)' and keyword arguments '{}' not found. 1 pattern(s) tried: [u'polls/(?P<pk>[0-9]+)/$']
And here's my setup of this django app:
/mysite
urls.py
/polls
models.py
urls.py
views.py
/templates
/polls
detail.html
index.html
results.html
Where: /mysite/urls.py is:
from django.conf.urls import include,url
from django.contrib import admin
urlpatterns = [
url(r'^polls/', include('polls.urls')),
url(r'^admin/', admin.site.urls),
]
also - /polls/models.py :
from __future__ import unicode_literals
import datetime
from django.db import models
from django.utils import timezone
# Create your models here.
class TText(models.Model):
text = models.CharField(max_length=200)
pub_date = models.DateTimeField('date published')
def __str__(self):
return self.text
def was_published_recently(self):
return self.pub_date >= timezone.now() - datetime.timedelta(days=1)
class Choice(models.Model):
text = models.ForeignKey(TText, on_delete=models.CASCADE)
choice_text = models.CharField(max_length=200)
votes = models.IntegerField(default=0)
def __str__(self):
return self.choice_text
also - /polls/urls.py :
from django.conf.urls import url
from . import views
app_name = 'polls'
urlpatterns = [
url(r'^$', views.IndexView.as_view(), name='index'),
url(r'^(?P<pk>[0-9]+)/$', views.DetailView.as_view(), name='detail'),
url(r'^(?P<pk>[0-9]+)/results/$', views.ResultsView.as_view(), name='results'),
url(r'^(?P<text_id>[0-9]+)/vote/$', views.vote, name='vote'),
]
also - /polls/views.py :
from django.shortcuts import get_object_or_404, render
# Create your views here.
from django.http import HttpResponseRedirect
from django.urls import reverse
from django.views import generic
from .models import Choice, TText
class IndexView(generic.ListView):
template_name = 'polls/index.html'
context_object_name = 'latest_text_list'
def get_queryset(self):
"""Return the last five published questions."""
return TText.objects.order_by('-pub_date')[:5]
class DetailView(generic.DetailView):
model = TText
template_name = 'polls/detail.html'
class ResultsView(generic.DetailView):
model = TText
template_name = 'polls/results.html'
def vote(request, text_id):
text = get_object_or_404(TText, pk=text_id)
try:
selected_choice = text.choice_set.get(pk=request.POST['choice'])
except (KeyError, Choice.DoesNotExist):
# Redisplay the question voting form.
return render(request, 'polls/detail.html', {
'text': text,
'error_message': "You didn't select a choice.",
})
else:
selected_choice.votes += 1
selected_choice.save()
# Always return an HttpResponseRedirect after successfully dealing
# with POST data. This prevents data from being posted twice if a
# user hits the Back button.
return HttpResponseRedirect(reverse('polls:results', args=(text.id,)))
also - /polls/templates/polls/detail.html:
<h1>{{ text.text }}</h1>
{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}
<form action="{% url 'polls:vote' text.id %}" method="post">
{% csrf_token %}
{% for choice in text.choice_set.all %}
<input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}" />
<label for="choice{{ forloop.counter }}">{{ choice.choice_text }}</label><br />
{% endfor %}
<input type="submit" value="Vote" />
</form>
also: /polls/templates/polls/index.html :
{% if latest_text_list %}
<ul>
{% for text in latest_text_list %}
<li>{{ text.text }}</li>
{% endfor %}
</ul>
{% else %}
<p>No polls are available.</p>
{% endif %}
also - /polls/templates/polls/results.html :
<h1>{{ text.text}}</h1>
<ul>
{% for choice in text.choice_set.all %}
<li>{{ choice.choice_text }} -- {{ choice.votes }} vote{{ choice.votes|pluralize }}</li>
{% endfor %}
</ul>
Vote again?
PS: It's the first time a post a question here on Stack,so feel free to point out any mistake on that as well.
OH,and yes, I did read the other posts of similar problems,but I coudn't match any of them with my own problem. Thank you for your time!
The context passed into generic views is based on the Model name. You have two options in the template, you can use either object or name_of_model. In your case, that's ttext. Alternatively, you can tell the generic view what to call the object in the context:
class DetailView(generic.DetailView):
model = TText
template_name = 'polls/detail.html'
context_object_name = 'text'
class ResultsView(generic.DetailView):
model = TText
template_name = 'polls/results.html'
context_object_name = 'text'
Then you can use what you're currently doing in your templates: text.id instead of ttext.id or object.id.
The problems are in your URL template tags. Essentially you are telling Django to find a URL that doesn't exist.
The main issue as far as I can see is that you are referring to a template variable text which doesn't exist. It doesn't exist because those templates are being rendered by Django's generic views, and the generic views use object as their standard template variable name for a single object. If you just change text to object in those template files you should get a better result.
The other option is to declare a context object name on the view class, like you've done in IndexView - context_object_name = 'latest_text_list'.

Categories