Access Many-to-Many relationship data in template - python

I am new to django and trying to model a OOP concept.
I have model for actor and movies. Movie have many-to-many relationship with actor model.
url.py
from movies import views
url(r'^recent/$', views.recentlyadded, {'movieid': 1}),
models.py
from django.db import models
class Actor(models.Model):
actorid = models.AutoField(primary_key=True)
name = models.CharField(max_length=250)
sex = models.CharField(max_length=1)
class Movie(models.Model):
movieid = models.AutoField(primary_key=True)
title = models.CharField(max_length=250)
actor = models.ManyToManyField(Actor)
view.py
from movies.models import *
def recentlyadded(request, movieid):
m = get_object_or_404(Movie, pk = movieid)
return render_to_response('search_results.html', {'movies': m})
search_results.html
{% if movies %}
{{movies.title}}
<ul>{{ movies.actor_set.all.count }}
{% for actor in movies.actor_set.all %}
<li>{{actor.name}}</li>
{%endfor%}
</ul>
{% endif %}
Output
The Dark Knight
I am not getting the actor list at all.
Should I use a intermediary model? If yes, what will happen if I have to associate directors to the movie model? How many intermediary model should be created?
Please help with the code. Thanks in advance.

Try to access to movies.actor directly
{% if movies %}
{{movies.title}}
<ul>{{ movies.actor.all.count }}
{% for actor in movies.actor.all %}
<li>{{actor.name}}</li>
{%endfor%}
</ul>
{% endif %}

Related

What is the proper approach to get data with one to many relationship

I am following a tutorial in Django where I found a certain for loop to get the entities in a model which is actually filtering the data.
The below is the model (models.py)
class Brand(models.Model):
name = models.CharField(max_length=30)
origin = models.CharField(max_length=50)
class Model(models.Model):
brand = models.ForeignKey(Brand, on_delete=models.CASCADE)
model_name = models.CharField(max_length=30)
class Review(models.Model):
article = models.CharField(max_length=2000)
label_model = models.ManyToManyField(Model)
The below is the views.py
from django.views import generic
from .models import Brand
from .models import Model
from .models import Review
class BrandListView(generic.ListView):
template_name = 'phonereview/brands.html'
context_object_name = 'all_phone_brands'
def get_queryset(self):
return Brand.objects.all()
class ModelDetailView(generic.DetailView):
model = Brand
template_name = 'phonereview/models.html'
class ReviewDetailView(generic.DetailView):
model = Model
template_name = 'phonereview/reviews.html'
The below is the template
1) Listing brands (tempates/appname/brands.html)
<ul>
{% for brand in all_phone_brands %}
<li>
<a href = "{% url 'phonereview:models' brand.slug %}">
{{ brand.name }}
</a>
</li>
{% endfor %}
</ul>
Here the all_phone_brands is coming from views.py.
2) Template for listing phone models
<ul>
{% for model_item in brand.model_set.all %}
<li>
<a href="{% url 'phonereview:reviews' model_item.slug %}">
{{ model_item.model_name }}
</a>
</li>
{% endfor %}
</ul>
Even though the code works, I am not sure putting brand.model_set.all is the proper approach. I guess, there must be a better approach then this.
Can anyone help me doing it in a proper way?
Use prefetch_related to optimize the query as,
Brand.objects.prefetch_related('model_set')
see the documentation for more details.

display model fieldnames in Django listview

