Django Templates: Accessing FK methods - django

Good Afternoon,
I'd like to be able to display a returned value from a method that is in a foreign table (the template obj shares a one-many relationship):
models.py
class teacher(stuff):
name = models.charfield()
website = models.URLField()
slug = models.SlugField(max_length=255, db_index=True, unique=True)
def get_page_url(self):
return reverse('teacher_page', args=[self.slug])
class homework(stuff):
assignment = models.ForeignKey(teacher)
due_date = models.DateField()
other assignment stuff..
I pass the assignment object into my template, and can access it's attributes like so:
{{homework.due_date}}
but let us say I want to display the page of the teacher who has assigned the homework. I thought I should be able to access it like so:
<a href='{{homework.teacher_set.get_page_url}}'>teacher page</a>
But this just results in an attribute error.
How can I get the url?
NOTE: This example was written on the fly for the purpose of conveying the question only. No syntax trolls!

Since it is a forward relationship, you would just do
{{homework.assignment.get_page_url}}
Further, if you are looking for a reverse foreign key relationship, you would do
{{teacher.name}}
{% for homework in teacher.homework_set.all %}
{{homework.due_date}}
{% endfor %}
because teacher.homework_set returns a Manager

Related

Django foreign key not getting data

I have two tables defined in my models:
class Products(models.Model):
productsid = models.AutoField(primary_key=True)
product_number = models.CharField(db_index=True, max_length=15)
title = models.CharField(max_length=255, default=None, null=True, blank=True)
date = models.DateField(db_index=True, default=datetime.date.today, null=True, blank=True)
class ProductFlag(models.Model):
product_number = models.CharField(db_index=True, max_length=15)
company = models.ForeignKey(Company, db_index=True, on_delete=models.SET_NULL, null=True)
productid = models.ForeignKey(Products, db_column='productsid', db_index=True, on_delete=models.SET_NULL, null=True)
I want to get the the 'title' from Products when I query ProductFlag.
In my views, I make this query:
productflags = ProductFlag.objects.filter(company__companyid=self.kwargs.get('company_id')).order_by('product_number')
I thought that I could then reference the title field in my template by looping through {% for product in productflags %} and
grabbing {{ product.productid.title }}, but I get nothing at all. Looking at it in the Django shell, it seems that my productid is always "None" (and my database definitely had data in productsid). I have no issue with the company foreign key. What am I doing wrong?
My apologies, I had a typo. I am referencing product.productid.title inside the loop in my template; product_number was in error. I have double-checked my database as well, and there is data in all the fields referenced.
I don't know that this will help, but in the django shell I get this behavior:
testflags = ProductFlag.objects.filter(company__companyid=43).order_by('product_number') gets a queryset of about seven. If I then try to access testflags[0].company.companyname, I get the actual company name. On the other hand, if I try to access testflags[0].productid.title, I get "AttributeError: 'NoneType' object has no attribute 'title'".
Also, if I try "testflags = ProductFlag.objects.select_related('productid').filter(company__companyid=43).order_by('product_number')" the query sees the column names in Products, but accessing them with productid, gives that AttributeError.
In pgAdmin, this query works just fine:
SELECT a.product_number, b.title
FROM productflag AS a
INNER JOIN products AS b
ON a.product_number = b.product_number
AND a.company_id = 43;
Thanks--
Al
From your snippet here:
{% for product in productflags %}
{{ product_number.productid.title }}
{% endfor %}
It looks like you're referencing the wrong variable name, because on loop, it's declared as product but you then go on to use product_number?
Try changing product_number to product or vice-versa.
Edit: Based on the new information it seems you have a typo in the filter part of your query. Try company_id rather than companyid.
.filter(company__company_id=43)
I believe the issue is in your loop. You need to access the title with
{{ product.productid.title }}
This is assuming the query set contains some data.
Thanks to everyone. You got me to look more closely at my code. It seems that my ProductFlag table was not being properly populated with the productid; so it was using a null value for its foreign key relationship with Products... No valid key = no valid data.

Can I have data from different fields of a model returned as separate HTML elements? (Django 2.1)

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.

Getting values correctly while using Many to Many relation

