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
Related
In my code I'm using a class CreateView with a ListView. I'm also using a for loop to show all the possible dates available (that are created in the StaffDuty models). My user should be able to just book a single date.
My problem is that I'm not able to save a single appointment, I have to compile all the form showed in my list to be able to submit. How can I solve this?
models.py
class UserAppointment(models.Model):
user = models.ForeignKey(UserProfile, on_delete=models.CASCADE)
staff = models.ForeignKey(StaffDuty, on_delete=models.CASCADE)
event = models.ForeignKey(Event, on_delete=models.CASCADE)
event_name = models.CharField(max_length=255)
date_appointment = models.DateField(null=True)
def __str__(self):
return self.event.name | str(self.staff.date_work)
def get_absolute_url(self):
return reverse('home')
views.py
class UserAppointmentAddView(CreateView):
model = UserAppointment
form_class = UserAppointmentForm
template_name = "reservation.html"
def form_valid(self, form):
form.instance.user = self.request.user.userinformation
def get_context_data(self, **kwargs):
kwargs['object_list'] = StaffDuty.objects.order_by('id')
return super(UserAppointmentAddView, self).get_context_data(**kwargs)
html
<div class="container">
<form method="post">
{% csrf_token %}
{% for appointment in object_list %}
<span>{{ form.staff }}</span>
<span>{{ form.event }}</span>
<span>{{ form.morning_hour }}</span>
<span>{{ form.afternoon_hour }}</span>
<div class="primary-btn">
<input type="submit" value="submit" class="btn btn-primary">
</div>
</div>
{% endfor %}
If I understand right, you are generating the same form for each appointment/ model instance, which won't work. What gets POSTed back does not identify which appointment object it refers to. That could be fixed with a hidden object_id field ... which is part of what model formsets do for you. Or you might put it into the value of your multiple submit buttons and pull it out of request.POST if you are happy to handle validation yourself.
The pure-Django solution is to generate a model formset. When it is submitted you would process the form that has changed and ignore the rest. (It will in fact give you lists of changed and unchanged objects).
The other approach would be using JavaScript to populate one form (possibly with hidden fields) when the user clicks on values in a table. Or no form in the template, just POST from JavaScript and validate what comes back through a form (or otherwise)
Formsets and model formsets look fearsomely complicated the first time you try to use them. They aren't really, but the first one you code may present you with a bit of a steep learning curve. It's easier if you can find something working that somebody else has already written, and adapt it.
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!
I'm learning Django as I go right now, but I'm trying to do something more dynamically.
Basically I've got multiple models defined as so:
class Group(models.Model):
name = models.CharField(max_length=255)
type = models.CharField(max_length=255) # Ignore this, is used somewhere else
class User(models.Model):
name = models.CharField(max_length=255)
group = models.ForeignKey(Group, verbose_name='group', on_delete=models.CASCADE)
(there are more models than these two)
I feel like writing a different view for each of these models isn't really a Django way to do it, but I'm struggling to find a different way. Basically I want to automatically create forms depending on what fields the model has.
So on /department/ there should be an text input for name and type.
But on /user/ there should be an text input for name and an selection for group.
All that rather in the same template. If possible ofcourse.
If it isn't possible, what's the best way to do this? Since creating a different template for each model doesn't seem right.
EDIT:
I've now got my CreateView working (very basic still). Now I want to create a ListView in a similar fashion. I've seen this issue, Iterate over model instance field names and values in template but it wasn't able to help me out...
forms.py
class ModelCreate(CreateView):
fields = '__all__'
template_name = 'polls/models/model_create.html'
def get_form(self, form_class=None):
try:
self.model = apps.get_model('polls', self.kwargs['model'])
except LookupError:
raise Http404('%s is not a valid model.' % self.kwargs['model'])
return super(ModelCreate, self).get_form(form_class)
model_create.html
{% extends 'polls/core.html' %}
{% block content %}
<form method="post">
{% csrf_token %}
{{ form }}
<input type="submit" value="Submit">
</form>
{% endblock %}
Would it be possible to create a ListView in a similar fashion? So that I get field names and values dynamically (bit like {{ form }})
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.
I have two models (Item and Album).
Album has a foreign key pointing to Item
like this
class Item(models.Model):
name = models.CharField(max_length=50)
price = models.IntegerField()
and
class Album(models.Model):
photo = ImageField(upload_to=item_directory_path)
caption = models.CharField(max_length=100, blank=True)
item = models.ForeignKey(Item, on_delete=models.CASCADE)
default = models.BooleanField(default=True)
In my template
{% for item in item_tags %}
<div class="item-dock">
<a href="{{item.name}}">
<img src="{{item.album_set.photo.filter(default=True)}}" class="img-responsive">
<p class="item-name text-center">{{item.name|capfirst}}</p>
</a>
Now the real issue is. Given that querying on a related model will always return a queryset. How can I retrieve a single object(in this case, a single photo from this queryset where the "default=True") from the Album model for an Item in my template.
I know about queryset and related manager!
Any help, suggestions will be much appreciated
Just query the first element if that would suffice.
# something like this in your template
{% item.album_set.first.photo %}
You can use a custom template filter for this:
Details about creating and using custom template tags and filters can be found here:
https://docs.djangoproject.com/en/1.11/howto/custom-template-tags/
from django import template
register = template.Library()
def default_image(queryset):
return queryset.get(default=True).photo.url
register.filter('default_image', default_image)
You can use it in the template like this:
{{ item.album_set|default_image }}
Remember you need to {% load your_custom_template_tags %} before using the the filter