DJANGO Supplement to the data list via an intermediate table - django

I have an intermediate models connection
Simplified:
class Person(models.Model):
first_name = models.CharField(max_length=20)
last_name = models.CharField(max_length=20)
etc...
class Company(models.Model):
name = models.CharField(max_length=60)
etc...
class CompanyEnrollment(models.Model):
person = models.ForeignKey(Person, on_delete=models.CASCADE)
company = models.ForeignKey(Company, on_delete=models.CASCADE)
company_position =
models.ForeignKey(CompanyPosition,on_delete=models.CASCADE)
etc...
class Meta:
unique_together = [['person', 'company']]
class CompanyPosition(models.Model):
name = models.CharField(max_length=60)
I want to create the following array:
datas = Person.objects.All(...{All elements of Person model supplemented with CompanyPosition_name}...)
There is a case where a person does not have a company_name association
Is it possible to solve this with a query?

If you have an explicit through model for your many-to-many relationship, you could use this to only get or exclude based on the entries of this table, using an Exists clause:
enrollments = CompanyEnrollment.objects.filter(person_id=OuterRef('pk'))
enrolled_persons = Person.objects.filter(Exists(enrollments))
unenrolled_persons = Person.objects.filter(~Exists(enrollments))
If you don't have an explicit intermediate table, then it's has been generated by Django directly. You should be able to use it by referring to it with Person.enrollments.through instead of CompanyEnrollment.
Since you did not detailed much the CompanyEnrollment table, I assumed you're in the second case.

This is not the best solution in my opinion, but it works for now, with little data. I think this is a slow solution for a lot of data.
views.py I will compile the two necessary dictionaries
datas = Person.objects.all().order_by('last_name', 'first_name')
companys = CompanyEnrollment.objects.all()
Use Paginator
p = Paginator(Person.objects.all(), 20)
page = request.GET.get('page')
pig = p.get_page(page)
pages = "p" * pig.paginator.num_pages
Render HTML:
context = {
"datas": datas,
"pig": pig,
"pages": pages,
"companys": companys,
}
return render(request, "XY.html", context)
HTML template:
{% for datas in pig %}
{{datas.first_name}} {{datas.last_name}}
{% for company in companys %}
{% if datas == company.person %}
{{company.company.name}} <br>
{% endif %}
{% endfor %}
{% endfor %}
not the most beautiful, but it works ... I would still accept a more elegant solution.

Related

Perform query in django against another table, but its not finding the table

I am trying to perform a query via a join.
My models.py looks like:
class TSFH(models.Model):
sB = models.DateTimeField(null=True)
sE = models.DateTimeField(null=True)
FKToUser = models.ForeignKey(User,default=None, on_delete=models.PROTECT)
class Tld(models.Model):
dNm = models.CharField(verbose_name="",max_length=40,unique=True)
FKToUser = models.ForeignKey('auth.user', default=None, on_delete=models.PROTECT)
class TSF(models.Model):
FKToT = models.ForeignKey('T', on_delete=models.PROTECT)
FKToTSFH = models.ForeignKey('TSFH', on_delete=models.PROTECT, null=True, blank=True)
views.py
enteredd = request.GET.get('d', '')
query=TSFH.objects.filter(FKToT__dNm=enteredd,FKToUser=request.user,sE__isnull=False)
return render(request, 'view.html', {'q':q})
templates/file.html
{% if q %}
{% for res in q %}
<li><span>{{ res.sE }}</span></li>
{% endfor %}
{% else %}
{% endif %}
When I view this all it complains about:
Cannot resolve keyword 'FKToT' into field
In plain sql I'm looking to perform the following just with dNm search directly from the enteredd instead of a hardcoded value of 123.145.23.1 as shown below:
SELECT sE
FROM tsfh, tsf, t
where
tsfh.id=tsf.FKTotsfh_id
and
t.id=tsf.FKToT_id
and
tsfh.sE is not null
and
t.dNm='123.145.23.1';
How can I keep these existing checks in the query but include this FKToT__dNm=enteredd somehow?
Thank you very much.
Do a little modification at this line:
query=TSFH.objects.filter(TST__FKToT__dNm=......)
If you put this meta into your class, it will specifically name the table.
class Meta:
db_table = '<your_table_name>'
You can read more here.

Query optimization: howto

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.

How to access properties of another table in one-to-many relationship using django template language?

