Using select widget in Django to get data from Postgres database - python

I am very new to Django, to Stackoverflow and to coding in general, so I'd appreciate any help.
I am trying to add a form to my website, which would have only select fields. After a user selects all options, I want to redirect them to another page, where I return different information in several tables from my database, based on all selects (all selected options together influence information shown in the tables).
I know this example is awkward, this is all made up just to give an idea of what I want to achieve in the end.
An example:
First page has 3 options:
book genre
city
age
Redirected page has three tables:
Most read books in this genre in this city by people around this age
List of libraries in this city, sorted based on how many books in this genre are there
How to sign up to top 3 libraries
A user does not modify the database in any way, so I suppose the form can have GET method.
So my question is what would be the best way to get values from the user and get a unique value based on that from the database? I want to return one list for each table, which I am planning to be regularly updating for each city, for each age group and for each genre.
I am trying to do this with the select widget now. For now I do not return anything, because I am not sure how to get the data from the user and use it.
forms.py:
class MyForm(forms.Form):
select1 = forms.ChoiceField(widget=forms.Select,
choices=Select1.objects.all().values_list('id', 'name'))
select2 = forms.ChoiceField(widget=forms.Select,
choices=select2.objects.all().values_list('id', 'name'))
select3 = forms.ChoiceField(widget=forms.Select,
choices=select3.objects.all().values_list('id', 'name'))
views.py
class Page(TemplateView):
template_name = 'project/index.html'
def get(self, request):
form = MyForm()
return render(request, self.template_name, {'form': form})
html:
<select name="{{ form.select1.name }}">
<option class="dropdown-menu" value="" disabled selected>Please
select</option>
{% for choice in form.select1.field.choices %}
<option value="{{ select1.0 }}">{{ select1.1 }}</option>
{% endfor %}
</select>
and the same code for the other two selects. I rendered them separately because of the way I designed the website.

Related

Django forms select from choices or enter new data

I have a Django form in which for some fields I pull choices from my database, shown below.
I have another field in which the user has to manually type in the data. Is it possible to give that field choices that are present from the database and an option to enter the data if the choice isn't there?
Example: The field name is player and I would like to have all the players already in database as options to choose from and if it is a new player, the option to enter it.
Is that what a TypedChoiceField is? I have been trying to find examples but no luck.
thanks!
forms
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
team_names = TeamName.objects.filter(league__name='MLB').order_by('name')
teams = [(team.id, team.name)for team in team_names]
self.fields['team'].choices = teams
TypedChoiceField is not what you think it is. It simply starts on a default value instead of a "------" blank value.
You could not define choices= on your model. But instead define a list of default choices outside of the model.
my_choices = (
"foo",
"bar",
"pop",
)
class MyModel(models.Model):
my_field = models.CharField(max_length=100)
Then in your view you'd want to import that tuple and pass it to you template:
from my_app.models import my_choices
def my_view(request, *a, **kw):
# view logic
return render(request, "path/to/my/template", choices=my_choices)
Then in your template you can have a select box with the default choices and string values. And also have an optional input type=text that will save to that field if populated.
Something like:
<select name="my_field">
<option value="" selected="selected">-----</option>
{% for choice in choices %}
<option value="{{ choice }}">{{ choice }}</option>
{% endfor %}
</select>
Will give you default choices. Then add an input with the same name, this will act as an optional new choice.
<input type="text" name="my_field"/>
Optionally you could write javascript logic that will ensure only the selectbox or the textfield gets submitted.

Show person list based on group selection list in django

I'm pretty new in django/ Python and any help will be appreciated
I'm trying to populate a list of person based on click on another list (Group)
Model:
class Grupo(models.Model):
Nome = models.CharField(max_length=20)
View
class GruposListView(ListView):
model = Grupo
template_name = 'reports/relatorio_form.html'
context_object_name = 'Grupo'
HTML
<h4 class="mb-3">Select a group:</h4>
<select id="Group" name="Group" size="5">
{% for Grupo in Grupo %}
<option value="Grupo">{{Grupo.Nome}}</option>
{% endfor %}
</select><br><br>
Here the result on the first list:
You needs rather some good tutorial instead of this answer.
HTML should have <form> and <button> to send selected group to server (ie. to other class GroupDetailView), and serve should get in as argument using
re_path(r'^group/(?P<group_number>\d+)$', views.GroupDetailView.as_view(), name='group-detail'),
and
class GroupDetailView(...):
def group_detail_view(request, group_number):
and use it to get persons from selected group
def group_detail_view(request, group_number):
persons = Person.objects.get(group=group_number)
and generate page with these person.
def group_detail_view(request, group_number):
persons = Person.objects.get(group=group_number)
return render(request, 'group_detail.html', context={'persons': persons})
All based on tutorial Django Tutorial Part 6: Generic list and detail views

