I'm building my first application (guess app) with Django, I've been doing well so far. But I've encountered an error when trying to redirect to a Detail View when a user submits a file through a submit function (similar to a 'post blog' scenario).
I've looked up several posts with the same problem and I can not figure out why my code is not working.
views.py
#login_required
def submit(request):
if request.method == 'POST':
submited_form = SubmitFileForm(request.POST, request.FILES)
if submited_form.is_valid():
...
form.save()
return HttpResponseRedirect(reverse('result-detail'), kwargs={'pk': form.pk})
else:
submited_form = SubmitFileForm()
return render(request, 'guess/submit.html', context)
class ResultDetailView(LoginRequiredMixin, DetailView):
model = Result
template_name = 'guess/result_detail.html'
context_object_name = 'result'
I know I'm mixing class based views with function based views, but for some reason I can not get my submit function to work when I try to implement it as a class based view. Anyway, I think that shouldn't be a problem
urls.py
url_patterns = [
...
path('result/<int:pk>', guess_views.ResultDetailView.as_view(), name='result-detail'),
...
]
result_detail.html
{% extends "guess/base.html" %}
{% block content %}
<article class="media content-section">
<div class="media-body">
<div class="article-metadata">
<a class="mr-2" href="#">{{ result.author }}</a>
<small class="text-muted">{{ result.date_posted }}</small>
</div>
<h2 class="article-title">{{ result.title }}</h2>
<p class="article-content">{{ result.statistic }}</p>
</div>
</article>
{% endblock content %}
I'd expect a redirect to the detail view of the object that has been created with the submit function and submitfileform (model form). I can access the details if I just type /result/ and the primary key of any created object. But apparently I can't do the same through a redirect.
The error I am getting:
NoReverseMatch at /submit/
Reverse for 'result-detail' with no arguments not found. 1 pattern(s) tried: ['result/(?P<pk>[0-9]+)$']
In your code, you have two problems. First, form is not a Model instance. When you call form.save(), it will return the model instance. So you need to store it in a variable. Second problem is that, you need to pass the kwargs as a known argument in the reverse, not in HttpResponseRedirect. So the following code should work:
instance = form.save()
return HttpResponseRedirect(reverse('result-detail',kwargs={'pk': instance.pk}))
Related
I cannot understand why it is working in one instance but not the other. I am working with django and output in django template. The only difference between the views/functions are in the second one (the one that is not working) I update the field with time. Time updates, saves in the model and displays updated time correctly. It is just the redirect that is not working.
The working redirect code-
Template, this code takes me to the edit page. Name of the url is "update" -
<td><button>Edit</button></td>
The form on the dit page-
{% block content %}
<div class="wrapper">
<h1 class="ok">Entry Form</h1>
<form action="" method="POST">
{% csrf_token %}
{{form}}
<input type="submit" value="submit">
</form>
</div>
<br>
{% endblock content %}
url-
path('update_entry/<str:pk>/', views.update, name = "update"),
And views.py-
def update(request, pk):
order=Bank1.objects.get(id=pk)
form = Bank1Form(instance=order)
if request.method == 'POST':
form = Bank1Form(request.POST, instance=order)
if form.is_valid():
form.save()
return redirect('/bank1')
context = {'form':form}
return render(request, 'myapp/entry.html', context)
Now here is the non working code. Template, the line that takes me to the update page. Name of the url is "update_enter_workout.-
<td><button>Start Time</button></td>
Form on the Edit page. Didn't add the entire form since I only need to update the time from this page. Just the submit button.-
{% block content %}
<Button>Close this page and go to Home</Button>
<div class="wrapper">
<h1 class="ok">Start/End the set now?</h1>
<form action="" method="post">
{% csrf_token %}
<input type="submit" value="YES!">
</form>
</div>
{% endblock content %}
url-
path('update_enter_workout/<str:pk>/', views.update_workout, name='update_enter_workout'),
Views.py-
def update_workout(request, pk):
order=WorkOut.objects.get(id=pk)
form=WorkOutForm(instance=order)
if request.method=='POST':
form=WorkOutForm(request.POST, instance=order)
time=datetime.now().strftime('%H:%M:%S')
WorkOut.objects.filter(id=pk).update(start=time)
if form.is_valid():
form.save()
return redirect('/bank1')
context={'form':form}
return render(request, 'myapp/enter_workout.html', context)
As you can see they are written the same way, but in the second instance redirect is not working. Any idea what can be changed. It is so simple, couldn't even find a typo or simple mistake like that.
Any advise?
Are you accepting str for id fields? Primary Keys are integers, not strings. You need to cast to an int path converter:
Instead of:
path('update_enter_workout/<str:pk>/', views.update_workout, name='update_enter_workout'),
Use:
path('update_enter_workout/<int:pk>/', views.update_workout, name='update_enter_workout'),
I’m building a blog and I’m new to django. I’m trying to build a post display page but tag variables are not working.
urls.py
urlpatterns = [
.
.
.
path('post/<slug>/', views.post_detail, name='post_detail'),
]
views.py
.
.
.
def post_detail(request, slug):
all_posts= Post.objects.all()
this_post = Post.objects.filter(post_slug=slug)
return render(request = request,
template_name = 'blog/post_detail.html',
context = {'this_post':this_post, 'all_posts':all_posts})
.
.
.
post_detail.html
{% extends 'blog/header.html' %}
{% block content %}
<div class="row">
<div class="s12">
<div class="card grey lighten-5 hoverable">
<div class="card-content teal-text">
<span class="card-title">{{ this_post.post_title }}</span>
<p style="font-size:70%">Published {{ this_post.post_published }}</p>
<p>{{ this_post.post_content }}</p>
</div>
</div>
</div>
{% endblock %}
Thanks from now!
instead of filtering, need to bring out single object then only it will be available in detail view. Output of filer will be a list.
this_post = Post.objects.get(post_slug=slug)
or
this_post = get_object_or_404(Post, post_slug=slug)
this_post is not a Model instance - it's a Queryset. Post.objects.filter() always returns a Queryset, even if there's only one record. Attribute post_title is an attribute of Post instance - not of a queryset.
You can do either:
use get():
Post.objects.get(post_slug=slug)
...or add first() to the queryset:
Post.objects.filter(post_slug=slug).first()
What's the difference?
get() will return an instance or raise Post.DoesNotExist exception if Post is not found.
filter(...).first() will return first result from queryset (as model instance) or None, if nothing was found.
I am elaborating on the tutorial in the django docs to build a voting app. What I try to achieve is to be able to delete a candidate and, at success, get back to the detailview of the election. I know I could just add another parameter to the url like (full template below)
<a href="{% url 'candidate_delete' c.id object.id %}" class="btn btn-danger fa fa-trash" class></a>
I would like to know whether it is possible to use a post method (although there is no form). I did some research, found the 'next' parameter, but it does not get through. It looks like it needs a form, since all examples are using the 'next' within a form.
I also tried setting the success_url based on the election the to-be-deleted-candidate is ForeignKey-d to, but that generates the error:
ImproperlyConfigured at /elections/candidate/delete/13/
The included URLconf '1' does not appear to have any patterns in it. If you see valid patterns in the file then the issue is probably caused by a circular import.
This is the view:
class CandidateDelete(LoginRequiredMixin, DeleteView):
model = Candidate
template_name = 'election/delete.html'
def get_object(self):
obj = super().get_object()
print(self.request.POST)
election = Election.objects.get(id=obj.poll_id)
if not election.owner_id == self.request.user.id:
raise Http404
return obj
def get_success_url(self, **kwargs):
obj = super().get_object()
election = Election.objects.get(id=obj.poll_id)
return reverse_lazy('election_detail', election.id)
The election_detail template
{% extends 'base.html' %}
{% block content %}
{{object.name}} -
<ul>
{% for c in candidate_list %}
<h2>{{ c.name }}</h2>
<li> {{ c.intro }} {{c.id}}
{{c.email}}
<a href="{% url 'candidate_delete' c.id %}" class="btn btn-danger fa fa-trash" class></a> <input type="hidden" name="next" value={{object.id}} />
</li>
{% endfor %}
<a href="{{ request.META.HTTP_REFERER }}" class="btn btn-primary" class>Back</a>
</ul>
{% endblock %}
the object in the template is the election that the candidates are linked to.
As you can see, I tried the post method, but, reading around, it seems to only work in a form. The success_url config throws an error as well.
Any help to use the post method or configure get_success_url with data from the model is much appreciated.
So, apparently, the reverse_lazy has to look like this:
def get_success_url(self, **kwargs):
obj = super().get_object()
election = Election.objects.get(id=obj.poll_id)
return reverse_lazy('election_detail', kwargs={'pk':election.id})
While in the template, you can just add the var, in the return function you have to specify it is a kwargs.
I am almost sure the "election= .. "can be shorter, but that is for later
I have two models. I do filtering of objects by these models and display them in a template.
Everything works fine, but an error occurs with url.
my urls.py
path('objects_model_A/<int:objects_A_id>', views.objects_A, name='objects_model_A'),
path('objects_model_B/<int:objects_B_id>', views.objects_B, name='objects_model_B'),
my views.py
def index(request):
objects_A = objects_A.objects.all().filter(is_published=True)
objects_B = objects_B.objects.all().filter(is_published=True)
queryset_list = list(chain(objects_A, objects_B))
context = {'queryset_list': queryset_list}
return render(request, 'templates/index.html', context)
def objects_A(request, objects_A_id):
objects_A = get_object_or_404(objects_a, pk=objects_A_id)
context = {
'objects_A': objects_A
}
return render(request, 'templates/objects_A.html', context)
def objects_B(request, objects_B_id):
objects_B = get_object_or_404(objects_b, pk=objects_B_id)
context = {
'objects_A': objects_A
}
return render(request, 'templates/objects_B.html', context)
my template.html
{% if queryset_list %}
{% for listing in queryset_list %}
<div class="col-md-6 col-lg-4 mb-4">
<div>
<a href="{% url 'objects_model_A' listing.id %}">Link
</a>
{% endfor %}
{% endif %}
Objects from different models are collected, have an appropriate data set, but url are wrong.
The object with model_A, url:
http://127.0.0.1:8000/objects_A/1
An object with model_B, url too:
http://127.0.0.1:8000/objects_A/1
I understand the error in the template. Line <a href="{% url 'objects_model_A' listing.id %}.
How to draw up URLs correctly so that objects from different models in the chain are displayed correctly. For object A was url:
http://127.0.0.1:8000/objects_A/1
For object B was url:
http://127.0.0.1:8000/objects_B/1
One often specifies a canonical URL at the model level with a get_absolute_url method [Django-doc]. You can thus implement this like:
from django.urls import reverse
class objects_A(models.Model):
# ...
def get_absolute_url(self):
return reverse('objects_model_A', kwargs={'objects_A_id': self.pk})
class objects_B(models.Model):
# ...
def get_absolute_url(self):
return reverse('objects_model_B', kwargs={'objects_B_id': self.pk})
In your template, you can then use:
{% for listing in queryset_list %}
<div class="col-md-6 col-lg-4 mb-4">
<div>
Link
</div>
</div>
{% endfor %}
Django has some tooling that takes get_absolute_url into account. For example you can pass a model object with a get_absolute_url method to a redirect(..) call [Django-doc], and Django will then redirect to the get_absolute_url() result of that object.
I am currently faced with a challenge, when a user gets authenticated they can see objects posted by other users they are following. The challenge here is I want the authenticated user to click on the name of a user following them and it automatically takes then to the a page containing all the posts by that user they clicked on. So far my code keeps showing me just the posts by the authenticated user only.
#Views.py
def article(request):
return render(request, 'article.html',
{'posts': post.objects.filter(user = request.user),'form' : CommentForm()})
#article.html
{% for post in posts %}
<div class = "username">
<font size="4.5">{{post.user}}</font>
</div>
<div class = "postbody">
<p>{{ post.body|lower|truncatewords:50 }}</p>
<p>{{post.likes}} people liked this article</a></p>
</div>
<p>likes {{post.likes}} </p>
{% endfor %}
{% endif %}
I appreciate any help thanks.
Change this line
post.objects.filter(user = request.user)
to filter on some other user object most likely like this
post.objects.filter(user__pk=user_id)
For a more complete solution your urls.py should look like this
url(r'^article/(?P<user_id>)/$', views.article),
in your views.py, accept the user_id as a new parameter
def article(request, user_id):
return render(request, 'article.html',
{'posts': post.objects.filter(user__pk=user_id),'form' : CommentForm()})