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.
Related
This question already has answers here:
Django: Generic detail view must be called with either an object pk or a slug
(6 answers)
Closed 1 year ago.
I'm starting with Django, and i wanna create simple projects to test my skills. First is the simple todo list. I've found a problem during trying to create 'delete task' functionality on my project.
views.py
from django.shortcuts import render, redirect
from django.urls import reverse_lazy
from .models import Task
from .forms import TaskForm
from django.views.generic import DeleteView
def index(request):
return render(request, 'todoxd_app/index.html')
def todo(request):
objekt = Task.objects.all()
context = {'objekt': objekt}
return render(request, 'todoxd_app/todo.html', context)
def new_todo(request):
if request.method != 'POST':
form = TaskForm()
else:
form = TaskForm(data=request.POST)
if form.is_valid():
form.save()
return redirect('todoxd_app/new_todo')
context = {'form': form}
return render(request, 'todoxd_app/new_todo.html', context)
class DeleteTodo(DeleteView):
model = Task
template_name = 'registration/delete_todo.html'\
urls.py
from django.urls import path, include
from .views import DeleteTodo
from . import views
app_name = 'todoxd_app'
urlpatterns = [
path('', views.index, name='index'),
path('todo/', views.todo, name='todo'),
path('new_todo/', views.new_todo, name='new_todo'),
path('delete/<post_pk>/', DeleteTodo.as_view() ,name='delete_todo'),
]
delete_todo.html
Title
{% extends 'todoxd_app/base.html' %}
{% block content %}
{% csrf_token %}
DELETE TASK
{% endblock content %}
from django.db import models
class Task(models.Model):
name = models.CharField(max_length=50)
description = models.TextField()
date_added = models.DateField(auto_now_add=True)
date_end_of_task = models.CharField(max_length=20)
progress = models.BooleanField()
def __str__(self):
return self.name
I would be grateful for help (:
for deleting task you have to specify django which task you want to delete and for that you have to call an id or slug field which has to be uniques only for that task then you can delete task here is the way and i am using id here
def DeleteTodo(request, id):
task = Task.objects.filter(id=id)
task.delete()
return render(request, 'registration/delete_todo.html')
in your html in href tag by which you want to allow user delete that task
Delete It
and last in your url
path('<int:id>/delete', views.DeleteTodo, name='delete_todo'),
and now you can delete it
By default, detail views like DeleteView will look for the primary key in the url with the kwarg pk as explained in the docs. So if you want to support using post_pk in your view, set that as the value in pk_url_kwarg:
class DeleteTodo(DeleteView):
model = Task
template_name = 'registration/delete_todo.html'
pk_url_kwarg = 'post_pk'
Or a simpler way to fix this is change your url config to use pk instead:
path('delete/<int:pk>/', DeleteTodo.as_view(), name='delete_todo'),
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]
This is probably easy to solve. I created a form which use forms.ModelForm.
My model has ForeignKey field. Form creates a select field for foreignKey, but but does not display value correctly.
models.py
from django.db import models
# Create your models here.
class Gender(models.Model):
name = models.CharField(max_length=8, null=True)
class Meta:
db_table='gender'
class UserExample(models.Model):
name = models.CharField(max_length=16,null=True)
age = models.IntegerField(blank=True, null=True)
gender = models.ForeignKey('Gender', on_delete=models.SET_NULL, null=True)
class Meta:
db_table='userExample'
def __str__(self):
return ""
forms.py
from django import forms
from .models import UserExample, Gender
class UserForm(forms.ModelForm):
class Meta:
model = UserExample
fields = ('name', 'age', 'gender')
views.py
from django.shortcuts import render
from .forms import UserForm
# Create your views here.
def index(request):
form = UserForm
return render(
request,
'index.html',
{'form': form}
)
urls.py
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^$', views.index, name='index'),
]
index.html
<html>
<head>
<title>test </title>
</head>
<body>
<form action="formreturn/" method="post">
{{ form.as_p }}
<input type="submit" value="Submit" />
</form>
</body>
</html>
And after I launch my app. In select box I get only selection for gender objects but not for gender names.
Optional I used to add values using sqllite3 like this:
sqlite> insert into gender values(1,"Male");
sqlite> insert into gender values(2,"Female");
Implement __unicode__ or __str__ method in Gender model,
def __unicode__(self):
return '%s' % self.name
And it will display gender names in your option choices.
How to customize the default form field behavior of ForeignKey Model field
ForeignKey maps to ModelChoiceField and you can override the default behavior of the same. You can override the 'Select' option field value using 'to_field_name' parameter (useful when you have multiple unique fields in your related model) otherwise option field values are defaulted to pk field.
'empty_label' will change the default "--------" with the empty_label atrribute
forms.py
class UserForm(forms.ModelForm):
gender = forms.ModelChoiceField(queryset=Gender.objects.all(),
to_field_name = 'name',
empty_label="Select Gender")
class Meta:
model = UserExample
fields = ('name', 'age', 'gender')
Option display names are defaulted to __str__ method output. You can override the default behavior by writing a custom choice field class (inherited from ModelChoiceField) and override the label_from_instance() method.
def__str__(self):
return self.name
You will add this on your gender class
I already gave this answer in another place, hope it's not bad to copy paste.
In my case, I didn't wanna go make an str for my billion models, so I just did this:
You can make one custom ModelChoiceField to which you can pass a function. That way if you have different fields for which you want different attributes to be displayed, you can have only 1 class:
class CustomModelChoiceField(forms.ModelChoiceField):
name_function = staticmethod(lambda obj: obj)
def __init__(self, name_function, *args, **kwargs):
if not name_function is None: self.name_function = name_function
super(CustomModelChoiceField, self).__init__(*args, **kwargs)
def label_from_instance(self, obj):
return self.name_function(obj);
You can then call it as simply as this:
form_field = CustomModelChoiceField(
lambda obj: obj.get_full_name(),
queryset=Whatever.objects.all(),
)
You can also pass None in case you're doing some dynamic stuff and it'll just basically default to a regular ModelChoiceField. I'm not too much of a python guy but this works for me.
See some snippets please:
1.Model UserProfile:
from django.db import models
from django.contrib.auth.models import User
class UserProfile(models.Model):
user = models.ForeignKey(User, unique=True)
email = models.EmailField(unique=True)
HEAD_CHOICE = (
('1', 'M'),
('2', 'F'),
)
image_id = models.CharField(max_length=2, choices=HEAD_CHOICE, default='2')
2.Model TimeLine:
from django.db import models
from django.contrib.auth.models import UserProfile
class TimeLine(models.Model):
user = models.ForeignKey(UserProfile)
3.TimeLine's views.py
from models import TimeLine
from django.shortcuts import render_to_response
def index(request):
timelinedict = TimeLine.objects.all()
return render_to_response('timeline.html', locals())
Question: how can I make the var 'timelinedict' contain fields (image_id, email) of UserProfile.
Thanks in advance:)
Question: how can I make the var 'timelinedict' contain fields
(image_id, email) of UserProfile.
It already does:
from models import TimeLine
from django.shortcuts import render
def index(request):
timelinedict = TimeLine.objects.all()
return render(request, 'timeline.html', {'objects': timelinedict})
In timeline.html:
{% for obj in objects %}
{{ obj.user.email }}
{{ obj.user.image_id }}
{% endfor %}
Use the render shortcut, not render_to_response. render will return the correct request context, which is useful when you are processing forms. It is best to get into the habit of using render.
Don't use locals(); because you will send every variable in the scope to your template. This is never what you want. Explicit is better than implicit.
You don't need to do anything special, you can directly access those attributes from instance of TimeLine.
For example
for t in TimeLine.objects.all():
print t.user.image_id, t.user.email
Similarly you can use that in template as well.
Your example for timelinedict isn't actually a dict it's a queryset containing TimeLine objects.
I think using the #property decorator as below will allow you to attach attributes to your TimeLine model objects.
class TimeLine(models.Model):
user = models.ForeignKey(UserProfile)
#property
def image_id(self):
return self.user.image_id
#property
def email(self):
return self.user.email
Of course, you could just access them directly in your template via object.user.image_id, etc.
I found something strange in Django's documentation which is called formset, see it here.
I am wondering What is formset used for and How to use it?
Formset is an example of datagrid .
If you want to use multiple form of same type at one page.you can use Formset.
Example :
class UserForm(forms.ModelForm):
class Meta:
model = User
fields = ["username", "email"]
Now if you want to use UserForm multiple times at one page you need to use Formset.
from django.forms.formsets import formset_factory
Uforms = formset_factory(UserForm, extra = 4) #extra used to define how many empty forms will display
Into Your views.py
def submit(request):
if request.POST:
#code to manage post request
# validation to formset you can follow django docs
else:
address_formSet = Uforms(instance=UserForm())
# render response
Template code
{{ address_formset.as_table }}
You can follow step by step django formset to learn.
Example Code
class Address(models.Model):
city = models.CharField(max_length=48)
zipcode = models.IntegerField(max_length=5)
class Friend(models.Model):
name = models.CharField(max_length=30)
address = models.ForeignKey(Address)
forms.py
from django import forms
from .models import Address, Friend
from django.forms.models import inlineformset_factory
MAX_ADDRESS = 2 #updated
AddressFormSet = inlineformset_factory(Address, Friend, extra=MAX_ADDRESS) #updated
class UserAddressForm(forms.ModelForm):
class Meta:
model = Address
view.py
from django.shortcuts import render_to_response
from .models import *
from .forms import UserSubmittedAddressForm, AddressFormSet
def submit(request):
if request.POST:
#Logic
else:
form = UserAddressForm()
address_formSet = AddressFormSet(instance=Address())
# render response
template code
{{ form.as_table }}
{{ address_formset.as_table }}
It's used to work with e.g. a table of records. It's a way to create data grid functionality in such a way that Django does all the heavy lifting (all data for all the records are sent back in the same POST).