Why _set.all dont work in tempale? - python

I have 3 connected with each other models. GroupRequirementType --> GroupRequirement --> Requirement. I am tring to show all requirements in template. Next code show me only GroupRequirementType objects. It seems like I have problems with _set.all. Whats wrong?
models.py:
class GroupRequirementType(models.Model):
name = models.CharField(_('Name'), max_length=250)
class GroupRequirement(models.Model):
group_requirement_type = models.ForeignKey(GroupRequirementType, on_delete=models.CASCADE)
name = models.CharField(_('Name'), max_length=250)
class Requirement(models.Model):
group_requirement = models.ForeignKey(GroupRequirement, on_delete=models.CASCADE)
name = models.CharField(_('Name'), max_length=250)
template:
{% for group_requirement_type in group_requirement_types %}
{{ group_requirement_type }}
{% for group_requirement in group_requirement_type.group_requirement_set.all %} <!--DONT WORK. WHY?-->
{{ group_requirement }}
{% for requirement in group_requirement.requirement_set.all %}
{{ requirement }}
{% endfor %}
{% endfor %}
{% endfor %}

It looks like Django doesn't automatically add an underscore when converting the CamelCase model name to lower case. grouprequirement_set.all works.

I'd highly recommend using Django ForeignKey related_name property in your models declaration, this makes backwards relations operations much easier: https://docs.djangoproject.com/en/1.11/ref/models/fields/#django.db.models.ForeignKey.related_name
In your case it will turn into something like
models.py:
class GroupRequirementType(models.Model):
name = models.CharField(_('Name'), max_length=250)
class GroupRequirement(models.Model):
group_requirement_type = models.ForeignKey(GroupRequirementType, related_name='group_requirements', on_delete=models.CASCADE)
name = models.CharField(_('Name'), max_length=250)
class Requirement(models.Model):
group_requirement = models.ForeignKey(GroupRequirement, related_name='requirements', on_delete=models.CASCADE)
name = models.CharField(_('Name'), max_length=250)
template:
{% for group_requirement_type in group_requirement_types %}
{{ group_requirement_type }}
{% for group_requirement in group_requirement_type.group_requirements.all %} <!--DONT WORK. WHY?-->
{{ group_requirement }}
{% for requirement in group_requirement.requirements.all %}
{{ requirement }}
{% endfor %}
{% endfor %}
{% endfor %}

Related

Django AdminInline on many-to-many relationship

I have two models like this:
class ArtCollection(models.Model):
# nothing important in this case
class Artwork(models.Model):
...
name = models.CharField(max_length=200, null=True, blank=True)
art_collections = models.ManyToManyField("ArtCollection", related_name="artworks")
image = models.ImageField(...)
Recently, I've change the relationship between them from FK for ArtCollection on Artwork model to m2m (as seen as above). What I would like to have now is something that I had before, particulary ArtworkInline in admin panel on ArtCollection change view (editable artwork fields like name, image change and so on). But it doesn't work. The only solution I've came across is this one (I know I should make an image preview rather than display its name - but its just an example):
from inline_actions.admin import InlineActionsMixin, InlineActionsModelAdminMixin
class ArtworkInline(admin.StackedInline):
model = ArtCollection.artworks.through
extra = 0
fields = ['artwork_image']
readonly_fields = ['artwork_image']
def artwork_image(self, instance):
return instance.artwork.image
artwork_image.short_description = 'artwork image'
class ArtCollectionAdmin(InlineActionsModelAdminMixin, admin.ModelAdmin):
...
inlines = [ArtworkInline]
Is it possible to have the editable fields in m2m relationship in inline django panel? I also use grappeli and custom template for inline (which are useless after changing the relationship - they have worked pretty well with FK, now I can have only readable_fields on default template).
{% extends 'admin/stacked_inline.html' %}
{% block fieldset %}
<fieldset class="module aligned {{ fieldset.classes }}">
{% for line in fieldset %}
{% with forloop.counter as counter %}
{% for field in line %}
{{ field.errors }}
{% if counter == 2 or counter == 6 %}
{% elif counter <= 7 %}
<p>{{ field.field }}</p>
{% endif %}
{% endfor %}
{% endwith %}
{% endfor %}
</fieldset>
{% if inline_admin_formset.formset.can_delete and inline_admin_formset.has_delete_permission and inline_admin_form.original %}
<span class="delete">{{ inline_admin_form.deletion_field.field }} {{ inline_admin_form.deletion_field.label_tag }}</span>
{% endif %}
{% endblock %}
Thanks for any advices.

