I'm dealing with some Django code I inherited from a dev and need to make a very simple change. In the code, there is a list of jobs displayed through a Django ListView. My problem is really simple. When I go to the page, I see the jobs sorted by date with earliest one first. I want to sort the jobs in the opposite order. I don't need any filtering, passing parameters in the URL, etc for now. Here are the relevant parts of the files:
#models.py
from django.db import models
class Job(models.Model):
created = models.DateTimeField(auto_now_add=True)
position = models.ManyToManyField(Position)
title = models.CharField(max_length=100)
#views.py
from .models import Job
class JobListView(ListView):
template_name="jobs/list.html"
model = Job
paginate_by = 10
#list.html
{% for job in object_list %}
<li class="display-list-item">
<h4><strong>{{job.title}}</strong></h4>
<ul class="list-inline job-info-list">
<span>{{job.created | timesince}} ago</span>
</ul>
</li>
{% endfor %}
#urls.py
urlpatterns = [
url('^$', views.JobListView.as_view(), name='job_list')
]
As mentioned, this causes the jobs to be displayed sorted by 'created' field. The ones created earlier are displayed first. What is the quickest way to make the ones created later display first?
first way
models.py
from django.db import models
class Job(models.Model):
created = models.DateTimeField(auto_now_add=True)
position = models.ManyToManyField(Position)
title = models.CharField(max_length=100)
class Meta:
ordering = ['-created']
second way
views.py
from .models import Job
class JobListView(ListView):
template_name="jobs/list.html"
queryset = Job.objects.order_by('-created')
paginate_by = 10
Related
I have class:
class Like(models.Model):
user = models.ForeignKey(User, related_name='likes', on_delete=models.CASCADE)
post = models.ForeignKey(Post, related_name='likes', on_delete=models.CASCADE)
ratingtype = models.IntegerField(default=0)
that lets me display total amount of lines in database table with this tag:
{{post.likes.count}}
What would be the best way to modify this class so i can differentiate the counting by two ratingtype (1 or 0)
Don't make queries in the template. Templates are used for render logic, not business logic.
You can annotate the Post object(s) you are fetching with:
from django.db.models import Count, Q
Post.objects.annotate(
likes0=Count('likes', filter=Q(ratingtype=0)),
likes1=Count('likes', filter=Q(ratingtype=1))
)
The Products that arise from this queryset will have two extra attributes: .likes0 and .likes1 that contains the number of likes with ratingtype=0 and ratingtype=1 respectively. You thus can then render this with:
{{ post.likes0 }}
{{ post.likes1 }}
I have forked the django-oscar catalogue app to alter the models being used. Not in a major way, and not in a way that would affect pulling data from the database as far as I can see. This seems to be supported by the fact the the django-oscar dashboard still works fine and lets me add and view products. My models.py from my forked app:
from django.db import models
class Collection(models.Model):
name = models.CharField(max_length=50)
prod_category = models.CharField(max_length=50)
description = models.TextField()
manufacturer = models.TextField()
num_products = models.PositiveIntegerField()
image_url = models.URLField()
from oscar.apps.catalogue.abstract_models import AbstractProduct
class Product(AbstractProduct):
collection = models.ForeignKey(Collection, on_delete=models.CASCADE, null=True)
multiplier = models.DecimalField(max_digits=2, decimal_places=1, default='2.2')
from oscar.apps.catalogue.models import *
Here is my relevant view from my views.py
def product(request):
template = loader.get_template('/home/my_app/my_site/main_page/templates/main_page/product.html')
prods = Product.objects.values_list('categories')
context={'prods': prods}
return HttpResponse(template.render(context))
I tried loading from the built in model and my forked model (commenting and uncommenting one or both), neither makes a difference:
#from forkedoscarapps.catalogue.models import Product
from oscar.core.loading import get_class, get_model
Product = get_model('catalogue', 'product')
And the code I am using in the template to display data from the view:
{% for instance in prods %}
<li><{{ instance.name }}</li>
{% endfor %}
The resulting HTML is:
<li></li>
Which shows it is reaching the for loop, but for some reason no data is returned.
There is at least one category called beds, which displays fine in the django-oscar dashboard. What have I missed in my view?
edit: When I change instance.name to just instance I get the following returned in the HTML:
(1,)
So it is somewhat working, and showing what I assume is the primary key being returned, but why is the name of the field not being returned?
Product.objects.values_list('categories') yields a list of id tuples that represent the categories associated with the products in that queryset. That's not what you want to send to the template, you want to send instances, more specifically product instances if I'm not mistaken.
Do Product.objects.all() instead, and just use {{ instance.title }} in the template according to the definition of the oscar model: https://github.com/django-oscar/django-oscar/blob/master/src/oscar/apps/catalogue/abstract_models.py and to what ever you customised over it.
I'm kind of new to django, I'm working on a project currently. It is a website where people can look for houses to rent. Users will be able to create accounts, search for houses to rent and create listings about the houses they want to rent out.
I created a model to save all the information about houses that users want to rent out. I need to filter this information and display each user's listing on their profile. I have searched online but no solution yet.
Really need help.
models.py
from django.db import models
from django.contrib.auth.models import User
class Myhouses(models.Model):
Available = 'A'
Not_Available = 'NA'
Availability = (
(Available, 'Available'),
(Not_Available, 'Not_Available'),
)
name_of_accomodation = models.CharField(max_length=200)
type_of_room = models.CharField(max_length=200)
house_rent = models.IntegerField()
availability = models.CharField(max_length=2, choices=Availability, default=Available,)
location = models.CharField(max_length=200)
nearest_institution = models.CharField(max_length=200)
description = models.TextField(blank=True)
image = models.ImageField(upload_to='profile_image')
author = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True, related_name='author')
def __str__(self):
return self.name_of_accomodation
view.py
class ListingByUser(LoginRequiredMixin, generic.ListView):
model = Myhouses
template_name ='houses/ListingByUser.html'
paginate_by = 10
def get_queryset(self):
return Myhouses.objects.filter(author=self.request.user)
urls.py
from django.conf.urls import url, include
from . import views
from django.contrib.auth.models import User
urlpatterns = [
url(r'^addlisting/$', views.addlisting, name='addlisting'),
url(r'^mylisting/', views.ListingByUser.as_view(), name='ListingByUser')
]
Template
<ul>
{% for houses in myhouses_list %}
<li>{{ houses.name_of_accomodation }}</li>
{%endfor %}
</ul>
Taking a quick view of your code, there is something that stuck me on your ListingByUser view: you override the get method only to set some attributes that are normaly defined as class attributes. That also could be preventing your view to actually get your models out of the database (via calling the get_queryset method) and rendering a proper response.
Edit
I found there's also a problem linking your template to the response the ListingByUser view is rendering. As far as I know, Django views doesn't look into the variable template_name for getting the response's template. But it does call a method get_template_names which returns a list of template names given as strings.
Try to modify it in this way:
views.py
class ListingByUser(LoginRequiredMixin, generic.ListView):
model = Myhouses
template_name ='myhouses/listing_by_user.html'
paginate_by = 10
def get_queryset(self):
return Myhouses.objects.filter(author=self.request.user)
def get_template_names(self):
return [self.template_name]
I have been loosely following a tutorial and can't seam to get a generic detail view to work properly. I am calling with a pk and the page displays but the variable {{publisher.name}} doesn't show up. I have deleted some of the code from views and the model which I consider peripheral but if there error isnt obvious I can repost.
All files are in the poll directory except the HTML file is in poll/template/poll
Thanks
The URL.py is
from django.conf.urls import url
from poll.views import PublisherList
from . import views
app_name = "poll"
urlpatterns = [
url(r'^publishers/$', PublisherList.as_view(), name = "publisherlist"),
url(r'^start/', views.PublisherCreate.as_view(), name = 'make-publisher'),
url(r'^(?P<pk>[0-9]+)/$', views.PublisherDetail.as_view(), name = 'detail-publisher'),
]
The View.py
from django.shortcuts import render
from django.views.generic.edit import CreateView
from django.views import generic
from django.views.generic import ListView
from poll.models import Publisher
...
class PublisherDetail(generic.DetailView):
model = Publisher
template_name = 'Poll/publisher_details.html'
and the HTML file
{% extends "personal/header.html" %}
{% block content %}
<h1>{{ Publisher.name }}</h1>
<h1>Options</h1>
{%endblock%}
and the models.py
from django.db import models
from django.core.urlresolvers import reverse
# Create your models here.
class Publisher(models.Model):
name = models.CharField(max_length=30)
address = models.CharField(max_length=50)
city = models.CharField(max_length=60)
state_province = models.CharField(max_length=30)
country = models.CharField(max_length=50)
website = models.URLField()
class Meta:
ordering = ["-name"]
def __str__(self): # __unicode__ on Python 2
return self.name
def get_absolute_url(self):
return reverse('build:details', kwargs = {'pk':self.pk})
The object in the template is called publisher, not Publisher.
You can't access the instance of the model like this in the template. Publisher is the name of your Model class but not an instance of it. The default name of the object in a generic detail view is object. So you need to use {{ object.name }}. Or you can use the lowercased Model name too as a default. In your case thats publisher.
If you want to change the variable name of your object you have to implement get_context_object_name(obj) method of your detail view.
The method has to return a string with the desired variable name of the object in your detail view template.
The default name of the object in the template is object, while the lowercase model name serves as an alias (publisher). You can specify that name in the view via the class attribute context_object_name, as described in the docs:
class PublisherDetail(generic.DetailView):
# ...
context_object_name = 'foo'
Then
{{ foo.name }}
# {{ publisher.name }} should work out of the box
will work in the template.
In a Django-REST-framework project I tried to use the nested relationship and got a "non_field_errors" in the browsable API web view.
The code is from this part of the documentation: http://www.django-rest-framework.org/api-guide/relations#nested-relationships
models.py:
from django.db import models
class Album(models.Model):
album_name = models.CharField(max_length=100)
artist = models.CharField(max_length=100)
class Track(models.Model):
album = models.ForeignKey(Album, related_name='tracks')
order = models.IntegerField()
title = models.CharField(max_length=100)
#duration = models.IntegerField()
class Meta:
unique_together = ('album', 'order')
ordering = ('order',)
def __unicode__(self):
return '%d: %s' % (self.order, self.title)
serializers.py:
from rest_framework import serializers
from myapp.models import Album, Track
class TrackSerializer(serializers.ModelSerializer):
class Meta:
model = Track
fields = ('order', 'title')
class AlbumSerializer(serializers.ModelSerializer):
tracks = TrackSerializer(many=True)
class Meta:
model = Album
fields = ('album_name', 'artist', 'tracks')
ERROR (at ../albums):
The Track input field is marked red with the error message: non_field_errors.
Clicking the OPTIONS button reveals the actual&correct data structure:
Tracks nested with their appropriate propertie
The raw data input of the browsable browser view shows:
{
"album_name": "",
"artist": "",
"tracks": null
}
Posting some valid raw-data actually works. But it'd be nicer if the web interface form would work as well. Especially since I'm wondering if there's something funny going on anyway.
Thank you in advance!
I have experienced this issue as well. One way to get rid of the error is to use:
class AlbumSerializer(serializers.ModelSerializer):
tracks = serializers.RelatedField(many=True)
class Meta:
model = Album
fields = ('album_name', 'artist', 'tracks')
However, this removes the nested track fields and displays only a string representation of the tracks.
Edit: I figured it out. What you want is this:
class AlbumSerializer(serializers.ModelSerializer):
class Meta:
model = Album
fields = ('album_name', 'artist', 'tracks')
read_only_fields = ('tracks',)
depth = 1
This will cause the tracks to nest without throwing the UI error.
One solution is to simply hide the HTML form on the browser side. For example, override Rest Framework's api.html template (by creating your_app/templates/rest_framework/api.html) and include the following:
{% extends "rest_framework/base.html" %}
...
{% block script %}
{{ block.super }}
<script>
$('.form-switcher a[name="html-tab"]').hide();
$('.form-switcher a[name="raw-tab"]').tab('show')
</script>
{% endblock %}
If you want to keep the HTML form for your flat endpoints and simply remove it from your nested ones, you could use the name variable as an indicator. For instance, include "Nested" in the names of your nested endpoints and do something like this:
if("{{ name }}".indexOf("Nested") >= 0){
$('.form-switcher a[name="html-tab"]').hide();
$('.form-switcher a[name="raw-tab"]').tab('show').hide();
}