How to load multiple models in one template in Django 2?
i've read Django Pass Multiple Models to one Template but, i'm lost in the answer and there is no specific answer there to get that view into the template,
Im trying to pass 3 models in views to template, which is Info, Slogan & Berita.
My views.py
from django.shortcuts import render
from django.http import HttpResponse
from .models import Artikel, Berita, Data, Galeri, Info, Slogan, Profil
from django.views.generic import ListView, DetailView
def home(request):
extra_context : {"info" : Info.objects.all(),
"slogan": Slogan.objects.all(),
"berita": Berita.objects.all(),
#and so on for all the desired models...
}
return render (request, 'blog/home.html')
class HomeListView(ListView):
context_object_name = 'slogan'
template_name = 'blog/home.html'
queryset = Info.objects.all()
def get_context_data(self, **kwargs):
context = super(HomeListView, self).get_context_data(**kwargs)
context['slogan'] = Slogan.objects.all()
context['berita'] = Berita.objects.all()
# And so on for more models
return context
my template home.html looks like:
{% for slogans in slogan %}
<p>{{ slogans.konten }}</p>
<p>{{ slogans.author }}</p>
{% endfor %}
my url urls.py looks like:
from blog.views import HomeListView
urlpatterns = [
url(r'^$', HomeListView.as_view(), name="home"),
]
and page source on browser shows nothing.
Im stuck on this, i found at least 3 similar result on this site but not works for me.
Related
I have a DB hat hs some values in it. I want to display these values on my index.html. i want to display them on the standard html path path('', views.index, name = "index"),
I currently displaying them at path('this_is_the_path/', my_db_class.as_view()),
The problem is that i am pulling the values from a class. and i can't figure out how to set the class to the original index.html path.
Models.py
from django.db import models
class Database(models.Model):
text = models.TextField()
Views.py
from django.shortcuts import render
from django.views.generic import ListView, DetailView
from .models import Database
# Create your views here.
def index(request):
return render(request,"index.html",{})
class my_db_class(ListView):
model = Database
template_name = 'index.html'
URLS.PY
from django.urls import path
from . import views
from .views import my_db_class
urlpatterns = [
path('', views.index, name = "index"),
path('this_is_the_path/', my_db_class.as_view()),
]
HTML.PY
<ul>
{% for post in object_list %}
<li> {{ post.text }}</li>
{% endfor %}
</ul>
So my problem is that the above code will only show my DB values at the this_is_the_path path, but i want to show it at the '' path.
just modify your index function like this.
views.py
def index(request):
object_list = Database.objects.all()
return render(request,"index.html",{'object_list':object_list})
I created a small Django application to manage data that fits a simple a model. For now I only need two views: one to list all records and another to edit a record with a generic form. Everything functions as expected, except the redirection from the edit view upon a successful update. In urls.py are the following contents:
from django.urls import path
from . import views
app_name = 'reqs'
urlpatterns = [
path('', views.IndexView.as_view(), name='index'),
path('<int:pk>/', views.ReqUpdateView.as_view(), name='update'),
]
In forms.py:
from django.forms import ModelForm
from .models import Requirement
class RequirementForm(ModelForm):
class Meta:
model = Requirement
fields = ['name', 'priority', 'source' , 'rationale']
And the templeate requirement_form.html:
<h1>{{ requirement.id }} - {{ requirement.name }}</h1>
<form method="post" novalidate>
{% csrf_token %}
<table>
{{ form.as_table }}
<tr><td></td><td><button type="submit">Save</button></td></tr>
</table>
</form>
{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}
<br><br>
Back to list
Finally views.py, on a first attempt to redirect the update to the list:
from django.views.generic import ListView, UpdateView
from django.urls import reverse_lazy
from .models import Requirement
from .forms import RequirementForm
class IndexView(ListView):
template_name = 'reqs/index.html'
context_object_name = 'requirements_list'
def get_queryset(self):
return Requirement.objects.order_by('subject')
class ReqUpdateView(UpdateView):
model = Requirement
form_class = RequirementForm
success_url = reverse_lazy('/')
With this formulation the Save button produces this error:
Reverse for '/' not found. '/' is not a valid view function or pattern name.
I also tried an empty string as argument to reverse_lazy, as well as the path name index, but a similar error message is produced.
On a second attempt I tried to redirect to the same page, redefining the get_success_url method to do nothing:
class ReqUpdateView(UpdateView):
model = Requirement
form_class = RequirementForm
context_object_name = 'requirement_update'
def get_success_url(self):
pass #return the appropriate success url
This returns a 404 error trying to redirect the browser to /reqs/1/None.
A third attempt to redirect to the form with the same record:
class ReqUpdateView(UpdateView):
model = Requirement
form_class = RequirementForm
context_object_name = 'requirement_update'
def get_success_url(self):
pk = self.kwargs["pk"]
return reverse("update", kwargs={"pk": pk})
Which complains about not finding the view:
Reverse for 'update' not found. 'update' is not a valid view function or pattern name.
How can I redirect success to a valid URL? It can either be the items list or the item update view, as long as it works.
There are few misconception that you did
reverse parameter should be as documented
URL pattern name or the callable view object
You have set namespace but you are not reversing with namespace as documented
So in your case
def get_success_url(self):
pk = self.kwargs["pk"]
return reverse("reqs:update", kwargs={"pk": pk})
reverse / reverse_lazy are used to get the url using view name or pattern name. If you want to use a url directly just write:
success_url = '/'
For the case of return reverse("update", kwargs={"pk": pk}) not working since you set app_name = 'reqs' you should be using return reverse("reqs:update", kwargs={"pk": pk}) instead.
I am new to Django and have been making a sample project. I have been trying to use Generic Detailview. It seems that url redirection works fine but DetailView can't get primarykey from the url.
Main url.py::
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^',include('personal.urls')),
]
Here is my app's urls.py code:
urlpatterns = [
url(r'(?P<pk>\d+)/$',views.detailView.as_view(),name="detail"),]
View file for the DetailView:
from django.shortcuts import render
from django.views import generic
from .models import Story
class detailView(generic.DetailView):
model = Story
template_name = 'personal/storydetail.html'
def get_context_data(self, **kwargs):
pk = kwargs.get('pk') # this is the primary key from your URL
print("PK:",pk)
Template Code:
{% block content %}
{{ Story.writer }}
<h6> on {{ Story.story_title }}</h6>
<div class = "container">
{{ Story.collection }}
</div>
{% endblock %}
Story Class code:
class Story(models.Model):
story_title = models.CharField(max_length=200) #Story title
writer = models.CharField(max_length=200) #WriterName
collection=models.CharField(max_length=200) #Collection/Book name
When I check primary key value on view it shows it 'NONE'. I can't find issue with the code. My pased url looks like : http://127.0.0.1:8000/personal/2/ where personal is the name of app and 2 should be taken as id.
The problem is that you are using kwargs instead of self.kwargs inside the get_context_data method. It should be something like:
def get_context_data(self, **kwargs):
# You need to call super() here, so that the context from the DetailView is included
kwargs = super(detailView, self).get_context_data(**kwargs)
pk = self.kwargs['pk'] # No need for get() here -- if you get a KeyError then you have a problem in your URL config that should be fixe # this is the primary key from your URL
# edit kwargs as necessary
...
return kwargs
In the get_context_data method, kwargs are those passed to the method to make up the context. They are different from self.kwargs, which are from the url pattern.
I'm trying to create a marketplace website similar to craigslist.
I created a form according to the Django tutorial "Working with forms", but I don't know how to render information I got from the POST forms.
I want to make information(subject,price...etc) that I got from POST show up on another page like this. http://bakersfield.craigslist.org/atq/3375938126.html and, I want the "Subject"(please look at form.py) of this product(eg.1960 French Chair) to show up on another page like this. http://bakersfield.craigslist.org/ata/ }
Can I get some advice to handle submitted information?
Here's present codes. I'll appreciate all your answers and helps.
<-! Here's my codes -->
◆forms.py
from django import forms
class SellForm(forms.Form):
subject = forms.CharField(max_length=100)
price = forms.CharField(max_length=100)
condition = forms.CharField(max_length=100)
email = forms.EmailField()
body = forms.TextField()
◆views.py
from django.shortcuts import render, render_to_response
from django.http import HttpResponseRedirect
from site1.forms import SellForm
def sell(request):
if request.method =="POST":
form =SellForm(request.POST)
if form.is_valid():
subject = form.cleaned_data['subject']
price = form.cleaned_data['price']
condition = form.cleaned_data['condition']
email = form.cleaned_data['email']
body = form.cleaned_data['body']
return HttpResponseRedirect('/books/')
else:
form=SellForm()
render(request, 'sell.html',{'form':form,})
◆urls.py
from django.conf.urls import patterns, include, url
from django.contrib import admin
admin.autodiscover()
urlpatterns = patterns('',
url(r'^sechand/$','site1.views.sell'),
url(r'^admin/', include(admin.site.urls)),
)
◆sell.html
<form action = "/sell/" method = "post">{% csrf_token%}
{{ form.as_p }}
<input type = "submit" value="Submit" />
</form>
I assume you have a Sell model/table in your db(where you store the users' "sells"), otherwise it wouldn't make any sense. This means you can save yourself some time and use a ModelForm,
instead of a simple Form. A model form takes a database table and produces an html form for it.
forms.py
from django.forms import ModelForm
from yourapp.models import Sell
class SellForm(ModelForm):
class Meta:
model = Sell
In your views.py you need one more view that displays the Sells that your users have
posted for others to see. You also need an html template that this view will render with context about each Sell.
sell_display.html
{% extends 'some_base_template_of_your_site.html' %}
{% block content %}
<div id="sell">
<h3> {{ sell.subject }}</h3>
<p> {{ sell.condition }}</p>
<p> {{ sell.body }}</p>
<!-- the rest of the fields.. -->
</div>
{% endblock %}
We also need a new url entry for the displaying of a specific Sell
urls.py
from django.conf.urls import patterns, include, url
from django.contrib import admin
admin.autodiscover()
urlpatterns = patterns('',
# Changed `sell` view to `sell_create`
url(r'^sechand/$','site1.views.sell_create'),
# We also add the detail displaying view of a Sell here
url(r'^sechand/(\d+)/$','site1.views.sell_detail'),
url(r'^admin/', include(admin.site.urls)),
)
views.py
from django.http import HttpResponseRedirect
from django.shortcuts import render_to_response, get_object_or_404
from yourapp.models import Sell
from yourapp.forms import SellForm
def sell_detail(request, pk):
sell = get_object_or_404(Sell, pk=int(pk))
return render_to_response('sell_display.html', {'sell':sell})
def sell_create(request):
context = {}
if request.method == 'POST':
form = SellForm(request.POST)
if form.is_valid():
# The benefit of the ModelForm is that it knows how to create an instance of its underlying Model on your database.
new_sell = form.save() # ModelForm.save() return the newly created Sell.
# We immediately redirect the user to the new Sell's display page
return HttpResponseRedict('/sechand/%d/' % new_sell.pk)
else:
form = SellForm() # On GET request, instantiate an empty form to fill in.
context['form'] = form
return render_to_response('sell.html', context)
This is enough to get you going I think. There are patterns to make these things more modular and better, but I don't want to flood you with too much information, since you are a django beginner.
I made a custom tag to display a list of categories and its url which worked until I made a category detail view which will only display articles based on the category.
Here is the category view:
from blog.models import Category, Entry
from django.shortcuts import render_to_response, get_object_or_404
from django.views.generic import list_detail
#for template tag to display all categories
def all_categories(request):
return render_to_response('category_detail.html', {
'categories': Category.objects.all()
})
def category_detail(request, slug):
"""
object_list
List of posts specific to the given category.
category
Given category.
"""
return list_detail.object_list(
request,
queryset = Entry.objects.filter(categories = Category.objects.filter(slug = slug)),
extra_context = {'category': Category.objects.filter(slug = slug)},
template_name = 'blog/category_detail.html',
)
Categories url:
from django.conf.urls.defaults import *
from django.views.generic.list_detail import object_list, object_detail
from blog.views.category import category_detail
from blog.models import Category, Entry
# for category detail, include all entries that belong to the category
category_info = {
'queryset' : Category.objects.all(),
'template_object_name' : 'category',
'extra_context' : { 'entry_list' : Entry.objects.all }
}
urlpatterns = patterns('',
url(r'^$', 'django.views.generic.list_detail.object_list', {'queryset': Category.objects.all() }, 'blog_category_list'),
url(r'^(?P<slug>[-\w]+)/$', category_detail),
)
and the custom category tag:
from django import template
from blog.models import Category
def do_all_categories(parser, token):
return AllCategoriesNode()
class AllCategoriesNode(template.Node):
def render(self, context):
context['all_categories'] = Category.objects.all()
return ''
register = template.Library()
register.tag('get_all_categories', do_all_categories)
Also here is how i am using the custom tag in base.html:
{% load blog_tags %}
<p>
{% get_all_categories %}
<ul>
{% for cat in all_categories %}
<li>{{ cat.title }}</li>
{% endfor %}
</ul>
</p>
Before I added category_detail in the view, the custom tag would display the url correctly like: /categories/news. However, now all of the links from the custom tag just displays the url or the current page your on. Whats weird is that it displays the category name correctly.
Does anyone know how to get the urls to work again?
EDIT
here is my category model, maybe something is wrong with my get_absolute_url():
import datetime
from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
class Category(models.Model):
title = models.CharField(max_length = 100)
slug = models.SlugField(unique = True)
class Meta:
ordering = ['title']
verbose_name_plural = "Categories"
def __unicode__(self):
return self.title
#models.permalink
def get_absolute_url(self):
return ('category_detail', (), {'slug': self.slug })
EDIT: updated get_absolute_url for Category model, however, that did not fix my problem. Also if i wasnt clear earlier, the category url worked even before changing the get_absolute_url
I am going to bet that get_absolute_url is actually returning an empty string. This would make the links reload the current page. Check out your HTML and look for something like this:
Category Title Example
If the URLs are actually blank, there is probably an error in get_absolute_url. When a Django template encounters an error when outputting a template variable it returns an empty string. Try calling get_absolute_url from a Django shell and see if it returns properly:
Category.objects.all()[0].get_absolute_url()
It looks like you renamed your view from blog_category_detail to category_detail, but forgot to update the reference in get_absolute_url.
Update: It doesn't look like the reverse URL lookup for 'category_detail' would succeed. Your urls file does not name the category_detail URL. You should either change the get_absolute_url reference to app_name.views.category_detail (or wherever it is stored) or name the URL by replacing that last line in your urls file with:
url(r'^(?P<slug>[-\w]+)/$', category_detail, name='category_detail'),
To find the source of the problem, you should debug this code from a command line. Something like this should do:
$ python manage.py shell
>>> from blog.mobels import Category
>>> cat = Category.objects.all()[0]
>>> cat.get_absolute_url()