How can I get item from a model field

I'm a Django beginner, how can I get profile_pic from Profile Model connecting it to 'to_user' field in FriendRequest Model.
I was able to get the names of users in 'to_user' field by this:
{% for data in sent_friend_request %}
{{ data.to_user.username }}
{% endfor %}
How do I get the profile_pic for each users?
class Profile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL)
profile_pic = models.ImageField()
class FriendRequest(models.Model):
to_user = models.ForeignKey(settings.AUTH_USER_MODEL)
from_user = models.ForeignKey(settings.AUTH_USER_MODEL)
def following_view(request, username):
sent_friend_request = FriendRequest.objects.filter(from_user__username=username)
context = {'sent_friend_request':sent_friend_request}
{% if data.to_user.profile_pic %}
<img src="{{ data.to_user.profile_pic }}">
{% endif %}
You can do like this:
{% if data.to_user.profile.profile_pic %}
<img src="{{ data.to_user.profile.profile_pic.url }}">
{% endif %}

how to show data from 2 models in django with one to many relashion in template

Hello i have 2 classes in my model:
class MO (models.Model):
many variables
class PhotoMO (models.Model):
mo = models.ForeignKey(MO, on_delete=models.CASCADE)
photo = models.ImageField(
upload_to='img/photo/%Y/%m/'
)
my views for template
class MOListView(DetailView):
template_name = 'main_site/mo_view.html'
model = models.MO
with template :
{% block content %}
<h1>{{ mo.name }}</h1>
<h3>{{ mo.phone_number }}</h3>
<h3>{{ mo.email_mo }}</h3>
<h3>{{ mo.adress_mo }}</h3>
{% for photos in mo.photomo.set.all %}
<img src="{{ photos.photo.url }}" alt="no img">
{% endfor %}
{% endblock %}
How can I display all the pictures from PhotoMO that refer to a specific entry in MO. With my "for" it dosen't work
You need to set the back relation:
class PhotoMO (models.Model):
mo = models.ForeignKey(MO, on_delete=models.CASCADE, related_name='photomo')
Then migrate the database to be able to access photomo.
Kind regards.
{% for photo in mo.photomo_set.all %}
<img src="{{ photo.photo.url }}" alt="none">
{% endfor %}
need to use mo.photomo_set.all

Is it possible to have two verbose_names in a Django Model?

I have a model that is defined like so...
class Message(models.Model):
email_subject = models.CharField(max_length=100, null=False, blank=False)
email = models.TextField(null=False, blank=False)
In want to be able to assign each of those fields two separate verbose_names(one in English, and one in Arabic). So that when I make a ModelForm, and render it to my template... I can do something like this...
{% for field in form %}
<p>
{% if field.field.required %}
<label for="{{ field.arabic_verbose_name}}" class='RequiredLabel'>{{ field.name }}</label>
{% else %}
<label for="{{ field.auto_id }}">{{ field.verbose_name}}</label>
{% endif %}
{% if field.errors %}
<div class='FieldErrorBox'>{{ field }}</div>
{% else %}
{{ field }}
{% endif %}
</p>
{% endfor %}
Is this possible?
from django.utils.translation import ugettext_lazy
class Message(models.Model):
email_subject = models.CharField(ugettext_lazy('Message field', 'email subject'), max_length=100, null=False, blank=False)
email = models.TextField(ugettext_lazy('Message field', 'email address'), null=False, blank=False)
Django internationalization can take care of this task. Coupled with a package like django-modeltranslation can often simplify the task. It's worth doing some tutorials to connect the dots. When using translatable strings in templates, there's tags (generally {% trans %}) to be used so that the correct lookups are performed.