In my listview I want to display several fields from two models containing a many-to-many field.
I can display the correct values from one table, but then I cannot access the other table with the many-to-manyfield.
Models.py
class Books(models.Model):
title = models.CharField(max_length=100)
class Author(models.Model):
book = models.ManyToManyField(Books)
first_name = models.CharField(max_length=150)
last_name = models.CharField(max_length=200)
Views.py
class BooksListView(ListView):
context_object_name = 'booklist'
model = Author
template_name = 'Books/books_list.html'
Book_list.html
{% for books in booklist %}
<h5><li class="list-group-item list-group-item-light"">
{{books.book.all}}:{{books.first_name}} {{books.last_name}}</li></h5>
{% endfor %}
The first and lastname are displayed properly, but the books.book.all ()i know this is the wrong query) returns a queryset containing the title (which is what I need, but this is in format <QuerySet [<Books: Book Title>]>. But books.book.title doesnt seem to work. What I want to display is "booktitle - firstname lastname", and because I am using two tables, I need a many-to-many relationship. Any thoughts?
The many-to-many relationship goes both ways, so you don't need to base everything around authors.
class BooksListView(ListView):
context_object_name = 'booklist'
model = Book
template_name = 'Books/books_list.html'
And the template:
{% for books in booklist %}
<li class="list-group-item list-group-item-light">
<h5>{{ book.title }}</h5>
<p>
{% for author in book.author_set.all %}
{{ author.first_name }} {{ author.last_name }}{% if not forloop.last %}, {% endif %}
{% endfor %}
</p>
</li>
{% endfor %}
Notes:
By default, the related_name is {{ModelName}}_set (author_set in this case). If you want something more natural you can set related_name='authors'.
There will be a query made to the databse for every book in the list and this can be quite slow with a lot of data, so take a look at prefetch_related().

Django - Forms - assign custom attributes to forms in forms.py

The question title might be a little misleading, but I couldn't think of a better title. If you've got better title, please edit the title.
I have following set of models.py and forms.py`
# models.py
class BHA_Component(models.Model):
field_1 = models.CharField(max_length=100)
field_2 = models.CharField(max_length=100)
field_3 = models.CharField(max_length=100)
# forms.py
class BHA_Component_Form(forms.ModelForm):
class Meta():
fields = '__all__'
I want to create custom attributes for each field, so that I can identify what kind of field it is on the Front-End, and assign a class for each field type.
Something like this:
Some fields are just plain blank, some are grey, some are purple, and some have check boxes. These are done by manually giving each field a particular HTML class on the Front-End. However, I want to give each field some attributes on the Back-End, and have those attributes identified on the Front-End. So, something like this:
{% for field in bha_component_form %}
{% if field.custom_attribute == 'option_1' %}
{{ field|add_class:"has_checkbox"}}
{% else if field.custom_attribute == 'option_2' %}
{{ field|add_class:"blue_background"}}
{% else %}
{{ field|add_class:"plain"}}
{% endif %}
{% endfor %}
How can I do this?
To pass in attributes on the backend you can try something likes this:
email = forms.EmailField(widget=forms.EmailInput(attrs={'class': "form_control form-control-lg", 'placeholder': "Email"}), required=True, )
So, for your specific case:
models.py:
class BHA_Component(models.Model):
field_1 = models.CharField(max_length=100, widget=forms.TextInput(attrs={'custom_attribute': "option_1") })
field_2 = models.CharField(max_length=100, widget=forms.TextInput(attrs={'custom_attribute': "option_2") })
field_3 = models.CharField(max_length=100, widget=forms.TextInput() })
It should be a case of using something like this in your template:
{% for field in bha_component_form %}
{% if field.widget.attrs.custom_attribute == 'option_1' %}
{{ field|add_class:"has_checkbox"}}
{% else if field.widget.attrs.custom_attribute == 'option_2' %}
{{ field|add_class:"blue_background"}}
{% else %}
{{ field|add_class:"plain"}}
{% endif %}
{% endfor %}
It should just be a case of modifying what I have outlined above for your specific use case.
Hope that helps!

Look up field from a different Django model given another model field

I have two models in Django: Room for offices, and Person for employees. One office could have multiple employees. I'm trying to make a detail-view html page that shows a person's details, like their name and office number. I can get the details from the Person model fine, but I'm having trouble doing a reverse look-up to the Room model. How can I get a person's office given the following code?
#models.py
class Room(models.Model):
number = models.CharField('Room number', unique=True)
persons = models.ManyToManyField('Person', blank=True)
#...
class Person(models.Model):
name = models.CharField('Full name', max_length=200)
#...
#views.py
from django.views import generic
class PersonDetailView(generic.DetailView):
model = Person
#person_detail.html
{% extends "base_generic.html" %}
{% block content %}
<h1>Name: {{ person }}</h1>
<p>Room: {{ Room.number }}</p>
{% endblock %}
All that currently does is return a name, but "Room" is left blank.
You could overload the get_context_data method
class PersonDetailView(DetailView):
model = Person
context_object_name = 'person'
template_name = 'person_detail.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
# woops, typo
# context['room'] = Room.objects.filter(person=context['object']).first()
context['room'] = Room.objects.filter(persons=context['object']).first()
return context
And the template:
#person_detail.html
{% extends "base_generic.html" %}
{% block content %}
<h1>Name: {{ person }}</h1>
<p>Room: {{ room.number }}</p>
{% endblock content %}
Edit:
But you might be better off with Person having a models.ForeignKey pointing to a Room, so a Person can only have one Room, but many Person can have the same Room.
You could then keep your orginal view and change your template:
#person_detail.html
{% extends "base_generic.html" %}
{% block content %}
<h1>Name: {{ person }}</h1>
<p>Room: {{ person.room.number }}</p>
{% endblock content %}

django categories: How to get children of a category using django-categories?

I am using django-categories to implement music related app. I want artist as my category and his/her songs as children
models.py
from django.db import models
from django_extensions.db.fields import AutoSlugField
from categories.models import CategoryBase
class Artist(CategoryBase):
cat = models.CharField(max_length=255, blank=True)
def __unicode__(self):
return self.name
class Song(models.Model):
title = models.CharField(max_length=255,)
slug = AutoSlugField(populate_from='title', unique=True)
description = models.TextField()
cat = models.ForeignKey(Artist, blank=True)
def __unicode__(self):
return self.title
In templates, artist_details.html
{% extends 'base_post.html' %}
{% load category_tags %}
{% block page_content %}
<h1>{{ artist.name }}</h1>
{% if artist.children.count %}
<h2>Subcategories</h2>
<ul>
{% for child in artist.children.all %}
<li>{{ child }}</li>
{% endfor %}
</ul>
{% endif %}
The template is getting rendered coz I can see artist's name. But i am unable to fetch the children. I checked the docs but I could not find much stuff related to fetching children.
There is data for both models in my DB, I added relevant info via admin interface. Can anyone tell me what I am missing ?
Also I open to using better packages. You can give any suggestions that implements categories.
SOLUTION: From django docs https://docs.djangoproject.com/en/1.6/topics/templates/#accessing-method-calls
thanks mariodev
Even using django-categories, you can't have songs as children of artists. Artists just do not form a category.
What you instead want is something like this:
from django.db import models
from django_extensions.db.fields import AutoSlugField
from categories.models import CategoryBase
class MusicCategory(CategoryBase):
# add extra fields, like images, "featured" and such here
pass
class Artist(CategoryBase):
name = CharField(max_length=255,)
categories = models.ManyToManyField(MusicCategory, related_name="artists")
def __unicode__(self):
return self.name
class Song(models.Model):
slug = AutoSlugField(populate_from='title', unique=True)
title = models.CharField(max_length=255,)
artist = models.ForeignKey(Artist, related_name="songs", on_delete=models.PROTECT)
categories = models.ManyToManyField(MusicCategory, related_name="songs")
description = models.TextField()
def __unicode__(self):
return self.title
and with some templates
{% extends 'base_post.html' %}
{% load category_tags %}
{% block page_content %}
<h1>{{ artist.name }}</h1>
{% if artist.songs.all.exists %}
<h2>Songs</h2>
<ul>
{% for song in artist.songs.all %}
<li>{{ song }}</li>
{% endfor %}
</ul>
{% endif %}
REF: https://django-categories.readthedocs.org/en/latest/custom_categories.html#creating-custom-categories

Categories