I am trying to display the get_context_data on the template. I have a method on the model class that I need to call from ProfileView which has two different models. For the Profile View I have Profile Model and for the shippingaddress view I have ShippingAddress Model. And these models are from two different app. I tried the function below and it does not show any error, but when I tried to call it in the Template, It does not show the method.
Views.py
class ProfileView(LoginRequiredMixin, DetailView):
model = Profile
template_name = "account/profile.html"
success_url = "/"
def get_context_data(self, *args, **kwargs):
context = super(ProfileView, self).get_context_data(**kwargs)
context['shipping'] = ShippingAddress.objects.filter(user=self.request.user)
return context
Template code
{{object.get_full_address}}
Models.py
class ShippingAddress(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL,
on_delete=models.CASCADE)
phone_number = PhoneNumberField(null=True, blank=True)
street_address = models.CharField(max_length=300)
province = models.CharField(max_length=300)
city = models.CharField(max_length=50)
country = models.CharField(max_length=50)
zip_code = models.CharField(max_length=10)
def __str__(self):
return str(self.user)
def get_phone_number(self):
return self.phone_number
#property
def get_full_address(self):
return f"{self.street_address}, {self.province}, {self.city}, {self.country}, {self.zip_code}"
object is the context variable that DetailView will add to the context. For your view this would be an instance of Profile. You pass a queryset into the context with the name shipping so you can loop over that:
{% for shipping_address in shipping %}
{{ shipping_address.get_full_address }}
{% endfor %}
Note: You need to loop because one user has multiple Shipping Addresses according to your models.
Note: Also you didn't need to override get_context_data you could simply have written:
{% for shipping_address in request.user.shippingaddress_set %}
{{ shipping_address.get_full_address }}
{% endfor %}
Where shippingaddress_set is the related model name with _set
appended. You can change that by setting related_name on your
foreign key.
Related
I have this ManyToMany relationship through an intermediary model:
class Group(models.Model):
members = models.ManyToManyField(Student, through='NamedMembershipClub')
class Membership(models.Model):
year = models.IntegerField()
user = models.ForeignKey(User, on_delete=models.CASCADE)
group = models.ForeignKey(Group, on_delete=models.CASCADE)
I'm trying to display members with the year they joined in my template.
I read on this post that I should use members_set.all
{% for member in object.members_set.all %}
<p>{{member.user.first_name}} {{member.year}}</p>
{% endfor %}
But it doesn't produce any output, the loop is just not entered because the set is empty.
I also tried :
{% for member in object.members.all %}
<p>{{member.first_name}}</p>
{% endfor %}
The view:
class DetailGroupView(TemplateView):
template_name = 'group/detail.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
self.object = Group.object.get(slug=kwargs['slug'])
context['object'] = self.object
return context
Which gives some satisfaction because I can display the user but not the associated data in the Membership model.
Is there any way to get the set directly in the template ? Thanks!
I'm running Django 3.0.
I have a class for a blog post detail like this:
class MaghaleDetail(DetailView):
model = MaghaalaatPost
template_name = 'Blog/Blog-elmi-detail.html'
context_object_name = 'maghaale'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["related_items"] = self.object.tags.similar_objects()[:3]
context["images"] = MaghaalaatImages.objects.all()
return context
and this is my models:
class MaghaalaatPost(models.Model):
title = models.CharField(max_length=250)
paragraph = models.TextField(blank=True)
class MaghaalaatImages(models.Model):
post = models.ForeignKey(MaghaalaatPost, default=None,
on_delete=models.CASCADE)
images = models.FileField(upload_to='post_images', blank=True)
the images context shows every single image because I set it to all(). how do I filter it to show only the images to this specific post?
You actually do not need to pass this to the context. If you define a relation (like a ForeignKey, OneToOneField, ManyToManyField, etc.), then Django will add a manager in the target model to access the related objects, you can thus access the related objects in the template with:
{% for image in maghaale.maghaalaatimages_set.all %}
… do something with image …
{% endfor %}
For the name of the relation in reverse, you can specify the related_name=… parameter [Django-doc]. If you do not specify this, Django will use modelname_set with modelname the name of the class of the model in lowercase.
or in the context:
class MaghaleDetail(DetailView):
model = MaghaalaatPost
template_name = 'Blog/Blog-elmi-detail.html'
context_object_name = 'maghaale'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['related_items'] = self.object.tags.similar_objects()[:3]
context['images'] = self.object.maghaalaatimages_set.all()
return context
I want to render every {{ episode.object }} in single video.html page where it works fine for {{ video.object }}. But it isn't showing anything for episode object.. The final template video.html that I want to render episode objects can be seen here https://ibb.co/K9NMXtS
I tried
{% for episode in episodes %}
{{ episode.title }}
{% endfor %}
But that didn't worked. Here is the other configurations:-
#models.py
class Video(models.Model):
title = models.CharField(max_length=100, unique=True)
slug = models.SlugField(max_length=200, unique=True)
year = models.CharField(max_length=4)
category = models.CharField(max_length=3)
trailer = models.URLField(default='')
def __str__(self):
return self.title
def get_absolute_url(self):
from django.urls import reverse
return reverse("video.html", kwargs={"slug": str(self.slug)})
class Episode(models.Model):
video = models.ForeignKey(Video, related_name='episodes', on_delete=models.CASCADE)
title = models.CharField(max_length=512)
air_date = models.DateField()
videolink = models.URLField(default='')
def __str__(self):
return self.title
# urls.py
urlpatterns = [
path('video/<slug>/', views.VideoDetail.as_view(), name='videos'),
]
# view.py
class VideoDetail(DetailView):
model = Video
template_name = 'video/video.html'
def get_context_data(self, *args, **kwargs):
context = super().get_context_data(*args,**kwargs)
context['Episodes'] = Episode.objects.all()
return context
Python and Django templates are case sensitive. You use Episodes in the view, which doesn't match episodes in the template. Change one of them so that it matches (episodes is recommended for model instances in Python/Django).
Next, you are using Episode.objects.all() at the moment, which will display all episodes. If you only want the episodes for that video, then filter the queryset:
context['episodes'] = Episode.objects.filter(video=self.object)
Or you can get the same result by following the foreign key backwards:
context['episodes'] = self.object.episodes.all()
add VideoDetail, self in super tag
and while calling in template {{ episode.video.slug }}
and slug enough in url
path('video/<slug>/', views.VideoDetail.as_view(), name='videos'),
class VideoDetail(DetailView):
model = Episode
template_name = 'video/video.html'
def get_context_data(self, *args, **kwargs):
context = super(VideoDetail, self).get_context_data(*args,**kwargs)
context['Episodes'] = Episode.objects.all()
return context
Forgive the logic of the table structure below example. It only meant as a simple example of the situation that I am.
So the situation is that I want to make an employee form page, where the department and line manager might or might not exist already. So I replace the drop-down box with the form field for the foreign key, so they can be created if need all in one step for the user. However, with this kind of dependency, I am not doing the right thing in view to make it work.
If you need more detail please do ask.
If you can make the Title more precise please do.
Thank you for your time.
Model
class Employee(models.Model):
name = models.CharField()
age = models.CharField()
line_manager = models.ForeignKey(LineManager)
department = models.ForeignKey(Department)
class LineManager(models.Model):
manager_name = models.CharField()
department = models.ForeignKey(Department)
class Department(models.Model):
department_name = models.CharField()
Form
class EmployeeForm(ModelForm):
class Meta:
model = Employee
fields = ['name',
'age'
#'line_manager' Not needed
#'department' Not needed]
exclude = ('line_manager', 'department')
class LineManagerForm(ModelForm):
class Meta:
model = LineManager
fields = ['manager_name']
exclude = ('department')
# There is a basic form for Department, as well.
View
class AddEmployeeView(View):
forms = {'department': DepartmentForm(self.request.POST or None),
'line_manager': LineManagerForm(self.request.POST or None),
'employee': EmployeeForm(self.request.POST or None)]}
def get(self, request, *args, **kwargs):
form_list = [form for _,form in forms]
return render (request, 'app/temp.html', {'forms': form_list}
def post(self, request, *args, **kwargs):
if all([form.is_valid() for _,form in forms]):
department_data = forms['department'].cleaned_data
department_obj, _ = Department.objects.get_or_create(department_data)
line_manager_instance = forms['line_manager'].instance
line_manager_instance.department = department_obj
line_manager_data = forms['line_manager'].cleaned_data
line_manager_obj, _ = LineManager.objects.get_or_create(line_manager_data)
employee_instance = forms['employee'].save(commit=False)
employee_instance.department = department_obj
employee_instance.line_manager = line_manager_obj
employee_instance.save()
html
<form method="POST">
{% csrf_token %}
{% form in forms %}
{{ form.as_p }}
{% endform %}
<input type='submit'/>
</form>
Currently I have the following structure.
I have Users, which can be Teachers or Students. Students can leave reviews for teachers. I've set up a detailed view for teachers and added a 'reviews' attribute to get_context_data to loop through reviews to display them.
Aim: Each user who is a student can submit a review of a teacher. I want to display a form at the bottom of my detailed view. If user already had a review, then we call update. If user doesn't have a review, we create it.
Models.py
class Teacher(models.Model):
user = models.OneToOneField(User, on_delete=models.PROTECT, related_name='Teacher')
availability = models.BooleanField(default=False)
def __str__(self):
return self.user.username
class Student(models.Model):
user = models.OneToOneField(User, on_delete=models.PROTECT, related_name='Student')
teacher = models.ForeignKey(Teacher)
reviewed = models.BooleanField(default=False)
def __str__(self):
return self.user.username
class Review(models.Model):
teacher = models.ForeignKey(Teacher)
student = models.OneToOneField(Student, on_delete=models.PROTECT, related_name='Student')
star = models.IntegerField(default=5)
body = models.TextField()
Views.py
class ReviewSubmitForm(forms.Form):
star = forms.IntegerField()
body = forms.CharField()
class TeacherView(generic.DetailView):
model = Teacher
def get_context_data(self, **kwargs):
# Call the base implementation first to get a context
context = super(TeacherView, self).get_context_data(**kwargs)
# Add extra context from another model
context['reviews'] = Review.objects.filter(teacher_id=self.kwargs['pk'])
context['rating'] = Review.objects.filter(teacher_id=self.kwargs['pk']).aggregate(Avg('star'))
context['form'] = ReviewSubmitForm()
return context
class ReviewSubmit(SingleObjectMixin, FormView):
template_name = 'users/teacher_detail.html'
form_class = ReviewSubmitForm
model = Review
def post(self, request, *args, **kwargs):
if not request.user.is_authenticated:
return HttpResponseForbidden()
self.object = self.get_object()
return super(ReviewSubmit, self).post(request, *args, **kwargs)
def get_success_url(self):
return reverse('users:detail', kwargs={'pk': self.object.pk})
I'm now able to see the form and use it in my template.
My teacher view is located at /users/<pk>
The logic that I'd like is: look for , check current student id.
If there is an entry with pk=pk and student_id = student_id then load update form. Otherwise if it's a student load create form.
This example is somewhat similar, but not quite the same.
Edit: form_template.html
{% for field in form %}
<div class="form-group">
<span color="red">{{ field.errors }}</span>
<label>
{{ field.label_tag }}
</label>
<div>{{ field }}</div>
</div>
{% endfor %}