Django Category Model and Template View Issue

My question is two phased but it's from the same Django Model. I am trying to get my Category model to work properly with my Petition model. Currently,
I get this 'FieldError' error when I define a queryset for my 'CategoryView' class:
Cannot resolve keyword 'created_on' into field. Choices are: description, id, petition, slug, title
Here is the code for the 'CategoryView' class:
class CategoryView(generic.ListView):
model = Category
template_name = 'petition/category.html'
context_object_name = 'category_list'
def get_queryset(self):
return Category.objects.order_by('-created_on')[:10]
Here is the code in my models.py:
class Category(models.Model):
title = models.CharField(max_length=90, default="Select an appropriate category")
slug = models.SlugField(max_length=200, unique=True)
description = models.TextField(null=False, blank=False)
class Meta:
verbose_name_plural = "Categories"
def __str__(self):
return self.title
def get_absolute_url(self):
return "/categories/%s/"%self.slug
class Petition(models.Model):
title = models.CharField(max_length= 90, default="Enter petition title here")
created_on = models.DateTimeField(auto_now_add=True)
image = models.ImageField(null=False, upload_to=imageupload)
video = models.CharField(max_length=600, default="Enter an external video link")
petition = models.TextField(null=False, default="Type your petition here")
created_by = models.ForeignKey(User)
category = models.ManyToManyField(Category)
def total_likes(self):
return self.like_set.count()
def __str__(self):
return self.title[:50]
def get_signatures(self):
return self.signature_set.all()
I get the 'FieldError' on my category view template (category.html) when the 'get_queryset()' has been defined.
When I comment it out, the page displays but posts are not retrieved; I get a list of the categories instead. Here is my category view template(category.html):
{% include 'layout/header.html' %}
{% load humanize %}
<div class="container content">
<div class="row">
<div class="col-md-8 post-area">
{% if category_list %}
{% for petition in category_list %}
<div class="petition-block">
<h2 class="home-title">{{petition.title}}</h2>
<span class="petition-meta">
Created {{petition.created_on|naturaltime}} by
{% if petition.created_by == user %}
You
{% else %}
#{{ petition.created_by }}
{% endif %}
{% if petition.created_by == user %}
Edit
{% endif %}
{% if petition.created_by == user %}
Delete
{% endif %}
</span>
{% if petition.image %}
<img src="{{ petition.image.url }}" alt="petition image" class="img-responsive" />
{% endif %}
</div><!--//petition-block-->
{% endfor %}
{% else %}
<p>Sorry, there are no posts in the database</p>
{% endif %}
</div>
<div class="col-md-4">
<h3>Topics</h3>
<ul>
{% for petition in category_list %}
<li>{{petition.title}}</li>
{% endfor %}
</ul>
</div>
</body>
</html>
What am I doing wrong? Please help.
That's because you are trying to order the Category's queryset by created_on and your Category model doesn't have any field called created_on. That field is within Petition model. If you want to order the categories by petition's created_on you should do a "join" between tables, but with Django's ORM is easy.
For simplicity on your code is better to name the relation
class Petition(models.Model):
...
categories = models.ManyToManyField(Category, related_name='petitions')
...
Now you can refer to the category's petitions as 'petitions'
Category.objects.order_by('-petitions__created_on')
For use the petitions within the template the best way is prefetch the petitions on the queryset to avoid hitting the database every time in the for loop.
Category.objects.prefetch_related('petitions').order_by('-petitions__created_on')
That would bring every petition for each category. So in your template you can use:
{% for category in category_list %}
{% for petition in category.petitions.all %}
...
#{{ petition.created_by }}
...
{% end for %}
{% end for %}

Categories

Resources