I would like to use properties from different tables connected with one-to-many relationship in hardcoded img src in the template.
Models.py:
class Offers(models.Model):
province = models.CharField()
district = models.CharField()
location = models.CharField()
class OffersPhotos(models.Model):
offers_id = models.ForeignKey('Offers')
order = models.IntegerField()
Views.py:
def index(request):
latest_offers = Offers.objects.order_by('-creation_date')[:5]
context_dict = {'latest_offers': latest_offers}
return render(request, 'something.html', context_dict)
Template:
{% for offer in latest_offers %}
<img src="http://something.com/{{offer.id}}/{{offer.offersphotos.id}}.jpg">
{% endfor %}
{{offer.id}} works perfectly but how can I access id of the photo that has order=1 in the same line?
I think is not a good idea to query all the offerphotos given an offer and getting the first one in a template.
Instead you can define a property in your Offers class, soy you can get the first photo.
It should be something like this:
Models.py
class Offers(models.Model):
province = models.CharField()
district = models.CharField()
location = models.CharField()
def first_offerphoto(self):
return self.offerphotos_set.first()
Template
{% for offer in latest_offers %}
<img src="http://something.com/{{offer.id}}/{{offer.first_offerphoto.id}}.jpg">
{% endfor %}
Although you can still using the logics in your template:
<img src="http://something.com/{{offer.id}}/{{offer.offerphotos_set.first.id}}.jpg">
But i rather doing all queries before displaying info into templates

How do I access the elements from this queryset in a template?

Here is the queryset:
researches = Graph.objects.filter(subject=subject_object).exclude(type='infografik').values_list('name', flat=True).distinct()
When I do:
{% for research in researches %}
in my template, the code in between executes the right amount of times, but for example {{ research.name }} doesn't work.
How to I access the object's attributes?
Thanks.
edited:
Graph model
name = models.CharField(max_length=100)
research = models.ForeignKey('Research')
explanation = models.TextField(max_length=1000)
path_to_file = models.CharField(max_length=100)
type = models.CharField(max_length=30, choices=type, null=True, blank=True)
subject = models.ManyToManyField(Subject)
thumbnail = models.ImageField(upload_to='thumbnails/', null=True, blank=True)
slug = models.SlugField(max_length=120, unique=True)
From the doc:
Each tuple contains the value from the respective field passed into the values_list()
So to print research names just do :
{% for research in researches %}
{{ research }}
{% endfor %}
Because you are asking for a flat list of values, there are no attributes to access. If you want access to all of the attributes, use either this query researches = Graph.objects.filter(subject=subject_object).exclude(type='infografik').distinct() which will return a queryset that can be iterated over or this one researches = Graph.objects.filter(subject=subject_object).exclude(type='infografik').values().distinct() which will return a list of dicts. In django's template language, you can access attributes in both like so:
{% for research in researches %}
{{ research.name }}
{{ research.author }}
...
{% endfor %}
The only way I know of to also get distinct objects is to use raw sql:
researches = Graph.objects.raw('SELECT * FROM appname_graph WHERE subject_id = %s AND type <> %s GROUP BY name', [subject_object.id, 'infografik'])

subquery in django

I have 2 models:
class Professors(models.Model):
professors_name = models.CharField('professor', max_length=32, unique=True)
class Discipline(models.Model):
auditorium = models.IntegerField('auditorium')
professors_name = models.ForeignKey(Professors)
In views:
disciplines = Discipline.objects.all()
So, I have number of auditorium and professors_name_id. But I need full profrssors name, not id. How to do it?
Models:
# models usually named in the singular
class Professor(models.Model):
professors_name = models.CharField('professor', max_length=32, unique=True)
class Discipline(models.Model):
auditorium = models.IntegerField('auditorium')
# your pointer is to a professor, not to the name
professor = models.ForeignKey(Professor)
In view:
# select_related('professor') to avoid a second query when accessing professor
disciplines = Discipline.objects.select_related('professor')
Template:
{% for disc in disciplines %}
{{ disc.auditorium }}: {{ disc.professor.name }}
{% endfor %}
For values:
Discipline.objects.values('auditorium', 'professor__name')
Django ORM will always returns the objects not the ids. You should have a design like this.
class Professor(models.Model):
name = models.CharField('professor', max_length=32, unique=True)
class Discipline(models.Model):
auditorium = models.IntegerField('auditorium')
professor = models.ForeignKey(Professors)
and use discipline.professor.name to retrieve the name alone.