Getting values correctly while using Many to Many relation - django

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()

Related

DJANGO Supplement to the data list via an intermediate table

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.

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.

Django: How to render non-Boolean database rows as checkboxes?

My model:
class LineItems(models.Model):
descr = models.CharField(max_length=100)
cost = models.DecimalField(max_digits=5, decimal_places=2)
My form:
class LineItemsForm(forms.ModelForm):
class Meta:
model = LineItems
fields = ['descr', 'cost']
Can someone please tell me either 1) how to render all of the product rows as checkboxes or 2) the proper way to do this if I'm coming at it incorrectly?
Ok, then you should design your model this way:
class Product(models.Model):
description = models.TextField()
cost = models.CharField(max_length=100)
# 'cost' should be a CharField because you would want to save currency name also e.g. €
users dont need a checkbox to buy it, I think, more appropriate way would be just an html button called "put into cart", where users can put items into cart .. and then in cart page, you give users the chance to delete the selected items again. now you think further about next steps..
in the model form you can specify in the meta class
class Meta:
widgets = {
'descr': CheckboxInput()
}
something like that anyway.
CheckboxInput is in django.forms.widgets I believe
Found what I was looking for. In my form:
LINEITEM_CHOICES = [[x.id, x.descr] for x in LineItems.objects.all()]
class LineItemsForm(forms.Form):
food = forms.MultipleChoiceField(choices=LINEITEM_CHOICES,
widget=forms.CheckboxSelectMultiple(), required=False)
In my view:
{% for radio in lineItems.food %}
<div class="food_radios">
{{ radio }}
</div>
{% endfor %}
My code is based off of this post.
Thank you for your answers.

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

Django Templates: Accessing FK methods

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