I want to do something like
{% if "sumit" in feed.like.person.all %}
But this gives me TemplateSyntaxError. How can I do this in Djagno ?
(Basically, I want to check if 'sumit' exists in feed.like.person.all)
Here are my relevant models.
class Feed(models.Model):
name = models.CharField(max_length=120)
text = models.CharField(max_length=1200)
timestamp = models.DateTimeField(auto_now=True, auto_now_add=False)
updated = models.DateTimeField(auto_now=False, auto_now_add=True)
class Like(models.Model):
feed = models.OneToOneField(Feed)
counter = models.PositiveIntegerField()
person = models.ManyToManyField(settings.AUTH_USER_MODEL, null=True, blank=True)
I think you intended to check the following:
# check if current user likes a feed
{% if request.user in feed.like.person.all %}
But if you are checking this for multiple feeds, then this method becomes inefficient. For multiple feeds, better approach is to use Annotations as mentioned by #AKS.
Your approach to check if a user likes a feed within the templates by querying for each feed is very inefficient.
I would suggest using Conditional Expressions to annotate each feed while fetching the queryset:
from django.db.models import BooleanField, Case, When, Value
feeds = Feed.objects.all().annotate(
is_liked=Case(
When(like__person=request.user, then=Value(True)),
default=Value(False),
output_field=BooleanField()))
This way you would be getting everything in one query only. And, then in the template you can just check is_liked on the feed:
{% if feed.is_liked %}You like this.{% endif %}
I haven't really executed this query but looking at the documentation it would be something similar.
Related
I have models that inherit from an abstract model like this:
class ImprovementAbstraction(models.Model):
needsImprovement = models.BooleanField()
hasFallacies = models.BooleanField()
hasEmotionalDeficiency = models.BooleanField()
isNecessaryToObtain = models.BooleanField()
doesAReallyCauseB = models.BooleanField()
areAllStepsPresent = models.BooleanField()
isCauseSufficient = models.BooleanField()
areAllClausesIdentified = models.BooleanField()
isCausalityCertain = models.BooleanField()
languageIsEnglish = models.BooleanField()
isTautologyPresent = models.BooleanField()
class Meta:
abstract = True
class Assumption(MainAbstractModel, ImprovementAbstraction):
need = models.ForeignKey(Need, on_delete=models.SET_NULL, null=True)
assumption = models.CharField(max_length=500, default="", null=True)
def __str__(self):
return self.assumption
In the template I would like to display all of the "ToImprovementAbstraction" Model fields associated with the Assumption model. Is there a way to loop over all the fields in the template, something like Assumption.ImprovementAbstractionFields.all() (made up code)?
I use the built-in vars() method for that.
For example, you have an Assumption object:
assumptionObject = .models.Assumption.objects.get(pk=1)
If you use vars() method with that query object like this:
vars(assumptionObject)
it will return a dictionary containing all the field names and values as a Python dictionary.
If you only want the field names you can use it like this:
vars(assumptionObject).keys()
EDIT: I should warn you that, if you use vars() on a query object, the returned dictionary will contain a django.db.models.base.ModelState object stored in a key called _state. If you're going to use the values in a for loop or something, you should put an exception for that.
Not exactly sure what your desired outcome is, but this is the basic approach to query data from the database and render the html:
You will first have to query the data from the database like so:
Views.py
def search(request):
queryset = ToImprovementAbstraction.objects.all()
context = {
'queryset': queryset
}
return render(request, 'your_template.html', context)
Then you can use the data to render your template like so:
your_template.html
{% for item in queryset %}
<p>{{ item.needsImprovement }}</p>
[...]
[...]
{% endfor %}
If oyu have multiple models you can make multiple queries to use one/many-to-many fields in your models to link them straight away.
get the assumption object in view and render the ImprovementAbstraction through foreign key. for example:
def get_item():
queryset = Assumption.objects.all()
return render(request, 'template.html', {'queryset': queryset})
Now in your template you can access the data this way
{% for query in queryset %}
{{query.need.needImprovement}}
{{query.need.hasFallacies}}
{{...}}
{% endfor %}
This way you can display everything in one loop. Hope this gets you some idea.
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 have three different models for my app. All are working as I expected.
class Tender(models.Model):
title = models.CharField(max_length=256)
description = models.TextField()
department = models.CharField(max_length=50)
address = models.CharField(max_length=50)
nature_of_work = models.CharField(choices=WORK_NATURE, max_length=1)
period_of_completion = models.DateField()
pubdat = models.DateTimeField(default=timezone.now)
class Job(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL)
title = models.CharField(max_length=256)
qualification = models.CharField(max_length=256)
interview_type = models.CharField(max_length=2, choices=INTERVIEW_TYPE)
type_of_job = models.CharField(max_length=1, choices=JOB_TYPE)
number_of_vacancies = models.IntegerField()
employer = models.CharField(max_length=50)
salary = models.IntegerField()
pubdat = models.DateTimeField(default=timezone.now)
class News(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL)
title = models.CharField(max_length=150)
body = models.TextField()
pubdat = models.DateTimeField(default=timezone.now)
Now I am displaying each of them at separate page for each of the model (e.g. in the jobs page, I am displaying only the jobs.). But now at the home page, I want to display these according to their published date at the same page. How can I display different objects from different models at the same page? Do I make a separate model e.g. class Post and then use signal to create a new post whenever a new object is created from Tender, or Job, or News? I really hope there is a better way to achieve this. Or do I use multi-table inheritance? Please help me. Thank you.
Update:
I don't want to show each of the model objects separately at the same page. But like feeds of facebook or any other social media. Suppose in fb, any post (be it an image, status, share) are all displayed together within the home page. Likewise in my case, suppose a new Job object was created, and after that a new News object is created. Then, I want to show the News object first, and then the Job object, and so on.
A working solution
There are two working solutions two other answers. Both those involve three queries. And you are querying the entire table with .all(). The results of these queries combined together into a single list. If each of your tables has about 10k records, this is going to put enormous strain on both your wsgi server and your database. Even if each table has only 100 records each, you are needlessly looping 300 times in your view. In short slow response.
An efficient working solution.
Multi table inheritance is definitely the right way to go if you want a solution that is efficient. Your models might look like this:
class Post(models.Model):
title = models.CharField(max_length=256)
description = models.TextField()
pubdat = models.DateTimeField(default=timezone.now, db_index = True)
class Tender(Post):
department = models.CharField(max_length=50)
address = models.CharField(max_length=50)
nature_of_work = models.CharField(choices=WORK_NATURE, max_length=1)
period_of_completion = models.DateField()
class Job(Post):
user = models.ForeignKey(settings.AUTH_USER_MODEL)
qualification = models.CharField(max_length=256)
interview_type = models.CharField(max_length=2, choices=INTERVIEW_TYPE)
type_of_job = models.CharField(max_length=1, choices=JOB_TYPE)
number_of_vacancies = models.IntegerField()
employer = models.CharField(max_length=50)
salary = models.IntegerField()
class News(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL)
def _get_body(self):
return self.description
body = property(_get_body)
now your query is simply
Post.objects.select_related(
'job','tender','news').all().order_by('-pubdat') # you really should slice
The pubdat field is now indexed (refer the new Post model I posted). That makes the query really fast. There is no iteration through all the records in python.
How do you find out which is which in the template? With something like this.
{% if post.tender %}
{% else %}
{% if post.news %}
{% else %}
{% else %}
Further Optimization
There is some room in your design to normalize the database. For example it's likely that the same company may post multiple jobs or tenders. As such a company model might come in usefull.
An even more efficient solution.
How about one without multi table inheritance or multiple database queries? How about a solution where you could even eliminate the overhead of rendering each individual item?
That comes with the courtesy of redis sorted sets. Each time you save a Post, Job or News, object you add it to a redis sorted set.
from django.db.models.signals import pre_delete, post_save
from django.forms.models import model_to_dict
#receiver(post_save, sender=News)
#receiver(post_save, sender=Post)
#receiver(post_save, sender=Job)
def add_to_redis(sender, instance, **kwargs):
rdb = redis.Redis()
#instead of adding the instance, you can consider adding the
#rendered HTML, that ought to save you a few more CPU cycles.
rdb.zadd(key, instance.pubdat, model_to_dict(instance)
if (rdb.zcard > 100) : # choose a suitable number
rdb.zremrangebyrank(key, 0, 100)
Similarly, you need to add a pre_delete to remove them from redis
The clear advantage of this method is that you don't need any database queries at all and your models continue to be really simple + you get catching thrown in the mix. If you are on twitter your timeline is probably generated through a mechanism similar to this.
The following should do want you need. But to improve performance you can create an extra type field in each of your models so the annotation can be avoided.
Your view will look something like:
from django.db.models import CharField
def home(request):
# annotate a type for each model to be used in the template
tenders = Tender.object.all().annotate(type=Value('tender', CharField()))
jobs = Job.object.all().annotate(type=Value('job', CharField()))
news = News.object.all().annotate(type=Value('news', CharField()))
all_items = list(tenders) + list(jobs) + list(news)
# all items sorted by publication date. Most recent first
all_items_feed = sorted(all_items, key=lambda obj: obj.pubdat)
return render(request, 'home.html', {'all_items_feed': all_items_feed})
In your template, items come in the order they were sorted (by recency), and you can apply the appropriate html and styling for each item by distinguishing with the item type:
# home.html
{% for item in all_items_feed %}
{% if item.type == 'tender' %}
{% comment "html block for tender items" %}{% endcomment %}
{% elif item.type == 'news' %}
{% comment "html block for news items" %}{% endcomment %}
{% else %}
{% comment "html block for job items" %}{% endcomment %}
{% endif %}
{% endfor %}
You may avoid the annotation altogether by using the __class__ attribute of the model objects to distinguish and put them in the appropriate html block.
For a Tender object, item.__class__ will be app_name.models.Tender where app_name is the name of the Django application containing the model.
So without using annotations in your home view, your template will look:
{% for item in all_items_feed %}
{% if item.__class__ == 'app_name.models.Tender' %}
{% elif item.__class__ == 'app_name.models.News' %}
...
{% endif %}
{% endfor %}
With this, you save extra overhead on the annotations or having to modify your models.
A straight forward way is to use chain in combination with sorted:
View
# your_app/views.py
from django.shortcuts import render
from itertools import chain
from models import Tender, Job, News
def feed(request):
object_list = sorted(chain(
Tender.objects.all(),
Job.objects.all(),
News.objects.all()
), key=lambda obj: obj.pubdat)
return render(request, 'feed.html', {'feed': object_list})
Please note - the querysets mentioned above using .all() should be understood as placeholder. As with a lot of entries this could be a performance issue. The example code would evaluate the querysets first and then sort them. Up to some hundreds of records it likely will not have a (measurable) impact on performance - but in a situation with millions/billions of entries it is worth looking at.
To take a slice before sorting use something like:
Tender.objects.all()[:20]
or use a custom Manager for your models to off-load the logic.
class JobManager(models.Manager):
def featured(self):
return self.get_query_set().filter(featured=True)
Then you can use something like:
Job.objects.featured()
Template
If you need additional logic depending the object class, create a simple template tag:
#templatetags/ctype_tags.py
from django import template
register = template.Library()
#register.filter
def ctype(value):
return value.__class__.__name__.lower()
and
#templates/feed.html
{% load ctype_tags %}
<div>
{% for item in feed reversed %}
<p>{{ item|ctype }} - {{ item.title }} - {{ item.pubdat }}</p>
{% endfor %}
</div>
Bonus - combine objects with different field names
Sometimes it can be required to create these kind of feeds with existing/3rd party models. In that case you don't have the same fieldname for all models to sort by.
DATE_FIELD_MAPPING = {
Tender: 'pubdat',
Job: 'publish_date',
News: 'created',
}
def date_key_mapping(obj):
return getattr(obj, DATE_FIELD_MAPPING[type(obj)])
def feed(request):
object_list = sorted(chain(
Tender.objects.all(),
Job.objects.all(),
News.objects.all()
), key=date_key_mapping)
Do I make a separate model e.g. class Post and then use signal to
create a new post whenever a new object is created from Tender, or
Job, or News? I really hope there is a better way to achieve this. Or
do I use multi-table inheritance?
I don't want to show each of the model objects separately at the same
page. But like feeds of facebook or any other social media.
I personally don't see anything wrong using another model, IMHO its even preferable to use another model, specially when there is an app for that.
Why? Because I would never want to rewrite code for something which can be achieved by extending my current code. You are over-engineering this problem, and if not now, you are gonna suffer later.
An alternative solution would be to use Django haystack:
http://haystacksearch.org/
http://django-haystack.readthedocs.io/en/v2.4.1/
It allows you to search through unrelated models. It's more work than the other solutions but it's efficient (1 fast query) and you'll be able to easily filter your listing too.
In your case, you will want to define pubdate in all the search indexes.
I cannot test it right now, but you should create a model like:
class Post(models.Model):
pubdat = models.DateTimeField(default=timezone.now)
tender = models.ForeignKey('Tender')
job = models.ForeignKey('Job')
news = models.ForeignKey('News')
Then, each time a new model is created, you create a Post as well and relate it to the Tender/Job/News. You should relate each post to only one of the three models.
Create a serializer for Post with indented serializers for Tender, Job and News.
Sorry for the short answer. If you think it can work for your problem, i'll write more later.
I have my models like this:
class Personne(BaseModel):
# [skip] many fields then:
photos = models.ManyToManyField(Photo, blank=True,
through='PersonnePhoto',
symmetrical=False,
related_name='parent')
def photo_profil(self):
a = PersonnePhoto.objects.filter(
personne=self, photo_type=PersonnePhoto.PHOTO_PROFIL)
return a[0] if len(a) else None
# [skip] many fields then:
travels = models.ManyToManyField(
TagWithValue, blank=True,
through='PersonneTravel',
default=None, symmetrical=False,
related_name='personne_travel')
class PersonneRelation(BaseModel):
src = models.ForeignKey('Personne', related_name='src')
dst = models.ForeignKey('Personne', related_name='dst')
opposite = models.ForeignKey('PersonneRelation',
null=True, blank=True, default=None)
is_reverse = models.BooleanField(default=False)
I need to show all contacts of one person, and for each contact, show all his/her travels, and his/her photo.
Here's my code in my view:
class IndexView(LoginRequiredMixin, generic.TemplateView):
template_name = 'my_home/contacts/index.html'
def get_context_data(self, **kwargs):
context = super(IndexView, self).get_context_data(**kwargs)
context['contacts'] = Personne.objects.get(
user=self.request.user).relations.all()
return context
Pretty simple.
The problem is in my template. my_home/contacts/index.html includes contact_detail.html for each contact:
{% for c in contacts %}
{% with c as contact %}
{% include 'includes/contact_detail.html' %}
{% endwith %}
{% endfor %}
In contact_detail.html, I call photo_profil, which makes a query to get the value of the picture of the contact.
{{ contact.photo_profil }}
This implies that if a user has 100 contacts, I will do one query for all his contacts, then 100 queries for each contact. How is it possible to optimize this? I have the same problem for travels, and the same problem for each ManyToMany fields of the contact, actually.
Looks like you need some prefetch_related goodness:
context['contacts'] = (Personne.objects
.get(user=self.request.user)
.relations
.all()
.prefetch_related('travels', 'photos'))
Note, however, that it will fetch all the contacts' photos, which is not you seem to expect. Basically you have two options here. Either add some hairy raw SQL to the Prefetch object's queryset parameter. Or (as I did in one of the projects) designate a separate main_photo field for storing the user's avatar (a separate ForeignKey to the Photo, I mean, not the completely independent one). Yes, it's clearly a denormalization, but queries become much more simple. And your users get a way to set a main photo, after all.
my title may not be very clear.
The problem I am facing now is:
my view passes arbitrary keyword arguments to another view.
This view handles with what info(keyword arguments it gets)
This is the example of search feature I am implementing.
Each user will have a list of Saved Searches. when they click on any one of the items in Search list, they will be directed to a different view that process the information it receives
In the Searches model, I have defined a get_absolute_url method that constructs the URL pattern of each of these search (based on models in the field).
my model:
class Searches(models.Model):
SELLER_CHOICES=(('OWNER','owner'),
('DEALER','dealer'),
('BOTH','both'), )
#search_id = models.IntegerField(primary_key=True)
user = models.ForeignKey(User)
make = models.CharField(max_length=100, blank=True)
model = models.CharField(max_length=100, blank=True)
keywords = models.CharField(max_length=100, blank=True)
max_price = models.IntegerField(blank=True, null=True)
min_price = models.IntegerField(blank=True, null=True)
max_year = models.IntegerField(blank=True, null=True)
min_year = models.IntegerField(blank=True, null=True)
pic_only = models.NullBooleanField()
search_title_only = models.NullBooleanField()
owner_dealer_all = models.CharField(max_length=10,choices=SELLER_CHOICES,verbose_name='owner/dealer')
class Meta:
#managed = False
db_table = 'Searches'
verbose_name_plural = "Searches"
def __unicode__(self):
return "%s %s %s-%s" %(self.make,self.model,self.max_year,self.min_year)
def get_absolute_url(self):
return reverse('postings.views.detail',args=[model_to_dict(self.object)])
view:
class SearchListView(ListView):
model=Searches
template:
{% extends "base.html" %}
{% block content %}
{% for obj in object_list %}
<p>{{ obj }}</p>
{% endfor %}
{% endblock %}
you can see from the image, when I click the your searches, I get error;
Reverse for 'postings.views.detail' with arguments '({'owner_dealer_all': u'DEALER', 'pic_only': True, 'make': u'toyota', u'id': 3, 'min_year': 1990, 'min_price': 4000, 'user': 1, 'keywords': u'hybrid', 'search_title_only': True, 'model': u'prius', 'max_price': 20000, 'max_year': 2012},)' and keyword arguments '{}' not found. 0 pattern(s) tried: []
Basically, I dont know how to handle this in the URL pattern.
OR
IF THIS IS A BAD DESIGN, PLEASE PLEASE SUGGEST A SOLUTION
If you really need to have all the variables in the URL, then you need to pass the variables as params of a GET query, so your URL will look like this:
http://example.com/search?owner_dealer_all=DEALER&pic_only=True&make=toyota&id=3&min_year=1990&min_price=4000&user=1&keywords=hybrid&search_title_only=True&model=prius&max_price=20000&max_year=2012
But, I would strongly suggest that you keep that URL as separate from the Search.get_absolute_url result, as the latter is supposed to point to the actual model. So have that function return something like:
http://example.com/search/23465
where the number is the ID for your Search model instance. In that view, get all the saved details and make a search on them. If you actually don't need the data in your URL, simply opt for the latter version only.