I created an app called "jobs", basically I'd like to create new "jobs" from the admin console and be able to post it on the jobs.html page.
I created the model and views but I think there is something wrong with the views that doesn't allow me to print the "jobs" on the html template.
Can you please tell me if the error is in views.py?
jobs/models.py
from django.db import models
# Create your models here.
class post_job(models.Model):
posizione= models.TextField(max_length=20)
descrizione= models.TextField(max_length=20)
requisiti= models.TextField(max_length=20)
def __str__(self):
"""String for representing the MyModelName object (in Admin site etc.)."""
return self.posizione
jobs/admin.py
from django.contrib import admin
from .models import post_job
# Register your models here.
admin.site.register(post_job)
jobs/views.py
from django.shortcuts import render
from .models import post_job
# Create your views here.
def viz_job(request):
posizione = post_job.posizione
print(posizione)
return render(request,'jobs/jobs.html',{'posizione':posizione})
Proper answer:
In your views:
from django.shortcuts import render
from .models import PostJob # proper naming
def viz_job(request):
jobs = PostJob.objects.all()
return render(request,'jobs/jobs.html',{'jobs': jobs})
in your template:
<ul>
{% for job in jobs %}
<li>
<h3>{{ job.posizione }}</h3>
<div>
{{ job.descrizione }}
</div>
</li>
{% endfor %}
</ul>
Note that all this is documented.
NB: if you're only interested in those two fields and don't need any of the model's methods, related objects or whatever, you can optimize the query a bit by using a values queryset that will yield dicts with the selected fields instead of full model instances:
jobs = PostJob.objects.values("posizione", "descrizione")
Everything else remains the same.
You have to know what do you want to return for the template, for example in the views.py :
from django.shortcuts import render
from .models import post_job
# Create your views here.
def viz_job(request):
jobs = []
descriziones = []
posizione = Job.objects.all()
for pos in posizione:
jobs.append(pos.posizione)
descriziones.append(pos.descrizione)
context = {
'posizione': jobs,
'descrizione': descriziones
}
return render(request, 'jobs/jobs.html',
context=context) # this will return context dictonary to the template
You can filter and get to fetch specific data from your database
Related
I'm currently attempting to learn how to use django to build a website but my input data in the models is not showing up properly
'''
from django.db import models
class products(models.Model):
name = models.CharField(max_length=255)
def __str__(self):
return self.name
class typeWork(models.Model):
work = models.CharField(max_length = 255)
hoursWorked = models.IntegerField()
number_in_stock = models.IntegerField()
daily_rate = models.FloatField()
genre = models.ForeignKey(products, on_delete=models.CASCADE)
'''
models.py
'''
from django.urls import path
from . import views
urlpatterns = [
path('hello/', views.hello, name='hello')
]
'''
urls.py
from django.shortcuts import render
from django.http import HttpResponse
from .models import typeWork
def hello(request):
products2 = {typeWork.objects.all()}
return render(request, 'index.html', {products2})
views.py is slightly altered as i was messing with it in order to try and fix it the image shows the code with no alterations and my original issue arising from that code
views.py
<table class="table">
<thead>
<tr>
<th>Work</th>
<th>Type of Work</th>
<th>Hours needed</th>
</tr>
</thead>
<tbody>
{% for products2 in products%}
<tr>
<td>{{products2.work}}</td>
<td>{{products2.genre}}</td>
<td>{{products2.hoursWorked}}</td>
</tr>
{% endfor %}
</tbody>
indes.html is also slightly altered the image will show the original code before i tried fixing it again
index.html
Actual error and what it does show currently
You can try passing your products2 variable through a so-called "context dictionary".
Updated version of views.py:
I'm currently attempting to learn how to use django to build a website but my input data in the models is not showing up properly
from django.shortcuts import render
from django.http import HttpResponse
from .models import typeWork
def hello(request):
products2 = typeWork.objects.all()
context = {"products2": products2}
return render(request, 'index.html', context)
You had some idea on how to pass these variables when you put the {} symbols, but only adding names between these symbols will pass a set. A dictionary would mean the curly braces + a set of key-value pairs.
The main idea is, everytime you're trying to pass data to a view, you'll need to do it via a dictionary. The key you're using will also be used in the template. By replacing your code with the one I wrote, you're going to be okay because your template is iterating through something called products2.
It's my first time to use ListView and it doesn't work and give me error.
I put get_query but they still give me same error. How can I fix the problem?
And everytime when I write code in views.py I always used 'def' not 'class'. But could see many people use (and also django documents) 'class' for ListView. So for general render stuffs we use 'def' and for django.views.generic stuffs we use class right? Why they distinguished these two?
This is error what I got.
ImproperlyConfigured at /search/results
ListView is missing a QuerySet. Define ListView.model, ListView.queryset, or override ListView.get_queryset().
urls.py
from django.urls import path
from django.conf import settings
from django.views.generic import ListView, TemplateView
from . import views
app_name = 'search'
urlpatterns = [
path('', TemplateView.as_view(template_name = "search/index.html")),
path('results', ListView.as_view(template_name = 'search/results.html')),
path('beerlist', views.beerlist, name='beerlist'),
path('<int:beerinfo_id>', views.beerinfo, name='beerinfo'),
]
views.py
from django.shortcuts import render, get_object_or_404, redirect
from django.db.models import Q
from django.views.generic import ListView, TemplateView
from .models import Beerinfo
# Create your views here.
def index(TemplateView):
template_name = 'search/index.html'
def results(ListView):
model = Beerinfo
template_name = 'search/results.html'
def get_queryset(self):
query = self.request.GET.get('q')
object_list = Beerinfo.objects.filter(
Q(name__icontains = query) | Q(label__icontains = query)
)
return obejct_list
index.html
<form action="{% url 'search:results' %}" name="se">
<label for='search'>What do you want to find?</label>
<input type="text" name='q'>
<input type="submit">
</form>
results.html
<ul>
{% for beer in ojbect_list %}
<li>{{ beer.name }}</li>
{% endfor %}
</ul>
models.py
from django.db import models
# Create your models here.
class Beerinfo(models.Model):
name = models.CharField(max_length=100)
label = models.CharField(max_length=500)
def __str__(self):
return self.name
You need to define the class that the list view will work with. For example:
class UserListView(ListView):
model = User
You can use a function (def) to accomplish the same thing that a generic view class, the difference is that most of what you write in the function is already defined in the class. In my example above, that class already handles the rendering of a default template, a context with the list of object of that template and pagination. The idea is to keep your code DRY.
The second advantage is that it creates a standard for your code, for example the default template to be used is
%(app_label)s/%(model_name)s%(template_name_suffix)s.html, so if your app name is users and your model is User, the this view expects a template named users/userlist.html
To use the pagiation simply set the paginate_by attribute of the class.
If you are trying to implement a simple view (for example all CRUD actions, then is very likely that you will benefit from using clases. Another good thing that classes give you, is that you can inherit goodies, for example, you can create a BaseListView class that inherits from ListView and set paginate_by to 25. If all your clases inherit from BaseListView then all your list will be paginated by 25 elements.
In views.py change def to class , you need to define a class to use Listview, Class Results(ListView). In urls.py, you are calling Listview , you should call views.Results.as_view()
I get stuck. I try to display each time a other table in django with the same def in my view.py code.
First problem is I can't transfer the string which I enter in the url to a model.
For example if I type 0.0.0.0:8000/polls/Cashflows I wanna display the table Cashflows of my db.
from django.http import HttpResponse
from django.template import loader
from django.apps import apps
from .models import Cashflows,Garbage,Inputacturial
def index(request):
list_cashflows=Cashflows.objects.all()
template=loader.get_template('polls/index.html')
context={'list_cashflows':list_cashflows,}
return HttpResponse(template.render(context,request))
def detail(request, table):
#model = apps.get_model('polls', 'table')
#model=apps.get_model ( 'polls',table.split('.',1))
model=Cashflows
liste_column=model.objects.all()
b=model._meta.get_fields()
#b=a[:]
liste_fields=list(b)
template=loader.get_template('polls/index2.html')
context={'liste_column':liste_column,'liste_fields':liste_fields,}
return HttpResponse(template.render(context,request))
I try different options but none of these really work for.
My next problem is to display these different tables.
I try to start with the field names.
<table>{% for item in liste_fields%}
<tr><th>liste_fields.item</th>
</tr>
{% endfor %}
</table>
It's just give me three rows with liste.fields.item and not columns with each field. Can you help me?
You have of use the o method verbose_name
For example:
list_fields = [field.verbose_name for field in Cashflows._meta.get_fields() if not field.is_relation or field.one_to_one or (field.many_to_one and field.related_model)]
https://docs.djangoproject.com/en/2.0/ref/models/meta/#migrating-from-the-old-api
I want to create custom page for admin panel without model. For first i copy index.html to project folder:
mysite/
templates/
admin/
index.html
Then add to apps block my code:
<div class="module">
<table summary="{% blocktrans with name="preferences" %}Models available in the preferences application.{% endblocktrans %}">
<caption>{% blocktrans with name="preferences" %}Preferences{% endblocktrans %}</caption>
<tr>
<th scope="row">Preferences</th>
<td>{% trans 'Change' %}</td>
</tr>
</table>
</div>
This works good, then I create new page /templates/admin/preferences/preferences.html and
add to urls.py:
url(r'^admin/preferences/$', TemplateView.as_view(template_name='admin/preferences/preferences.html')),
And add code to preferences.html:
{% extends "admin/base_site.html" %}
{% block title %}Test page{% endblock %}
Run it and see message with error "The requested admin page does not exist.". What I do wrong?
You need to add your admin URL before the URL patterns of the admin itself:
urlpatterns = patterns('',
url(r'^admin/preferences/$', TemplateView.as_view(template_name='admin/preferences/preferences.html')),
url(r'^admin/', include('django.contrib.admin.urls')),
)
This way the URL won't be processed by Django's admin.
Years go by and still a relevant answer to this can be posted.
Using Django 1.10+ you can do:
security/admin.py (this is your app's admin file)
from django.contrib import admin
from django.conf.urls import url
from django.template.response import TemplateResponse
from security.models import Security
#admin.register(Security)
class SecurityAdmin(admin.ModelAdmin):
def get_urls(self):
# get the default urls
urls = super(SecurityAdmin, self).get_urls()
# define security urls
security_urls = [
url(r'^configuration/$', self.admin_site.admin_view(self.security_configuration))
# Add here more urls if you want following same logic
]
# Make sure here you place your added urls first than the admin default urls
return security_urls + urls
# Your view definition fn
def security_configuration(self, request):
context = dict(
self.admin_site.each_context(request), # Include common variables for rendering the admin template.
something="test",
)
return TemplateResponse(request, "configuration.html", context)
security/templates/configuration.html
{% extends "admin/base_site.html" %}
{% block content %}
...
{% endblock %}
See Official ModelAdmin.get_urls description (make sure you select proper Django version, this code is valid for 1.10 above)
Note the use of get_urls() above.
This new admin page will be
accessible under:
https://localhost:8000/admin/security/configuration/
This page will be protected under admin login area
You should be using admin's get_urls.
If you want to create a custom page just to place there an arbitrary form to handle user input, you may give django-etc a try. There's etc.admin.CustomModelPage you can use:
# admin.py
from etc.admin import CustomModelPage
class MyPage(CustomModelPage):
title = 'My custom page' # set page title
# Define some fields you want to proccess data from.
my_field = models.CharField('some title', max_length=10)
def save(self):
# Here implement data handling.
super().save()
# Register the page within Django admin.
MyPage.register()
Here's an example of everything that should be needed (as of Django 1.6) for a custom admin page that is linked to from a button next to the "History" button in the top right of an object's detail page:
https://gist.github.com/mattlong/4b64212e096766e058b7
Full example:
from django.urls import path
from django.contrib import admin
from django.db import models
class DummyModel(models.Model):
class Meta:
verbose_name = 'Link to my shiny custom view'
app_label = 'users' # or another app to put your custom view
#admin.register(DummyModel)
class DummyModelAdmin(admin.ModelAdmin):
def get_urls(self):
view_name = '{}_{}_changelist'.format(
DummyModel._meta.app_label, DummyModel._meta.model_name)
return [
path('my_view/', MyCustomView.as_view(), name=view_name)
]
With this approach Django's makemigrations command will create DB migration to create table for DummyModel.
Extending the AdminSite class worked best for me, as per django's documentation. This solution protects the page(s) under the admin site login mechanism, and setting it up is easier than it may look:
Where you have other admin code (eg. myapp/admin.py), extend the default class:
from django.contrib.admin import AdminSite
class CustomAdminSite(AdminSite):
def get_urls(self):
custom_urls = [
path('admin/preferences/', self.admin_view(views.my_view)),
]
admin_urls = super().get_urls()
return custom_urls + admin_urls # custom urls must be at the beginning
site = CustomAdminSite()
# you can register your models on this site object as usual, if needed
site.register(Model, ModelAdmin)
Implement the view
def my_view(request):
return render(request, 'admin/preferences/preferences.html')
Use that admin site in urls.py, instead of the default one
from myapp import admin
# now use admin.site as you would use the default django one
urlpatterns = [
# ...
path('admin/', admin.site.urls),
# ...
]
If you want to hook a page into the existing admin site, then you can do the following, which is based on #arnaud-p's answer above. Arnaud's answer didn't work for me, as subclassing adminsite's get_url function lost access to existing admin pages until I added the registry as follows.
Using the following method, your additional pages will require staff access, and you don't need to change your urls.py, so this is great for making admin pages for apps etc... You can pass each_context in the view in order to get permissions etc.
works for django 3.2.9
In admin.py
from django.contrib import admin
from django.urls import path
from . import views
class CustomAdminSite(admin.AdminSite):
def get_urls(self):
self._registry = admin.site._registry
admin_urls = super().get_urls()
custom_urls = [
path('preferences/', views.Preferences.as_view(admin=self), name="preferences"),
]
return custom_urls + admin_urls # custom urls must be at the beginning
def get(self):
request.current_app == self.name
return super().get(request)
def get_app_list(self, request):
app_list = super().get_app_list(request)
app_list += [
{
"name": "My Custom Preferences App",
"app_label": "Preferences",
# "app_url": "/admin/test_view",
"models": [
{
"name": "Preferences",
"object_name": "preferences",
"admin_url": "/admin/preferences",
"view_only": True,
}
],
}
]
return app_list
site = CustomAdminSite()
the view...
class Preferences(views.generic.ListView):
admin = {}
def get(self, request):
ctx = self.admin.each_context(request)
return render(request, 'admin/preferences/preferences.html', ctx)
the template...
{% extends "admin/base_site.html" %}
{% block content %}
...HELLO WORLD!
{% endblock %}
I am new to django (1.2.4). I have created some crud with generic views. But How can I show something like "The student was added successfully" when student is created using django's messaging framework?
As of Django 1.6+, using any class-based generic views, you can rely on the successMessageMixin. It's as simple as adding the mixin to your class definition and setting success_message attribute to whatever you want.
As Olivier Verdier mentioned, please remember to display messages in your main template!
a simple example from the docs:
from django.contrib.messages.views import SuccessMessageMixin
from django.views.generic.edit import CreateView
from myapp.models import Author
class AuthorCreate(SuccessMessageMixin, CreateView):
model = Author
success_url = '/success/'
success_message = "%(name)s was created successfully"
a more complex example:
from django.contrib.messages.views import SuccessMessageMixin
from django.views.generic.edit import CreateView
from myapp.models import ComplicatedModel
class ComplicatedCreate(SuccessMessageMixin, CreateView):
model = ComplicatedModel
success_url = '/success/'
success_message = "%(calculated_field)s was created successfully"
def get_success_message(self, cleaned_data):
# cleaned_data is the cleaned data from the form which is used for string formatting
return self.success_message % dict(cleaned_data,
calculated_field=self.object.calculated_field)
As far as I know, there isn't a straightforward way of doing this using traditional generic views. I've always felt that the documentation on generic views was pretty lacking and so never used them.
In theory you could use a decorator by making the assumption that a redirect meant a successful submission.
So you could write something like this (none of this code has been tested):
urls.py:
try:
from functools import wraps
except ImportError:
from django.utils.functional import wraps
from django.http import HttpRedirectResponse
from django.contrib import messages
from django.views.generic import *
def add_message(success_message=None):
def decorator(func):
def inner(request, *args, **kwargs):
resp = func(request, *args, **kwargs)
if isinstance(resp, HttpRedirectResponse):
messages.success(request, message)
return resp
return wraps(func)(inner)
return decorator
student_info_edit = {
'template_name': 'myapp/student/form.html',
'template_object_name': 'student',
'form_class': studentForm,
}
student_info_new = {
'template_name': 'myapp/student/form.html',
'form_class': studentForm,
'post_save_redirect': '/myapp/students/',
}
urlpatterns += patterns('',
url(r'^students/$', list_detail.object_list, { 'queryset': Student.objects.all() }, name="students"),
url(r'^students/(?P<object_id>\d+)/$', add_message("Student record updated successfully")(create_update.update_object), student_info_edit, name="student_detail"),
url(r'^students/new$', add_message("The student was added successfully.")(create_update.create_object), student_info_new, name="student_new"),
)
All that said and coded, Django 1.3 introduced class-based generic views, so if you're interested in moving onto Django 1.3 you should look into those. They may allow more customization, not sure.
In the long run I rarely see the benefit form using generic views, and this goes double for things like add/update.
The functionality that you are asking for is already implemented in Django generic views:
https://github.com/django/django/blob/1.2.X/django/views/generic/create_update.py#L115
You will see the messages by displaying messages in your main template.
Actually I think the documents explain it pretty well for generic/function based views:
https://docs.djangoproject.com/en/2.0/ref/contrib/messages/
It basically passes context to your template with an if statement to display that context or not.
View:
from django.contrib import messages
def home_page(request):
if request.method == 'POST':
messages.success(request, 'Student added successfully')
context = {}
return render(request, 'homepage/index.html', context)
else:
form =yourForm()
return render(request, 'homepage/index.html', form)
And then it will be displayed in your template using the following. Remember to iterate '...because otherwise the message storage will not be cleared for the next request':
{% if messages %}
<ul class="messages">
{% for message in messages %}
<li{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
As it renders the page again just add an anchor tag to your form and include in your form action i.e.
action="{% url 'home_page:index' %}#subscribe"
If you're using bootstrap add class alert-success