I am running into an issue where my database is information is displaying on one template, but I want certain parts to display on another page for a blog.
When I click into physics-blog it will display my images and post title. For this, I have looped through the database. Works fine and perfectly.
But when I click into one of them and want to show {{ physicsBlog.body }} it doesn't show anything. Which I can't wrap my head around because that works just fine in the other ListView template, but not in the DetailView template.
Here is my code.
models.py
class physicsBlog(models.Model):
title = models.CharField(max_length=250)
blog_image = models.ImageField(null=True, blank=True)
description = models.CharField(max_length=200)
author = models.ForeignKey(User, on_delete=models.CASCADE)
body = RichTextField(blank=True, null=True)
date_created = models.DateField(auto_now_add=True)
def __str__(self):
return self.title + ' | ' + str(self.author)
views.py
class physicsBlogListView(ListView):
model = physicsBlog
template_name = 'physics.html'
ordering = ['-id']
class physicsBlogDetailView(DetailView):
model = physicsBlog
template_name = 'physics-blog-details.html'
urls.py
urlpatterns = [
path('', views.home, name="home"),
path('physics-blog', physicsBlogListView.as_view(), name="physics-blog"),
path('physics-blog/<int:pk>', physicsBlogDetailView.as_view(), name="physics-blog-details"),
path('crypto-blog', cryptoBlogListView.as_view(), name="crypto-blog"),
path('crypto-blog/<int:pk>', cryptoBlogDetailView.as_view(), name="crypto-blog-details"),
]
I'm not super familiar using these generic displays that Django provides, but from the django docs it says
While this view is executing, self.object will contain the object that
the view is operating upon.
So maybe try {{ object.body }} in your template?
You can use standard way of rendering data in standard single-object view (mostly DetailView):
{{ object.body }}
But if you want to see it better, just add context_object_name variable:
class physicsBlogDetailView(DetailView):
context_object_name = "physics_blog"
...
After such change in template:
{{ physics_blog.body }}
Without context_object_name it's object or object_list. I'm kinda surprised that you did ok in ListView and had problem in DetailView, because it's the same thing.
Related
I'm making a picture gallery web-app. I want to make some of displayed photos to belong to a specific collection. Each collection is supposed to have its own page that displays all of the pictures that belong to it.
The name of each unique page is supposed to be photo_collection model, which I added to the class Image in models.py. But for some reason, I get TypeError at /projects/sample_collection_name/ - photo_collection() got an unexpected keyword argument 'photo_collection'
No idea what's causing this error. I tried renaming the photo_collection function (it has the same name as my model), but it didn't work.
models.py
class Image(models.Model):
title = models.CharField(max_length=300)
image = models.ImageField(null=True, blank=True, upload_to='images/')
pub_date = models.DateTimeField('Date published', default=timezone.now)
photo_collection = models.CharField('Photo collection', max_length=250, null=True, blank=True)
views.py
def photo_collection(request):
image = Image.objects.all()
return render (request, 'photo_app/collection.html', context={'image': image})
urls.py
urlpatterns = [
#some other patterns here
path('projects/<str:photo_collection>/', views.photo_collection, name='photo_collection'),
]
gallery.html
{% if i.photo_collection != Null %}
{{i.photo_collection}}
{% endif %}
you need to add photo_collection to your view parameters.
it will be like this:
def photo_collection(request, photo_collection):
image = Image.objects.all()
return render (request, 'photo_app/collection.html', context={'image': image})
when ever you add a variable to your url path you need to add that variable to view parameters too.
here is the documentation for this matter:
https://docs.djangoproject.com/en/4.1/topics/http/urls/
I have a simple ManyToOne relationship where users can post comments to a poller object.
Comments Model
class Comments(models.Model):
poller = models.ForeignKey(Pollers, on_delete=models.CASCADE, related_name='comments')
created_on = models.DateTimeField(auto_now_add=True)
comment = models.CharField(max_length=250)
created_by = models.CharField(max_length=80)
class Meta:
ordering = ['created_on']
def __str__(self):
return 'Comment {} by {}'.format(self.body, self.name)
The View
def single_poller(request, poller_id):
"""retrieves the item clicked by the user from DB and renders
the single_poller template for further user interaction
"""
# Retrieve the item via get
poller = Pollers.objects.get(poller_id=poller_id)
# Increase the view field of the object by
poller.poller_views += 1
# Save the changed instance and overwrite new view integer
poller.save()
# Get the form for comments
form = CommentsForm
context = {
'poller': poller,
'form': form
}
return render(request, 'pollboard/single_poller.html', context)
Now I want to render the comments for each poller into my template like so
<div id="comments-choice-one-wrapper" class="comments-wrapper">
{{ poller.comments.comment }}
</div>
Somehow it doesn't render the comment I created beforehand. I checked in Django admin if the comment is rly related to the poller and this looks just fine.
poller.comments.all is a QuerySet of Comments, so this is a collection, therefore it makes no sense to use .comment since that is an attribute of a Comment object, not an attribute of QuerySet with comments.
You can enumerate over the comments.all, and thus render these comments individually:
<div id="comments-choice-one-wrapper" class="comments-wrapper">
{% for comment in poller.comments.all %}
{{ comment.comment }}
{% endfor %}
</div>
In you Comments model, using self.name or self.body makes not much sense, since that model has no name property or field. You likely should use the __str__ on the Poller:
class Comments(models.Model):
# ⋮
def __str__(self):
return f'Comment {self.comment} by {self.poller}'
Note: normally a Django model is given a singular name, so Comment instead of Comments.
I've added photologue to my project, because it does 99% of the things I was trying to achieve by myself.
Now I need to connect the uploaded images and images in galleries to my posts. This is why I've added a ManyToMany field to the photologue Photo model
Class ImageModel(models.Model):
post_images = models.ManyToManyField(Post, blank=True)
And will do the same to the Gallery model
class Gallery(models.Model):
post_gallery = models.ManyToManyField(Post, blank=True)
Now my idea is to be able to add a gallery and/or specific images to my post . Both options should be available.
The queryset I would like to have is to get all the individual images, that are attached to the post and also all the images in the gallery if a gallery is attached. Then to pass and render them to the page in some sort of gallery (Slider, carousel or something else).
I'd like to be able to get them in the template with one for loop, so I think the queryset have to be one.
I have a view that renders the specific page type and I don't know if I should include the queryset and context in this function or to create a new one for the images. And how to do it.
def post(request, slug):
post = get_object_or_404(Post, post_slug=slug)
context = {
'post': post,
}
return render(request, 'project_name/post.html', context)
I hope I have explained what I'd like to do. Django is new to me and querysets are still a bit complex.
Shouldn't you try adding galleriesto posts from posts?
from photologue.models import Gallery
class Post(models.Model):
gallery = models.ManyToManyField(Gallery, blank=True )
#Edit ___
#TwinDewey In this case you need to make a query in Views to get the Galleries when showing Post details.
galleries = gallery.posts.all()
gal = []
for excercise in excercises:
gal.append(Gallery.objects.filter(gallery__name=self.post.title))
Or you can make a query and merge it with the Post context using
from itertools import chain
list(chain(post_context,Gallery.objects.filter(gallery__name=self.post.title)))
That´s for gallery. Posts would have another query.
You can use union to group the photos tied to the post itself and inside the gallery. The trick is to get the right models so they are the same objects:
from django.db import models
from photologue.models import Gallery, Photo
class Post(models.Model):
title = models.CharField(max_length=100)
published_at = models.DateTimeField(blank=True, null=True)
text = models.TextField()
photos = models.ManyToManyField(Photo, related_name='posts')
galleries = models.ManyToManyField(Gallery, related_name='posts')
#property
def all_images(self):
# Create a number of querysets that have photos from selected galleries
# ..note:
# .only() is used to trim down on the fields fetched from the database.
# .prefetch_related() is used to eliminate extra queries during iteration
qs = []
for gallery in self.galleries.prefetch_related('photos').only('photos'): # type: Gallery
qs.append(gallery.photos.only('image', 'title'))
return self.photos.only('image', 'title').union(*qs)
Now you can use it in a template like so:
{% for photo in post.all_images %}
<img src="{{ photo.image.url }}" alt="{{ photo.title }}" />
{% endfor %}
I am compiling a database of articles and have my model set up like this:
class articles(models.Model):
ArticleID = models.IntegerField(primary_key=True)
Title = models.CharField(max_length=500)
Author = models.CharField(max_length=200, null=True)
Journal = models.CharField(max_length=500, null=True)
Date = models.IntegerField(null=True)
Issue = models.IntegerField(null=True)
Link = models.URLField(max_length=800, null=True)
Content = models.TextField()
class Meta:
db_table = 'TEST'
def __str__(self):
return f'{self.Title}, {self.Author}, {self.Journal},{self.Date}, {self.Issue}, {self.Content}'
def get_absolute_url(self):
return reverse('article-detail', args=[str(self.ArticleID)])
The idea is pretty simple. Each meta data type (i.e. title, author) is it's own field, and the actual content of the article is in the field Content.
My view for this model:
def article_detail(request, ArticleID):
ArticleID = get_object_or_404(articles, ArticleID=ArticleID)
context = {'ArticleID': ArticleID}
return render(request, 'article_detail.html', context)
The HTML template for the view:
{% extends 'base.html' %}
{% block content %}
<div class="container">
{{ ArticleID }}
</div>
{% endblock %}
The data displayed in on the HTML page is one big block of text in one single HTML element. How can I make it so that I can use CSS to target each individual field from the model? Must I make separate models for each field (and bound them with foreign keys)?
No of course not. You can access fields with normal dot notation: ArticleID.Title, ArticleID.Author, etc.
(But you shouldn't call your context variable ArticleID; it's the whole article, not the ID. Also, Python style is to use lower_case_with_underscore for variables and attribute names.)
There is already a primary key in for every model which is called id, you don't have to explicitly declare that.
Secondly you are getting an article object with get_object_or_404 so if you use . (dot) notation you will get your desired value in your template.
Something like-
<h2>{{article.Title}}</h2>
<p>{{article.Content}}</p>
though you have to send article names instead of ArticleID in context variable.
In addition to Mr. Daniel Roseman's comment you should use class name Article instead of articles which is not pythonic.
I'm building a CMS for my company's website (I've looked at the existing Django solutions and want something that's much slimmer/simpler, and that handles our situation specifically.. Plus, I'd like to learn this stuff better). I'm having trouble wrapping my head around generic relations.
I have a Page model, a SoftwareModule model, and some other models that define content on our website, each with their get_absolute_url() defined. I'd like for my users to be able to assign any Page instance a list of objects, of any type, including other page instances. This list will become that Page instance's sub-menu.
I've tried the following:
class Page(models.Model):
body = models.TextField()
links = generic.GenericRelation("LinkedItem")
#models.permalink
def get_absolute_url(self):
# returns the right URL
class LinkedItem(models.Model):
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = generic.GenericForeignKey('content_type', 'object_id')
title = models.CharField(max_length=100)
def __unicode__(self):
return self.title
class SoftwareModule(models.Model):
name = models.CharField(max_length=100)
description = models.TextField()
def __unicode__(self):
return self.name
#models.permalink
def get_absolute_url(self):
# returns the right URL
This gets me a generic relation with an API to do page_instance.links.all(). We're on our way. What I'm not sure how to pull off, is on the page instance's change form, how to create the relationship between that page, and any other extant object in the database. My desired end result: to render the following in a template:
<ul>
{% for link in page.links.all %}
<li><a href='{{ link.content_object.get_absolute_url() }}'>{{ link.title }}</a></li>
{% endfor%}
</ul>
Obviously, there's something I'm unaware of or mis-understanding, but I feel like I'm, treading into that area where I don't know what I don't know. What am I missing?
How are the LinkedItem associated with a Page? A GenericRelation is used for a reverse relationship, but as it stands now there isn't any relationship so it has nothing to match to. I think this is what you're looking for in your model design:
class Page(models.Model):
body = models.TextField()
# Moved generic relation to below
class LinkedItem(models.Model):
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = generic.GenericForeignKey('content_type', 'object_id')
# LinkedItems now relate to a Page model, and we're establishing the relationship
# by specifying 'links' to keep the syntax you're looking for
page = models.ForeignKey(Page, related_name='links')
title = models.CharField(max_length=100)
On a side note, this model setup allows one LinkedItem to relate to a Page. If you wanted to re-use linkeditems, you could make it a M2M:
class Page(models.Model):
body = models.TextField()
links = models.ManyToManyField(LinkedItem)
class LinkedItem(models.Model):
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = generic.GenericForeignKey('content_type', 'object_id')
title = models.CharField(max_length=100)
In both of these instances, page.links.all() will be all of the linked items.
Also, parenthesis aren't used in the template syntax.
I haven't seen templates access managers directly before as in the use of page.links.all
From my understanding you need to pull back the links as a list in a view and pass that as a variable to the template. Also, you need to resolve any foreign keys ahead of time which you can do by using select_related.
ie.
def some_view(request,*args,**kwargs):
...
page_links = page_instace.links.select_related().all()
...
return render_to_response(
'the_template.html',
#extra_context to pass to the template as var_name:value
{
"page_links":page_links,
},
# needed if you need access to session variables like user info
context_instance=RequestContext(request)
)
then in the template...
<ul>
{% for link in page_links %}
<li><a href='{{ link.content_object.get_absolute_url() }}'>{{ link.title }}</a></li>
{% endfor%}
</ul>
see
http://docs.djangoproject.com/en/1.1/ref/models/querysets/#id4
I'd have given more links but stack wouldn't let me.
Why are you trying to access link.content_object inside the page.link.all() list? Inside this list, link.content_object will always be the same as page.
I don't think I understand what you're trying to do here, but right now that code should generate a list of links all to the current page with the link.title text.
Can you explain what you are trying to do with LinkedItem?