I am new to the Django web framework.
I have a template that displays the list of all objects. I have all the individual objects listed as a link (object title), clicking on which I want to redirect to another page that shows the object details for that particular object.
I am able to list the objects but not able to forward the object/object id to the next template to display the details.
views.py
def list(request):
listings = listing.objects.all()
return render_to_response('/../templates/listings.html',{'listings':listings})
def detail(request, id):
#listing = listing.objects.filter(owner__vinumber__exact=vinumber)
return render_to_response('/../templates/listing_detail.html')
and templates as:
list.html
{% for listing in object_list %}
<!--<li> {{ listing.title }} </li>-->
{{ listing.title}}<br>
{% endfor %}
detail.html
{{ id }}
The variables that you pass in the dictionary of render_to_response are the variables that end up in the template. So in detail, you need to add something like {'listing': MyModel.objects.get(id=vinumber)}, and then the template should say {{ listing.id }}. But hat'll crash if the ID doesn't exist, so it's better to use get_object_or_404.
Also, your template loops over object_list but the view passes in listings -- one of those must be different than what you said if it's currently working....
Also, you should be using the {% url %} tag and/or get_absolute_url on your models: rather than directly saying href="{{ listing.id }}", say something like href="{% url listing-details listing.id %}", where listing-details is the name of the view in urls.py. Better yet is to add a get_absolute_url function to your model with the permalink decorator; then you can just say href="{{ listing.get_absolute_url }}", which makes it easier to change your URL structure to look nicer or use some attribute other than the database id in it.
You should check the #permalink decorator. It enables you to give your models generated links based on your urls pattern and corresponding view_function.
For example:
# example model
class Example(models.Model):
name = models.CharField("Name", max_length=255, unique=True)
#more model fields here
#the permalink decorator with get_absolute_url function
#models.permalink
def get_absolute_url(self):
return ('example_view', (), {'example_name': self.name})
#example view
def example_view(request, name, template_name):
example = get_object_or_404(Example, name=name)
return render_to_response(template_name, locals(),
context_instance=RequestContext(request))
#example urls config
url(r'^(?P<name>[-\w]+)/$', 'example_view', {'template_name': 'example.html'}, 'example_view')
Now you can do in your templates something like this:
<a href={{ example.get_absolute_url }}>{{ example.name }}</a>
Hope this helps.
In your detail method, just pass the listing into your template like so:
def detail(request, id):
l = listing.objects.get(pk=id)
return render_to_response('/../templates/listing_detail.html', {'listing':l})
Related
So I'm trying to: pass a variable owner_id in the view def new(request, owner_id) to render new.html that it will be used in the action of a form as a parameter/argument action="{{ url 'new' owner_id }}".
Like This:
def new(request, owner_id): # from here
if request.method == 'POST':
...
else:
category = Category.objects.all()
render(request, "auctions/new.html", {
"category": category,
"owner_id": owner_id # <--- to HERE
})
view.py
urls.py
new.html Error detected in this file by django
Layout.html template
Could not parse the remainder
ERROR screenshot
It's driving me crazy... I can't understand why its not working.
And the worst part is I already did it on another view and it WORKED!
The only difference is here I use the same variable again inside in the form to "feed" it again, throught the same url, view... etc.
Whether there (another url and view) I used it as a normal variable inside the brakets {{ }}.
PD: I probably lack the basic understanding how django starts to process all this.
A template tag is written between {% and %}, not {{ url 'new' owner_id }}, so:
action="{% url 'new' owner_id %}"
I'm extending the edit template for a ModelView so that I can show some other information from the database that is relevant for determining how to edit the record in this view. I know how to extend the template and get it to work, but I can't figure out how to query an object and use it in the template.
Also I need to use the value from the model/record in querying the new object I need to pass.
Here is my code from init.py:
class MilestoneView(ModelView):
edit_template = '/admin/milestone_model/milestone_edit.html'
can_delete = True
#i need something like this to work:
referrals = Referral.query.filter_by(email=model.email)
#then i need to pass referrals into the template
admin = Admin(app, name="My App", template_mode='bootstrap3')
admin.add_view(MilestoneView(Milestone, db.session, name='Milestones'))
Then from milestone_edit.html, I want something like this to work:
{% extends 'admin/model/edit.html' %}
{% block body %}
{{ super() }}
{% for r in referrals %}
<p>{{ r.name }}</p>
{% endif %}
{% endblock %}
But of course the referrals object is not available to use in the template. How do I customize this ModelView in order to pass this object in from the init file? I've reviewed the available posts on this subject(ish) on here and haven't found an answer. Thanks in advance.
Override your view's render method, see code on Github, and test if the view being rendered is the edit view. Now you can inject any data into the kwargs parameter. For example:
class MilestoneView(ModelView):
def render(self, template, **kwargs):
# we are only interested in the edit page
if template == 'admin/model/milestone_edit.html':
# Get the model, this is just the first few lines of edit_view method
return_url = get_redirect_target() or self.get_url('.index_view')
if not self.can_edit:
return redirect(return_url)
id = get_mdict_item_or_list(request.args, 'id')
if id is None:
return redirect(return_url)
model = self.get_one(id)
if model is None:
flash(gettext('Record does not exist.'), 'error')
return redirect(return_url)
referrals = Referral.query.filter_by(email=model.email)
kwargs['referrals'] = referrals
return super(MilestoneView, self).render(template, **kwargs)
Note how the model is retrieved. This is a direct copy of the code in method edit_view code. Adjust the code for your use-case.
Use the variable referrals in your edit Jinja2 template.
The render method is called in the following routes for each view:
'/' - i.e. the list view code
'/new/' - code
'/edit/' - code
'/details/' - code
As far as I know, the default data type of id is integer for models in Django.
For example, if I have such a model inside my models.py file, Django sets a id(primary key) for every instance of it and Django increments it automatically like 1,2,3 etc. :
class AuctionListing(models.Model):
name = models.CharField(max_length=200)
url = models.URLField()
def __str__(self):
return f"{self.name}"
Since it sets id(primary key) automatically as a data type of integer, I can create such a url in the url.py file :
path("<int:listing_id>", views.listing, name="listing")
And my views.py file:
def index(request):
return render(request, "auctions/index.html", {"auctionList":AuctionListing.objects.all()} )
also, index.html file :
{% for listing in auctionList %}
<img src = "{{listing.url}}" alt = "{{listing.name}}">
{% endfor %}
The issue with this, when it passes listing.id to the path("int:listing_id", views.listing, name = "listing"), it doesn't pass id as integer but as str. That's why, path doesn't accept it since it is int:listing_id and when I go to the page, it gives me this error : "
The current path, url 'listing' listing.id, didn't match any of these".
When I change int:listing_id to str:listing_id it works. I wonder if the default data type of id is a string data type in Django? As far as I know it should be a data type of integer. Can someone explain please?
By the way, I am inheriting from AbstractUser.
DB is sqlite3
Yes, the default object primary key data type in django is int but if you want to access it you should either declare your own primary key field or use the default name which is pk, in that case your urls should look something like this:
path("", views.listings, name="listings"),
path("<int:pk>", views.listing, name="listing")
and your views something like this:
def index(request):
listings = AuctionListing.objects.all()
return render(request, 'listings.html', {'listings': listings'}
def listing(request, pk):
listing = AuctionListing.objects.get(pk=pk)
return render(request, 'listing.html', {'listing': listing'}
and in your listings.html:
{% for listing in listings %}
{{ listing.name }}
{% endfor %}
I am using Django for develop a website. The website is intended to use to search information stored in a MySQL database.
This is the current basic flow of the web site.
1) index.html - this has a form to select an option
2) according the option, users will redirect to search.html (include a form)
3) once the user provides the criteria, the result will be displayed in reply.html
In my views.py , I have two functions.
from django.shortcuts import render
from website.models import WebsiteRepository
from .forms import SearchForm
from .forms import SelectTypeForm
def Search(request):
if request.method == 'POST':
#do something
return render(request, 'reply.html', {'env_dict':env_dict})
else:
#do something
return render(request, 'search.html', context = context)
def index(request):
if request.method =='POST':
#do something
return render(request, 'search.html', context = context)
else:
#do something
return render(request, 'index.html', context= context)
When I go to index.html page, I can select a option and it will direct me to search.html. After, I fill the form there and submit, it wont give me the reply.html page.
I have a feeling that, I could make this work by changing urls.py.
from django.urls import path
from website import views
urlpatterns = [
path('', views.index, name='index'),
#path('search/', view.Search, name ='Search')
]
I tried to google it. But its too much details and Iam kind of lost.
Do any of you guys know how to achieve this?
Thanks
search.html
{% extends "base_generic.html" %}
{% block content %}
<h3>Welcome to search information Repository</h3>
<form method="post">
{% csrf_token %}
{{form.as_p}}
<button type = 'submit'>submit</button>
</form>
{% endblock %}
index.html
{% block content %}
<h3>Welcome to information Repository</h3>
<form method="post">
{% csrf_token %}
{{form.as_p}}
<button type = 'submit'>submit</button>
</form>
just for clarify things more, ill add the forms.py too
from django import forms
from .models import WebsiteRepository
class SearchForm(forms.Form):
websiterepository = WebsiteRepository
env_indicators = websiterepository.objects.filter (key_aspect='Environmental').values_list('repo_id','indicator')
indicator = forms.ChoiceField(choices=env_indicators,label = 'Indicator' )
OPTIONS = (('2000','2000'),('2001','2001'),('2002','2002'), ('2003','2003'),('0000','0000'),)
year = forms.ChoiceField(choices=OPTIONS)
class SelectTypeForm(forms.Form):
OPTIONS = (('1', 'Envirnmental Indicators'),('2','Economic Indicators'),('3','Social Indicators'),)
types = forms.ChoiceField(choices=OPTIONS)
Your code is wrong on many points.
First thing first: for a search, you want a GET request, not a POST (POST is for updating the server's state - adding or updating your database mostly). This is the semantically correct method (since you want to GET data), and it will allow a user to bookmark the url.
Second point: you don't want to submit the search form to the index view but to the search view. No need for redirects etc, just use the {% url %} templatetag to fill the action attribute of your form (you of course need to have a 'Search' url in your urls.py):
<form method="get" action="{% url 'Search' %}">
{% csrf_token %}
{{form.as_p}}
<button type = 'submit'>submit</button>
</form>
if you want to have this form on more than one page (which is often the case for search forms), use an inclusion tag tha will take care of creating an unbound SearchForm and render the template fragment.
Then in your search view, you only want GET requests, and do not use two different templates, this will only lead to useless duplication.
def Search(request):
form = SearchForm(request.GET)
# use the form's data - if any - to get search results
# and put those results (even if empty) in you context
return render(request, 'reply.html', {'env_dict':env_dict})
And finally, your search form is totally broken:
class SearchForm(forms.Form):
# this is totally useless
websiterepository = WebsiteRepository
# this will only be evaluated once at process startup, so you will
# get stale data in production - and probably different data
# per process, in a totally unpredictable way.
# You need to either put this in the form's __init__ or wrap it
# in a callable and pass this callable
env_indicators = websiterepository.objects.filter (key_aspect='Environmental').values_list('repo_id','indicator')
indicator = forms.ChoiceField(choices=env_indicators,label = 'Indicator' )
# are you going to manually add a new year choice every year ???
OPTIONS = (('2000','2000'),('2001','2001'),('2002','2002'), ('2003','2003'),('0000','0000'),)
year = forms.ChoiceField(choices=OPTIONS)
For the "indicators" ChoiceField you want something like:
def get_indicators_choices():
return Websiterepository.objects.filter (key_aspect='Environmental').values_list('repo_id','indicator')
class SearchForm(forms.Form):
# IMPORTANT : we are NOT calling the function here, just
# passing it (python functions are objects) to the field, which
# will call it everytime the form is instanciated, so you don't
# have stale data
indicator = forms.ChoiceField(
choices=get_indicator_choices,
label='Indicator')
As a last note: be consistent with your namings (ie why name one view in all lower (index) and capitalize the other (Search) ? Whichever convention you choose (I strongly suggest respecting pep8 here), at least stick to it for the whole project.
The problem is that code is not redirecting to /search, instead rendering search.html after post from index.html.
Try doing like-
views.py-
#your code
def index(request):
#do something
if request.method == 'POST':
return redirect('Search')
else:
#render index.html
def search(request):
#do something
if request.method == 'POST':
#render reply.html
else:
#render search.html
Another way to achieve this is if you specify action in your form so that form posts on /search.
search.html
<form method="post" action="/search">
{% csrf_token %}
{{form.as_p}}
<button type = 'submit'>submit</button>
</form>
I have a same template that is used for different urls (in this case: /create/ and /edit/[PK of an item] , named "create" and "edit" in the url.py).
I would like to show different things in my template depending if I'm on /edit/ or /create/.
How can I check this ?
{% if '/create' in request.path %} works, but I'd like to use a url tag (or equivalent, to not have it "hard coded").
What I would like to do looks like (in pseudo code - this doesn't work) {% if request.path in url create %} XXX {% endif %}.
Should I make all the necessary tests in the views.py, send a variable about it in the context, test on this variable in the template? In my case it seems a bit heavy for a simple url test ...
You can set a url with a as value.
{% url 'some-url-name' arg arg2 as the_url %}
{% if the_url in request.path %}
I'd say go for making two views if it's a significant difference (different form, etc.) - eliminates url logic in templates entirely, and no real 'test' needed either - don't have to check request.path/pass url/etc.
urls
urlpatterns = patterns('',
(r'^create/$', create),
(r'^edit$', edit),
)
views
def create(request):
text = "Create something"
return render_to_response('same-template.html', {'text': text}, context_instance=RequestContext(request)
def edit(request):
text = "Edit something"
return render_to_response('same-template.html', {'text': text}, context_instance=RequestContext(request)
template
{% text %}
Can also pass multiple changes easily with a list this way too:
views
def create(request):
data = []
data['text'] = "Create something"
data['form'] = CreateForm()
return render_to_response('same-template.html', {'data': data}, context_instance=RequestContext(request)
def edit(request):
data = []
data['text'] = "Edit something"
data['form'] = EditForm()
return render_to_response('same-template.html', {'data': data}, context_instance=RequestContext(request)
template
{% data.text %}
{% data.form %}
Either you do it in a view, or write a template tag.
Looking on django snippets, this one looks nice: http://djangosnippets.org/snippets/1531/