Django display different models/tabells - python

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

Related

Django file not showing input data in actual website

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.

How to replace Foreign Key with Many To Many in Django models without broking whole app?

I want to change my Foreign Key to Many To Many field to let the user select multiple categories in a dropdown list.
This is what I already have. After I change Foreign Key to Many To Many I'm getting milion errors, I have to get rid of on_delete=models.CASCADE which is a core of my app. What can I do? Which way should I take? Maybe add another model? I'm so confused, especially when I am a Django newbie. Thank you for your help!
MODELS
class Category(models.Model):
name = models.CharField(max_length=50, unique=True)
def __str__(self):
return f'{self.name}'
class Expense(models.Model):
class Meta:
ordering = ('date', '-pk')
category = models.ForeignKey(Category, null=True,blank=True, on_delete=models.CASCADE)
name = models.CharField(max_length=50)
amount = models.DecimalField(max_digits=8,decimal_places=2)
date = models.DateField(default=datetime.date.today,db_index=True)
def __str__(self):
return f'{self.date} {self.name} {self.amount}'
The clue of the application is to let the user create a category e.g "PC". Then add some expenses like "GPU", "CPU" etc... and let the user link it to the "PC" category. And when the user wants to delete certain categories, all the expenses linked to it, gonna be deleted too. And this is the thing I have already did. BUT NOW I want to let the user search the main table of expenses by multiple categories. And here comes my problem, I don't have a clue how to do it and keep the whole application in one piece with all the functionalities.
SCREENSHOTS:
Categories View with just added PC category
Expense Add View
I don't think there is a simple answer to your question, but here are some resources that might help. First, I don't think you should change your models. From the way you described your application, I think a foreign key model with on_delete=CASCADE is good. The basic idea here is that you need to change your list view function so that it performs a query of your database. Also modify your template.html to include a search bar.
https://github.com/csev/dj4e-samples/tree/master/well
https://www.dj4e.com/lessons/dj4e_ads4
Modify Your List View To Allow The Searching
This is an example of a list view that allows you to search for a single term, and returns anything in the database that matches from any field. This isn't what you want to do exactly, but if you can get this working then you can modify the search conditions for your specific application. What is going on in the code below is that instead of return every item in my Ad table in my SQL database, I filter it based on the search. Then, I pass "ad_list" to the template view. Since I already filtered ad_list based on the search, in the template view it will only list the items that match. This is based on the DJ4E course, and you can watch the video there to get an idea of how he implements the search bar better.
from ads.models import Ad
from django.views import View
from django.shortcuts import render, redirect, get_object_or_404
from django.urls import reverse_lazy, reverse
from django.http import HttpResponse
from django.core.files.uploadedfile import InMemoryUploadedFile
from django.contrib.humanize.templatetags.humanize import naturaltime
from ads.utils import dump_queries
from django.db.models import Q
class AdListView(ListView):
# By convention:
template_name = "ads/ad_list.html"
def get(self, request) :
strval = request.GET.get("search", False)
if strval :
# Simple title-only search
# objects = Ad.objects.filter(title__contains=strval).select_related().order_by('-updated_at')[:10]
# Multi-field search
query = Q(title__contains=strval)
query.add(Q(text__contains=strval), Q.OR)
objects = Ad.objects.filter(query).select_related().order_by('-updated_at')[:10]
else :
# try both versions with > 4 posts and watch the queries that happen
objects = Ad.objects.all().order_by('-updated_at')[:10]
# objects = Ad.objects.select_related().all().order_by('-updated_at')[:10]
# Augment the post_list
for obj in objects:
obj.natural_updated = naturaltime(obj.updated_at)
ctx = {'ad_list' : objects, 'search': strval}
retval = render(request, self.template_name, ctx)
dump_queries()
return retval;
Modify Your Template.html to include a search bar
<form>
<input type="text" placeholder="Search.." name="search"
{% if search %} value="{{ search }}" {% endif %}
>
<button type="submit"><i class="fa fa-search"></i></button>
<i class="fa fa-undo"></i>
</form>
PS, I think you can answer your own question better when you figure it out, so help others and post it!

