I'm working on multi-user rss reader. I want to limit display of posts only to those which are unread. I've managed to do this in my single "feed" view as below, but I can't figure out how to do the same in multiple feed aka "category" view.
I've been trying something like here https://docs.djangoproject.com/en/1.5/topics/db/queries/#spanning-multi-valued-relationships but it didn't work for me
Should I change my "category" view code or template code? and if so how would you go about it?
thanks!
-S
models
class UserCategory(models.Model):
name = models.CharField(unique=False, max_length=64)
user = models.ForeignKey(User)
slug = AutoSlugField(populate_from='name', always_update='True', unique_with='user')
class Feed(models.Model):
feed_url = models.URLField(unique=True)
default_title = models.CharField(max_length=64, blank=True)
link = models.URLField(blank=True)
class UserFeed(models.Model):
feed = models.ForeignKey(Feed)
title = models.CharField(max_length=64)
category = models.ForeignKey(UserCategory)
user = models.ForeignKey(User)
slug = AutoSlugField(populate_from='title', always_update='True', unique_with='user')
class Post(models.Model):
feed = models.ForeignKey(Feed)
title = models.CharField(max_length=256)
content = models.TextField()
link = models.URLField(max_length=512)
class ReadPost(models.Model):
user = models.ForeignKey(User)
post = models.ForeignKey(Post)
views
def feed(request, user_feed_slug):
user_feed = get_object_or_404(UserFeed.objects.filter(slug=user_feed_slug, user=request.user))
read_post = ReadPost.objects.filter(user=request.user).values_list('post')
posts = Post.objects.select_related().filter(feed=user_feed.feed).exclude(id__in=read_post)
def category(request, user_category_slug):
user_category = get_object_or_404(UserCategory.objects.filter(slug=user_category_slug, user=request.user))
templates
feed
{% for post in posts %}
{{ post.title }}
{% endfor %}
category
{% for feed in user_category.userfeed_set.all %}
{{ feed.title }}
{% for post in feed.feed.post_set.all %}
{{ post.title }}
{{ post.content }}
{% endfor %}
{% endfor %}
You can write custom template filter, i.e:
#register.filter
def unread(posts, read_posts):
return posts.exclude(id__in=read_posts)
(before you must pass read_post to category template context).
Try this queryset:
def category(request, user_category_slug):
user_category = get_object_or_404(UserCategory, slug=user_category_slug,
user=request.user))
feeds = UserFeed.objects.filter(category__slug=user_category_slug, user=request.user)\
.prefetch_related('feed__post_set')
then in your template:
{% for feed in feeds %}
{{ feed.title }}
{% for post in feed.feed.post_set.all %}
{{ post.title }}
{{ post.content }}
{% endfor %}
{% endfor %}
Related
I have multiple users in my project
my models.py file is
class User(AbstractUser):
is_student = models.BooleanField(default=False)
is_teacher = models.BooleanField(default=False)
class Teacher(models.Model):
user = models.OneToOneField(User,on_delete=models.CASCADE,primary_key=True,related_name='Teacher')
name = models.CharField(max_length=250)
subject_name = models.CharField(max_length=250)
email = models.EmailField(max_length=254)
phone = models.IntegerField()
teacher_profile_pic = models.ImageField(upload_to="classroom/teacher_profile_pic",blank=True)
def __str__(self):
return self.name
class Announcement(models.Model):
title = models.CharField(max_length=30)
content = models.TextField()
date_posted = models.DateTimeField(default=timezone.now)
teacher = models.ForeignKey(Teacher, on_delete=models.CASCADE)
def __str__(self):
return self.title
If the logged in user is a teacher it is allowed to create an announcement
Now i want that only the teacher who posted the announcement should be able to see the delete button
My html file is
{% extends "classroom/base.html" %}
{% block content %}
<h1>Announcements</h1>
{% for announcement in announcements %}
<!-- starting loop (posts is keyword from view) -->
<div style="border-style: solid;">
{% if object.teacher.id == request.teacher %}
<div>
Delete
</div>
{% endif %}
<a class="mr-2">Posted by: {{ announcement.teacher }}</a>
<h2><a class="article-title">{{ announcement.title }}</a></h2>
<p class="article-content">{{ announcement.content}}</p>
</div>
{% endfor %}
{% endblock content %}
the if statement is supposed to be true if logged in teacher is the teacher who originally posted it. However the delete button is visible for every announcement
my views.py has
class AnnouncementListView(ListView):
context = {
'announcements' : Announcement.objects.all()
}
model = Announcement
template_name = 'classroom/all_announcements.html'
context_object_name = 'announcements'
Try using this.
{% if announcement.teacher.user == request.user %}
<div>
Delete
</div>
{% endif %}
Your models are a bit "unconventional".
However, this should work:
{% if announcement.teacher.user == request.user %}
...
{% endif %}
I am working on a django project and I have 2 models that look like this:
class Playlist(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.CASCADE,related_name='playlist_user')
name = models.CharField(max_length=120)
image = models.ImageField(upload_to=upload_image_path)
genre = models.CharField(max_length=120,null=True,blank=True)
track = models.ManyToManyField('Post',related_name='playlist_track')
class Post(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.CASCADE)
title = models.CharField(max_length=120)
slug = models.SlugField(unique=True)
image = models.ImageField(upload_to=upload_image_path)
audiofile = models.FileField(upload_to=upload_image_path,null=True)
genre = models.CharField(max_length=120,null=True,blank=True)
and this view:
def userprofileview(request):
own_tracks = Post.objects.filter(user=request.user)
playlist_ = Playlist.objects.filter(user=request.user)
context = {
'own_tracks':own_tracks,
'playlist_':playlist_
}
return render(request,'userprofile.html',context)
but when I try to query the posts from the playlist like this:
{% for object in playlist_ %}
{{ object.track }}
{% endfor %}
I get:
posts.Post.None
Thank you for any suggestions
In order to access the related objects, you need to add .all at the end:
{% for object in playlist_ %}
{% for post in object.track.all %}
{{ post.title }}
{% endfor %}
{% endfor %}
To avoid the N+1 problem, you can use .prefetch_related(..) [Django-doc]:
def userprofileview(request):
own_tracks = Post.objects.filter(user=request.user)
playlist_ = Playlist.objects.filter(user=request.user).prefetch_related('post')
context = {
'own_tracks':own_tracks,
'playlist_':playlist_
}
return render(request,'userprofile.html',context)
I am creating a website with a collection of menus from restaurants in my town (since none of them seem to be on grubhub or the internet). I am having trouble creating a model for this. As you know every restaurant menu has sections(I.e Appetizers, Chicken, Steak) and entries under each section(I.e under Appetizers: Mozzarella Sticks, Nachos, etc.) I am trying to create a Menu model so that each section of the menu and all of its entries can automatically fill a template:
<h1>{{section}}</h1> <!--I.e:"Appetizers"-->
<p>{{food}} </p><!--I.e:"Mozzarella Sticks"-->
<p>{{ food_details }}</p>
With the above template, I can use a loop to loop through each section, then another inner loop to loop through each food and food_details belonging to that specific section, but I am not sure how to model this properly:
from django.db import models
class Restaurant(models.Model):
name = models.CharField(max_length=50)
address = models.CharField(max_length=80)
phoneNumber = models.CharField(max_length=10)
def __str__(self):
return "%s the place" % self.name
class Menu(models.Model):
restaurant = models.OneToOneField(
Restaurant,
on_delete=models.CASCADE,
primary_key=True,
)
# not sure how to build menu fields
#if I do the following each menu will only have one of these fields, which will not work:
section = models.CharField(max_length=50)
food = models.CharField(max_length=50)
food_details = models.CharField(max_length=200)
How can I create a model of a menu that has multiple section's and multiple food and food_details entries under each section? I hope this made sense, let me know if there is anything I can add and thanks in advance for any help.
You could try something like this:
# models.py
FOOD_TYPES = (
('appetizer', 'appetizer'),
('entree', 'entree'),
('dessert', 'dessert'),
)
class FoodItem(models.Model):
name = models.CharField(max_length=30)
description = models.CharField(max_length=100)
type = models.CharField(max_length=100, choices=FOOD_TYPES)
class Menu(models.Model):
restaurant = models.OneToOneField(
Restaurant,
on_delete=models.CASCADE,
primary_key=True,
)
food_items = models.ManyToManyField(FoodItem)
In a view:
# views.py
class Restaurant(TemplateView):
model = Restaurant
template_name = 'name'
...
def get_context_data
context = super(Menu, self).get_context_data(**kwargs)
restaurant = Restaurant.objects.get(name='McDonalds')
context['restaurant'] = Restaurant.objects.get(name='McDonalds')
context['menu'] = Menu.objects.get(restaurant=restaurant)
return context
In the template:
# template.html
<h1>{{ restaurant.name }}</h1>
<h2>Menu</h2>
{% for item in menu.food_items %}
{% if item.type = 'appetizer' %}
<p>
{{ item.name }}
{{ item.description }}
{{ item.type }}
</p>
{% else %}
<p>No appetizers</p>
{% endif %}
{% if item.type = 'entree' %}
<p>
{{ item.name }}
{{ item.description }}
{{ item.type }}
</p>
{% else %}
<p>No entrees</p>
{% endif %}
{% if item.type = 'dessert' %}
<p>
{{ item.name }}
{{ item.description }}
{{ item.type }}
</p>
{% else %}
<p>No dessert</p>
{% endif %}
{% endfor %}
I have 2 model objects, Business & BusinessImage as so, listed with views and index.html. I am trying to list the business's featured image, but it's not happening. I am getting the following error:
'QuerySet' object has no attribute 'businessimage_set'
How can I get the business featured image for a list?
Business
class Business(models.Model):
name = models.CharField("Name", max_length=70, default="Business Name")
slug = models.SlugField()
description = models.TextField("About", max_length=400)
category = models.ManyToManyField(Category, verbose_name="Categories", blank=True)
order = models.IntegerField("Order", default=0)
claimed = models.BooleanField("Claimed", default=False)
featured = models.BooleanField("Featured", default=False)
class Meta:
ordering = ['order']
verbose_name = "Business"
verbose_name_plural = "Businesses"
def __str__(self):
return self.name
BusinessImage
class BusinessImage(models.Model):
business = models.ForeignKey(Business)
image = models.ImageField(upload_to="images/business")
title = models.CharField(max_length=120)
featured = models.BooleanField(default=False)
timestamp = models.DateTimeField(auto_now_add=True, auto_now=False)
updated = models.DateTimeField(auto_now_add=False, auto_now=True)
def __str__(self):
return self.title
view.py
from .models import Business, BusinessImage
def index_view(request):
latest_business_list = Business.objects.all()
images = latest_business_list.businessimage_set.all()
template = loader.get_template('index.html')
context = RequestContext(request, {
'latest_business_list': latest_business_list,
'images': images,
})
return HttpResponse(template.render(context))
index.html
{% block content %}
<div class="text-center business_title">
<h2>Featured</h2>
</div>
{% if latest_business_list %}
{% for business in latest_business_list|slice:":4" %}
{% if business.active %}
<div class="col-sm-6 col-md-3">
<li>{{ business.name }}</li>
{% for image in latest_business_list.businessimage_set.all %}
{% if image.featured %}
<a href="{% url 'single_product' product.slug %}">
<img src="{{MEDIA_URL}}{{image.image}}" alt="{{image}}">
</a>
{% endif %}
{% endfor %}
</div>
{% endif %}
{% endfor %}
{% endif %}
{% endblock %}
businessimage_set is an attribute of a Business instance, but you're trying to access it as an attribute of a queryset (i.e. list of businesses). If your goal is just to be able to access the images for each business in a template, you can leave out images entirely. Instead your template would have:
{% for image in business.businessimage_set.all %}
(Though look into prefetch_related for efficiency.)
So I am just now getting to grips with Django,
I want to something relatively straughtforward. I have a model thus:
class Article(models.Model):
id = models.IntegerField(primary_key=True)
volnumber = models.IntegerField(db_column='volNumber')
title = models.TextField()
keywords = models.TextField(blank=True)
start_page = models.IntegerField(null=True, blank=True)
end_page = models.IntegerField(null=True, blank=True)
author_1 = models.TextField(blank=True)
author_2 = models.TextField(blank=True)
author_3 = models.TextField(blank=True)
author_4 = models.TextField(blank=True)
author_5 = models.TextField(blank=True)
author_6 = models.TextField(blank=True)
author_7 = models.TextField(blank=True)
author_8 = models.TextField(blank=True)
author_9 = models.TextField(blank=True)
author_10 = models.TextField(blank=True)
in my view:
def index(request):
article_list = Article.objects.all()
volume_list = Volume.objects.all()
auth_list = ['author_1', 'author_2', 'author_3', 'author_4', 'author_5', 'author_6', 'author_7', 'author_8', 'author_9', 'author_10', ]
return render_to_response('index.html', {
'article_list': article_list,
'volume_list': volume_list,
'auth_list' : auth_list,
})
and I want to iterate over the first articles authors, as well as eliminating empty entries for the list in the template:
<ul class="articleList">
{% for article in article_list %}
<li>
{% for author in auth_list %}
<i>{{ article."author" }}</i>
{% endfor %}
{{ article.title }}{{ article }}
</li>
{% endfor %}
</ul>
obviously that doesn't work, and I'm not sure the template is the place for this logic, but I hope from this it is clear what I am trying to achieve.
Any assistance much appreciated.
I am not sure you want to design a list of authors that way. If you want multiple authors, consider using a new model for Author and then using a ManyToManyField in your Article class to link articles to authors. Then, you can loop through authors in your template like so:
{% for author in article.authors.all %}
<!-- blah blah -->
{% endfor %}
Here is the Author model:
class Author(models.Model):
first_name = models.TextField(...) # don't copy to ..., put whatever params you need
last_name = models.TextField(...)
and the adjusted Article model:
class Article(models.Model):
# add this line
authors = models.ManyToManyField(Author)
Now you do not need to return an auth_list in your view code.
If you don't want to change your data model (although I strongly advice you to follow #andrew-lee suggestion) you are not allowed to call-by-name attributes in the templates. You should do:
# in the view
return render_to_response('index.html', {
'article_list': article_list,
'volume_list': volume_list,
'auth_list' : [getattr(article, name) for name in auth_list],
})
# in the template
{% for author in auth_list %}
<i>{{ author }}</i>
{% endfor %}
Building on what has already been said, it makes the most sense to change your model, but if you want to keep it as-is and display a list of only the author fields which have been filled in, you might do this in the template:
<ul class="articleList">
{% for article in article_list %}
<li>
{% for author in auth_list %}
{% if author %}
<i>{{ author }}</i>
{% endif %}
{% endfor %}
{{ article.title }}{{ article }}
</li>
{% endfor %}
</ul>