redirect url with primary key DJANGO - python

So I have a list with some recipes and I want the user to be able to click on a recipe and be redirected to a view with more details. In other words, I want every recipe to have its own url. I am trying this code as below, but it does not work, it redirects 404 side after I click on recipe.
My model:
class Recipe(models.Model):
recipe_name = models.CharField(max_length=250)
preparation = models.CharField(max_length=1000)
ingredients = models.ManyToManyField(Ingredient)
recipe_image = models.ImageField(upload_to='images/', default='')
def __str__(self):
return self.recipe_name
View:
def GenerallView(request):
lista1 = Recipe.objects.all()
return render(request, 'drinks/GenerallView.html', {'lista1': lista1})
def DetailView(request, pk):
lista = get_object_or_404(Recipe, pk=pk)
return render(request, 'drinks/DetailView.html', {'lista': lista})
Url:
path('generall_view', views.GenerallView, name='GenerallView'),
path('detail_view/<int:pk>', views.DetailView, name='DetailView'),
Templates:
generall view
<ul>
{% for drink in lista1 %}
<li>{{ drink.recipe_name }}</li>
{% empty %}
<li>No notes yet.</li>
{% endfor %}
</ul>
detail view
<h1>{{ drink.recipe.name }}</h1>

The name of the obbject is drink, not Recipe, so you should write this with {% url 'DetailView drink.pk %}, furthermore the name of your view is DetailView, not detail_view:
<ul>
{% for drink in lista1 %}
<li>{{ drink.recipe_name }}</li>
{% empty %}
<li>No notes yet.</li>
{% endfor %}
</ul>
In the DetailView you passed a variable named lista as well, so you should render this with:
<h1>{{ lista.recipe_name }}</h1>

Related

How to display images of a particular Blog post?

models.py
class PostModel(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
date_time = models.DateTimeField(auto_now_add=True)
title = models.TextField(null=True)
body = models.TextField(null=True)
def __str__(self):
return str(self.user)
class ImagesPostModel(models.Model):
post = models.ForeignKey(PostModel, on_delete=models.CASCADE)
images = models.I
views.py
def show_posts(request):
posts = PostModel.objects.filter(user=request.user)
images = []
for post in posts:
images.append(ImagesPostModel.objects.filter(post=post))
context = {
'posts': posts,
'images': images,
}
return render(request, 'show_posts.html', context)
show_posts.html
{% extends 'base.html' %}
{% block content %}
{% for post in posts %}
{{post.title}}
<br>
{{post.body}}
<br>
{{post.data_time}}
<br>
{% for imgs in images %}
{% for image in imgs %}
{{image.post_id}}
<img src="{{image.images.url}}" alt="postimage" style="width: 300px;">
<br>
{% endfor %}
{% endfor %}
<hr>
<hr>
{% endfor %}
{% endblock %}
I want the images of a post to be displayed which are related to that post only. But here all the images combined for all posts of a particular user are being displayed each time in every post. How to resolve it?
You put yourself in that dilemma, you can fix the view code to fix that easily
def show_posts(request):
posts = PostModel.objects.filter(user=request.user)
for post in posts:
post.images = ImagesPostModel.objects.filter(post=post))
context = {
'posts': posts,
}
return render(request, 'show_posts.html', context)
and then you iterate over post.images in the template
OR you use post.images_set.all() to access the post images.
I would suggest you to use related_name for the post in your ImagePostModel. In your models.py you can do this.
class ImagesPostModel(models.Model):
post = models.ForeignKey(PostModel, on_delete=models.CASCADE, related_name="imagePost")
images = models.ImageField()
And then in your template use {{ post.imagePost.all }}
You can prefetch the images in bulk with:
def show_posts(request):
posts = PostModel.objects.filter(
user=request.user
).prefetch_related('imagespostmodel_set')
context = {
'posts': posts
}
return render(request, 'show_posts.html', context)
then in the template, you can access the .imagespostmodel_set of the post:
{% for post in posts %}
…
{% for image in post.imagespostmodel_set.all %}
{{image.post_id}}
<img src="{{image.images.url}}" alt="postimage" style="width: 300px;">
<br>
{% endfor %}
…
{% endfor %}
Note: Models normally have no Model suffix. Therefore it might be better to rename PostModel to Post.

How do I show navbar items based on a model field in Django?

I have a Blog model that looks like this:
class Blog(models.Model):
title = models.CharField(max_length=200)
content = models.TextField()
slug = models.SlugField(max_length=200, unique=True)
author = models.ForeignKey(User, on_delete=models.CASCADE, related_name='blogs')
parent = models.CharField(max_length=50, choices=PARENT_TUTORIALS)
def get_absolute_url(self):
return reverse("blog_list", args=[str(self.parent), str(self.slug)])
I can succesfully display all the blogs on a table of contents via my table.html template:
{% for blog in blog_list %}
<li>{{blog.title}}</li>
{% endfor %}
However, I want to show only those blogs that have the same Blog.parent value as the current blog page. For example, the page example.com/biology/page1, has biology as a parent. When the user is on that page, the table of contents should show only the pages that have biology as a parent.
Why not just add an if statement like so?
template.html
{% for blog in blog_list %}
{% if blog.parent == current_blog.parent %}
<li>{{blog.title}}</li>
{% endif %}
{% endfor %}
Another option is to filter with js, something like (untested):
template.html
{% for blog in blog_list %}
<li class="blog-list-item {{blog.parent}}">
{{blog.title}}
</li>
{% endfor %}
script.js
$('.blog-list-item').filter(':not(.biology)').hide();

Posts not showing author who wrote it in Django

Basically, I'm writing an app in which people can make blog and image posts. So far, I've completed users to be able to write text posts. However, when I try to create a post, it returns "By: None" when it should be returning "By: shrey". In this case, Bob is the author. Here's an image:
Here's an image for the post creation view:
Theoretically, when I enter a post it should say who it was written by.
Here's the template for the create post:
{% extends "social/base.html" %}
{% load crispy_forms_tags %}
{% block content4 %}
<h1>Make Your Post</h1>
<p>Write a post / Share an image</p>
<br>
<div class="container">
<form method="post">
{% csrf_token %}
{{form|crispy}}
<button type="submit" name="button">Make Post</button>
</form>
</div>
{% endblock content4 %}
Here's the function for the create post view:
class PostCreateView(CreateView):
model = Posts
fields = ['post_title', 'post_text_content']
def form_valid(self, form):
form.instance.author = self.request.user
print(self.request.user)
return super().form_valid(form)
Thank you in advance.
EDIT: Home Page Template (template which displays the posts):
{% extends "social/base.html" %}
{% block content %}
<h1>Your Feed</h1>
<p>This is your feed. Here, you'll see posts from people you follow.</p>
{% if user.is_authenticated %}
<p>You are logged in as {{user.username}}. This is your feed.</p>
{% else %}
<p>You are not logged in. This is a random feed.</p>
{% endif %}
{% for post in posts %}
<h1>{{ post.post_title }}</h1>
<p>By {{ post.post_author }} on <i>{{ post.post_date }}</i></p>
<p>{{ post.post_text_content }}</p>
{% endfor %}
Click here to make a post.
<br>
Click here to logout.
<br>
Click here to login.
<br>
Click here to sign up and make an account.
<!--<p>Want to post something? Enter your info here: </p> -->
{% endblock content %}
Posts Model:
class Posts(models.Model):
post_title = models.CharField(max_length = 40, help_text = 'Enter post title')
post_text_content = models.TextField(max_length = 1000)
post_author = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
post_date = models.DateField(auto_now = True, auto_now_add = False)
#Make optional Image Field
class Meta:
ordering = ['post_title', 'post_author', 'post_date', 'post_text_content']
def __str__(self):
return self.post_title
def get_absolute_url(self):
return reverse('social-home')
The name of the field is post_author, not author, hence you should set post_author:
class PostCreateView(CreateView):
model = Posts
fields = ['post_title', 'post_text_content']
def form_valid(self, form):
form.instance.post_author = self.request.user
return super().form_valid(form)
That being said, normally in Django one does not prefixes the model fields with the name of the model. One reason not to do that is that you can define abstract models where you define the field once, and then use inheritance to add the field to other models.

Django _set.all filter not working in template

I'm trying to filter a list of objects in my database but I can't get it to work on the template using _set.all. The strange thing is it's something I've done in two other places in my project but I cant see why it isnt working this time.
view.py:
class GolfMonthlyView(generic.ListView):
template_name="monthly_view/golf-monthly-view.html"
context_object_name='golf_monthly_view'
queryset = GolfMonthlyView.objects.all()
def get_context_data(self, **kwargs):
context = super(GolfMonthlyView, self).get_context_data(**kwargs)
context['golftour'] = golf_models.Tour.objects.all()
context['golftournament'] = golf_models.Tournament.objects.all()
models:
class Tour(models.Model):
name = models.CharField(max_length=100)
class Tournament(models.Model):
tour = models.ForeignKey('Tour', on_delete=models.CASCADE)
name = models.CharField(max_length=100)
template html:
{% for info in golf_monthly_view %}
{% for competition in golftour %}
{% for golftournament in golftour.golftournament_set.all %}
<ul>
<li>{{golftournament.name}}</li>
</ul>
{% endfor %}
{% endfor %}
{% endfor %}
The good news out of all this is in trying to work out my problem its forced me to use the Django Shell for the first time properly. So I know the relationship is there and functional, it just isnt displaying in the template.
Edit: The working thing:
class RugbyMonthlyView(generic.ListView):
template_name="monthly_view/rugby-monthly-view.html"
context_object_name='rugby_monthly_view'
queryset = RugbyMonthlyView.objects.all()
def get_context_data(self, **kwargs):
context = super(RugbyMonthlyView, self).get_context_data(**kwargs)
context['competition'] = rugby_models.Competition.objects.all()
context['match'] = rugby_models.Match.objects.all()
return context
model.py:
class Competition(models.Model):
name = models.CharField(max_length=200)
class Match(models.Model):
competition = models.ForeignKey('Competition', on_delete=models.CASCADE)
html template:
{% for match_info in rugby_monthly_view %}
{% for competition in competition %}
*code*
{% for match in competition.match_set.all %}
*code*
{% endfor %}
{% endfor %}
{% endfor %}
You have golftour.golftournament_set.all nested in a loop on the context list golf_monthly_view (not sure why you're doing this), which I think is empty because the ListView QuerySet is wrong:
queryset = GolfMonthlyView.objects.all()
# ^^^^ ?? This is not a model
If you yank off the outer for loop for example, the inner loops should proceed if the QuerySets are not empty:
{% for competition in golftour %}
{% for golftournament in golftour.tournament_set.all %}
<ul>
<li>{{golftournament.name}}</li>
</ul>
{% endfor %}
{% endfor %}

Accessing dictionary values in django templates

Please help me in displaying the values of dictionary in django templates. I tried google to find out, but could not get the solution.
Below is the Model
class Ride(models.Model):
type = models.BooleanField(default=False)
add_source = models.ForeignKey(Address, related_name='source')
add_destination = models.ForeignKey(Address, related_name='destination')
ride_comment = models.TextField(null=True,max_length=140,blank=True)
def __unicode__(self):
return self.ride_comment
class Driver(models.Model):
ride_id = models.ForeignKey(Ride)
user_id = models.ForeignKey(User)
drv_carseats = models.SmallIntegerField(null=True,blank=False)
def __unicode__(self):
return self.user_id.username
View
for ride in result_list:
if ride.type:
driver = Driver.objects.get(ride_id = ride)
userList[ride.pk] = driver.user_id.username
print 'driver', driver.user_id.username, userList[ride.pk]
return render_to_response('rides/search.html', {'result_list':result_list,'userList':userList}, context )
And here is my template code
{% for result in result_list %}
{% if result %}
{{ userList[result.pk] }}
<em>{{ result.add_source }}</em>
<em>{{ result.add_destination }}</em>
<em>{{ result.ride_comment }}</em>
{% endif %}
{% endfor %}
I am getting the following error
TemplateSyntaxError at /rides/search/
Could not parse the remainder: '[result.pk]' from 'userList[result.pk]'
you should write a django custom filter for this.
create a file name get_dict_val.py inside your app..
project
-app
-templatetags
__init__.py
get_dict_val.py
Now in get_dict_val.py
#register.filter
def get_item(dictionary, key):
return dictionary.get(key)
In template
add this as first line write..
{% load get_dict_val %}
now replace in your code in template
{{ userList|get_item:result.pk }}
You don't need to create dictionary to access drivers at the template level, you can follow the relationship backward as Driver model has the foreign key for Ride model:
{% for result in result_list %}
{% if result %}
{% with result.driver_set.all as drivers %}
{% for driver in drivers %}
{{ driver.user_id }}
{% endfor %}
{% endwith %}
<em>{{ result.add_source }}</em>
<em>{{ result.add_destination }}</em>
<em>{{ result.ride_comment }}</em>
{% endif %}
{% endfor %}
It is good to specify the related_name for ForeignKey as it makes life easier to access objects:
ride_id = models.ForeignKey(Ride, related_name='drivers')
Then you can do:
ride = Ride.objects.get(id='some_id')
drivers = ride.drivers.all()

Categories