In Django, how would you have an html page that lists all objects in the database with a common attribute?

First off, I'm a rookie on the field so if I miss out any necessary details, please do let me know and I'll update ASAP.
Working with Django framework and SQLite database, I would like to have two html pages that list all items with the same "type" attribute.
Right now models.py looks like this (there are more attributes after this, but that doesn't matter here, I think):
class Articulo(models.Model):
MEDICINAL = 'med'
AUTOCULTIVO = 'cul'
TIPO_PROD = [
(MEDICINAL, 'Medicinal'),
(AUTOCULTIVO, 'Autocultivo'),
]
tipo = models.CharField(
max_length=3,
choices=TIPO_PROD,
default=MEDICINAL,
)
So I'd like for one of the html pages to list all the items with 'med' and another for all the items with 'cul'.
What I have tried is to write something similar to the search function to bring up those items by filtering that attribute, like this:
def medicinal(request):
items = Articulo.objects.filter(tipo__icontains=med)
return render(request, 'medicinales.html', {'articulos': articulos})
However, I'm really not sure how to continue from there.
I also want to add CSS to the list once it's displayed, but for that I will replicate the one I use for the search function, since I want them to retain the same style.
Thank you very much in advance and again, please let me know if I missed out some important information.
You don't need to use two views to do this, you can define one ListView, and then filter the data shown in the list by defining a get_queryset function in your view. Here is a quick example to give you an idea:
urls.py
path(r'list/', ArticuloListView.as_view(), name='articulo-list')
views.py
class ArticuloListView(ListView):
model = Articulo
context_object_name = 'articulos'
template = 'artucilo_list.html' #this path may differ depending on your project structure
def get_queryset(self):
search_term = self.request.GET['q'] #'q' is defined in your search form
return Articulo.objects.filter(tipo=search_term)
search template
...
<form action="{% url 'articulo-list' %}" method='GET'>
<input name="q" type="text" value="{{ request.GET.q }}" placeholder="Search"/>
</form>
...
articulo_list.html template
...
{% for articulo in articulos %}
{{ articulo.tipo }}
{% endfor %}
...
You dont have to filter based on a search form, you can also manually do it by using the querystring in a link href, like this:
Med List
I have managed to get it done by using a queryset as iri suggested, but in a simpler way.
In urls.py
path('medicinales/', productos_med, name='medicinales'),
In views.py:
def productos_med(request):
queryset = Articulo.objects.filter(tipo='med')
context = {
"object_list": queryset
}
return render(request, "medicinales.html", context)
And in medicinales.html (the page with the list of all 'med' objects):
{% for instance in object_list %}
<p>{{instance.nombre}}</p>
<p>{{instance.descripcion}}</p> <!-- And so on for every wished attribute. -->
Then for objects with attribute 'cul' I followed the same steps changing tipo in queryset to 'cul' and rendering a different html page. After that applying CSS was easy!
Thank you very much iri for answering and pointing me in the right direction and the community for being such an awesome source of info!

CBV: How To Make A Drop Down Database Query Using Django FormView

What I would like to do is have a dropdown list containing objects from a database. When the user selects an object, I would like the information displayed on the page.
What I have been able to do is have the values shown in the dropdown list, but I have not been able to display the way I'd like. I've been trying to do so a certain way to hopefully be able to better control the look of the form.
models.py
class Vehicle(models.Model):
make = models.CharField(max_length=20)
model = models.CharField(max_length=20)
def __str__(self):
return self.make + ' ' + self.model
class Package(models.Model):
make_model = models.ForeignKey(
Vehicle, on_delete=models.CASCADE
)
name = models.CharField(max_length=20)
price = models.IntegerField()
views.py
class VehicleCompareView(FormView):
template_name = "main/somehtml.html"
form_class = forms.CompareForm
forms.py
objectlist = forms.ModelChoiceField(queryset=models.Package.objects.all() \
.order_by('make_model__make'))
html file
<form method="GET">
<select class="form-control">
<option value="0" selected disabled>Select Vehicle 1</option>
{% for q in form.objectlist %}
<option value="{{q.name}}">{{ q.make_model__make }}</option>
{% endfor %}
</select>
</form>
<div>
<p>Selected Vehicle: {{q.make_model__make}} {{q.make_model__model}}<br>
Price: ${{q.price}}
</p>
</div>
So let's start with what I have found that somewhat works from messing with the code.
If I use {{form}}, I get the package list, but it only displays the package name of course. If I attempt to use .values() in the query set in forms.py, it returns what I want, but in a dictionary(so it'll literally show 'make': 'someMake', 'model':'someModel', 'package:'somepackage') in the user dropdown list.
When I attempt to do the select/option way that I prefer to, after the for loop doing {{ q }} returns the same list of packages, but if I try to format what I want to see {{ q.make_model__make }} {{ q.make_model__model }} {{q.name}}, nothing shows except a dropdown of blanks(though the correct number of blanks).
There may be a better way than what I'm trying, but from a lot of searching and looking around on here I found my way to using a FormView with a ModelChoiceField query set. At the end of the day, I want a dropdown list to show Make Model Name from the database. When the user makes a selection, I would like to display the attributes on the page. Obviously I haven't even gotten to the issue of the selection part yet. From what I understand I'll need to use Ajax to have everything populate on selection. But that's a problem for another time. For now I'd just like the dropdown to display the way I'd like. Preferably using the select/option method so I can have control over the look rather than just rendering a generic form.
I solved my issue. I started reading all posts on Django query forms I could find, including those that didn't relate to my issue, to better understand exactly how everything works. Someone mentioned that the select statement is built inside the ModelForm. I then realized I was trying to force two different things, and why what I was doing didn't really make sense. I played with the code some more and here is what I did to solve my issue of displaying in the manner I wanted.
forms.py
objectlist = forms.queryset = models.Vehicle.objects.all().order_by('make')
html
<form>
<select class="form-control">
<option value="" selected disabled>Select Vehcile 1</option>
{% for q in form.objectlist %}
{% for b in q.package_set.all %}
<option value="">
{{ q.make }} {{ q.model }} {{ b.name }}
</option>
{% endfor %}
{% endfor %}
</select>
</form>
Using the nested for loop was the only way I could get the attributes of a related model to display inside the same select dropdown. The model Package has a foreign key called 'make_model' that refers to the model Vehicle. I wasn't able to call 'make_model__make' to display related vehicle names with the package in the dropdown list.
I'll leave my mistake up for anyone else having a similar issue to see what not to do in this situation along with what worked for me in the end.

How can I get a Django view.py to request a selected posts information such as primary key?

I have a Django project with an HTML file that lists all of the CSV files that have been uploaded to my Postgresql database and when you click on the CSV of interest a new page is rendered with the CSV model's basic information (name/time submitted).
This is the First Page:
{% for csv in Data_List %}
<button class="btn btn-primary" style = "font-size:1.2em;" >{{csv.name}}</button>
<br><br>
{% endfor %}
This is the second page:
<p>{{request.user.username}}'s Note
<h6>{{worklog.name}}
<br>
{{worklog.date}}
<br>
{{worklog.notes|safe}}
<br>
{{worklog.mycsv|safe}}
</h6>
</p>
However, my goal is that when you click the button a python VIEW will be passed (or just retrieve) the chosen posts primary key (or other information). I want to do this so the view can ask the database for the actual CSV and do some work.
How can I get a view.py to request a selected posts information such as primary key?
Thanks and Happy Coding
#The url
url(r'^anote/(?P<pk>\d+)$', views.A_Note, name = 'anote'),
#The view
def A_Note(request, pk):
#the rest of code here
return render(request, "some.html", {"thing":thing, "pk":pk, "etc":etc})
I learned that sharp brackets <> in a url passes the value through to the view where it can then be accessed as an argument when defining the view. From there it can easily be used in the code.
Thanks!

Categories

Resources