I have standart User model and Categories model like this;
class Categories(models.Model):
name=models.CharField(max_length=100)
def __str__(self):
return self.name
And here is another class for relation which associates some users with some categories;
class Interested(models.Model):
user = models.ManyToManyField(User)
category = models.ManyToManyField(Categories)
For example if I have Users such as Bob, Eric, Oliver, Michael
and categories such as Basketball, Football
and relations like that
Bob -> Basketball,Football
Eric-> Basketball
Oliver -> Football
(michael not interested in anything)
I want to get list of who interested in what? How can I handle this? Thank you for your help.
You can get the instance of Interested for a user with:
interested = Interested.objects.get(user="your user")
and list the linked categorys by:
interested.category.all()
But I would, if not nescessary for any other reason, just link the category directly to the user....
class Category(models.Model):
name = models.Charfield()
user = models.ManyToManyField(user)
This way you can get the categorys for a user:
categorys = Category.objects.filter(user="youruser")
and if you pass this to your template just do:
{% for category in categorys %} {{ category.name }}{% endfor %}
To get the users interested in a category, just get the Category instance with:
category = Category.objects.get(name="categoryname")
and the the related user models with:
usersincategory = category.user.all()
if you want this for all categorys just use a normal for loop:
categorys = Category.objects.all()
for category in categorys:
category.user.all()

Custom managers in a Many-to-Many relation for usual filters

class Proposal(models.Model):
author = models.ForeignKey(Person, related_name="author")
def get_tags(self):
return Tag.objects.filter(tagged_proposals=self.id)
class Tag(models.Model):
tagged_proposals = models.ManyToManyField(Proposal)
name = models.CharField(primary_key=True, max_length=60)
I need to list the proposal's tags on a certain template so I would write {% for tag in proposal.get_tags %} and it works perfectly.
Now I read about Managers and it seems a good move to convert my get_tags into a Manager. I tried the following but it didn't output a thing. What am I doing wrong? Does it make sense to turn it a Manager in the first place?
class ProposalsTagsManager(models.Manager):
def get_query_set(self):
proposal_id = how-do-i-get-the-proposal-id???
return Tag.objects.filter(tagged_proposals=proposal_id)
usage: {% for tag in p.tags.all %} output: nothing
You don't need a custom function for this.
When a table is being referenced with a ManyToManyField you get a method called MODEL_set to get a queryset of that model.
So in your case you can reference all your tags like this:
proposal = Proposal.objects.get(pk=1)
tags = proposal.tag_set.all() # You can also use filter here

django many to many get attributes from other object

So I've been using django for a while now, and it's great. I've recently come across a little bit of a problem, and I'm sure there's a crappy way to get it to work, but what I've found with Django is that they've usually built in all sorts of mechanisms to do things for you. So what I'm not finding is this:
Here are my models:
class LandmarkGroup(models.Model):
Name = models.CharField(max_length=150)
Description = models.CharField(max_length=300, blank=True)
IsActive = models.BooleanField(default=True)
landmarks = models.ManyToManyField('Landmark', blank=True, null=True)
def __unicode__(self):
return self.Name
class Landmark(models.Model):
Name = models.CharField(max_length=150)
Description = models.CharField(max_length=300, blank=True)
Polygon = models.PolygonField()
IsActive = models.BooleanField(default=True)
objects = models.GeoManager()
def __unicode__(self):
return self.Name
I also have another model 'Team' that has a ManyToMany with LandmarkGroup, but I'm not going to post it here. I have a view where I query for all the landmarks that have a landmarkgroup that has a team with the same team id as the one I passed in:
def mobile_startup(request):
...
landmarkGroups = LandmarkGroup.objects.filter(team=device.team, IsActive=True)
landmarks = Landmark.objects.filter(landmarkgroup__team=device.team, IsActive=True)
...
return render_to_response('webservice/mobile_startup.html', {'landmarks': landmarks, 'landmarkGroups': landmarkGroups})
Everything works, the only problem I'm having is, I'm returning this all as JSON to the mobile app, and I want to provide the landmarkGroup id for the landmark, so in my template I've been trying to:
"landmarkGroup" : {{ landmark.landmarkgroup.id }} }
but that's not working. Does anyone know any way I can get the landmarkGroup ID for each landmark in my set? Do I need to extract it when I do the query? I know I can reference each landmarkGroup in the query because I can do 'landmarkgroup__team=device.team', but I need to able to reference this object in the template
LandmarkGroup.landmarksis a ManyToManyField,therefore one Landmark can belong to multiple groups.
You should be able to output them in your template like this:
{% for group in landmark.landmarkgroup_set.all %}{{ group.pk }}{% endfor %}
The first group belonging to the landmark should be accessible through {% landmark.landmarkgroup_set.all.0 %}