Django - printing variables in templates

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

Django ListView

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()

pass data from view to form as choices

Do not understand how to pass data obtained from form.data in view as choices to form field. I would really appreciate any help.
So, here is what I am doing: I choose data using checkboxes at page, and then I need to display chosen data (their names) at the same page with additional textfield near each. Later all textfields must be filled and 'names' and inserted data must be sent to server.
As I understand for this I need to render data with textfield using form. I suppose it could be this one:
forms.py
import methods
class MultiTextField(SelectMultipleField):
widget = widgets.TableWidget()
option_widget = widgets.TextInput()
class SelectedForm(Form):
choices = methods.selected()
value = MultiTextField('value',choices = choices)
views.py
from forms import ...
selected_data = {}
def return_selected():
return selected_data
methods.py
from views import return_selected
def selected():
data = return_selected()
choices = []
for key, value in data.iteritems():
for item in value:
choices.append((item, key))
return choices
Variable selected_data stores data that were chosen through other form.
If I run this code I got error ImportError: cannot import name return_selected. Probably it is because I import views in methods, methods in forms and forms in views o.O
I see no other way how to make what I need, but it does not work as it is.
Well, I found how to pass choices.
forms.py
class MultiTextField(SelectMultipleField):
widget = widgets.TableWidget()
option_widget = widgets.TextInput()
class SelectedForm(Form):
name = MultiTextField()
views.py
#app.route('/home', methods=['GET', 'POST'])
def show_work():
selected = SelectedForm(request.form)
choices = []
for key, value in selected_data.iteritems():
choices.append((key, value))
selected.name.choices = choices
return render_template('home.html', selected=selected)
It is possible to add form choices in views with selected.name.choices = choices.
But this form puts data in strange way:
home.html
<form name="selected" action="{{url_for('selected_work', url='result') }}" method="post">
<p> {{selected.name}}</p>
<input type="submit" value="Calculate">
</form>
in choices was lets say: [(1,"Apple"), (2,"Apple")] but html show label 'Apple' and near it textfield with inserted number 1 and again label 'Apple' with number 2 inserted in textfield.
When I submit form ofcourse it sends inserted data in textfield, which is ['1', '2']. But somehow I need obtain: [(Apple, 1 and value inserted in textfield),(Apple, 2, inserted value)].
You have a circular dependency. Views import forms, which imports methods, which imports forms.
But your proposed solution is extremely dangerous. You are storing data at module level, which is absolutely not thread-safe and will lead to information leaking between users. Do not do this. Store the data in the session, which is per-user.
Thank you Daniel for your advice about session. I store chosen data in session now.
Here is how I solved my task. I decided not to use wtforms form for rendering data chosen with checkboxes. I keep all choices in session
views.py
import methods
from forms import ...
def make_record(works):
if session['data']:
if not works:
pass
else:
for work in works:
session['data'].append(work)
else:
session['data'] = [works]
#app.route('/home', methods=['GET', 'POST'])
def show_work():
demount = DemountForm(request.form)
tile = TileForm(request.form)
chosen = []
for each in session['data']:
chosen.append(each)
selected = methods.get_selected(chosen)
return render_template('home.html', demount=demount, tile=tile, selected = selected)
#app.route('/home/<path:url>', methods=['GET', 'POST'])
def select_work(url):
db = url
if db:
form = DemountForm(request.form)
work = form.name.data
make_record(work)
return redirect(url_for('show_work'))
methods.py
def get_selected(ids):
selected = {}
for each in ids:
data = db_session.query(Work.name, Work.dimension).filter(Work.id==each).all()
data = data[0]
selected[each] = data
return selected
home.html
{% if selected %}
<div id="chosen">
<form action="/home">
{% for key, value in selected.iteritems() %}
{{value[0]}}<input type="text" id="{{key}}">{{value[1]}}<br>
{% endfor %}
<input type="submit" value="Submit">
</form>
</div>
{% endif %}
In such way I obtained what I needed. On one page I got menu with checkboxes and div which display choices and textfields near each to insert additional data.

Categories