How to pass selection from Django template to Class view - django

I am struggling with something that should be routine for me by now but I have a mental block.
I have a model that stores Country names and a slug version of the name.
Eg. "United States", "united-states"
I want to display the country names in a template for selection, then return the selected country's slug value to the Class based View which will then obtain the data. The list of countries can be links or dropdown - whatever. But I need to obtain the selected value in the View. Here is a simplified version:
Template
{% extends 'base.html' %}
{% block content %}
<form method="POST">
{% for country in object_list %}
{{ country.pretty_name }}</br>
{% endfor %}
</form>
{% endblock content %}
View
class CountryView(TemplateView):
country_name = THE SLUG
country_obj = Country(country_name)
country_obj.build_country_dictionary()
country_obj.display()
So I think I need one of the get methods to access this but I cannot work it out. Thanks for any help.

The "structured way"
Have a look at FormView, where you define your form class (which you also need to create, depends on your situation can be a model form as well). The rest is pretty much handled by the view.
https://ccbv.co.uk/projects/Django/4.0/django.views.generic.edit/FormView/
PSEUDO code
class MyForm(ModelForm):
model = YourModel
class MyFormView(FormView):
form_class = MyForm
# depends on what you want to do, you can overwrite form_valid to do your logic
The quickest way
PSEUDO code
{% extends 'base.html' %}
{% block content %}
<form method="POST">
{% csrf_token %}
<select name="selection">
{% for country in object_list %}
<option value="{{ country.slug_name }}">{{ country.pretty_name }}</option>
{% endfor %}
</select>
<input type="submit">Submit</input>
</form>
{% endblock content %}
class CountryView(TemplateView):
def post(self, request, *args, **kwargs):
selection = request.POST.get('selection')

Related

Not showing the Form in html

This is my model
class showroom(models.Model):
serialno=models.IntegerField(db_index=True,primary_key=True)
carname=models.CharField(max_length=50)
carmodel=models.CharField(max_length=50)
price=models.IntegerField()
rating=models.IntegerField(validators=[MinValueValidator(1),MaxValueValidator(5)])
This is my forms.py
class RegisterForm(ModelForm):
class Meta:
model = showroom
fields =("__all__")
views.py
class carform(CreateView):
model = showroom
form_class=RegisterForm
template_name = "carbrand/carregister.html"
context_object_name='registerform'
html page
{% block content %}
{{registerform}}
{% endblock content %}
It's just showing a blank screen. I have imported all the necessary classes and views. It will make this too long for you so i removed it.can anyone please tell me if anything wrong in my view/form.
The name of the form is not determined by the context_object_name. In fact in a CreateView, the context_object_name does not change anything since no object is passed.
A FormView (and its descendants), always pass the form that is constructed as form to the context. You thus should render this with:
{% block content %}
<form method="post" action="{% url 'some-view-name' %}">
{% csrf_token %}
{{ form }}
<button type="submit">submit</button>
</form>
{% endblock content %}

How to filter a ManyToMany field from django template?

I have a model named Universities in which there is a ManyToMany field named bookmarks associated with User model. In template file, I have looped through all the universities {% for university in universities %} and I am trying to show a bookmark icon based on the logged in user has bookmarked that specific university or not. However, it seems like I can not filter the query in template directly. How do I do that?
Don't name your models with plural names. "universities" should be "university" because every instance of the model represents a single university.
You can access one to many and many to many relationships in the templates. How you do that depends if you have assigned a related_name to the relationship.
Let me show you an example:
class University(models.Model):
name = models.CharField(max_length=50)
bookmarks = models.ManyToManyField(Bookmark, on_delete="models.CASCADE", related_name="universities")
Then you pass a list of all university models to the template:
class MyView(View):
def get(self, request):
context = { 'universities' : University.objects.all() }
return render(request, "mytemplate.html", context)
And finally you access all that you need from the template. This part is slightly tricky but not too much.
{% for university in universities %}
{% for bookmark in university.bookmarks.all %}
{{ bookmark }}
{% endfor %}
{% endfor %}
If you were to instead pass to the template a list of Bookmark instances, then you would have used the related_name stated in our example.
So like this:
{% for bookmark in bookmarks %}
{% for university in bookmark.universities.all %}
{{ university }}
{% endfor %}
{% endfor %}
If you didn't specify a related_name, then you can access the same data using the _set convention:
{% for bookmark in bookmarks %}
{% for university in bookmark.university_set.all %}
{{ university }}
{% endfor %}
{% endfor %}

Using Checkbox in ListView

I'm trying to make Todo app. I want to make checkbox next to task, so when you select it, the task is set to done. The problem is, I can't really know how to change value of my BooleanField in Task Model. There are plenty of posts like this, but they are usually using functions inside views.py or use forms, but I can't relate do my form in ListView.
views.py
class TodolistView(LoginRequiredMixin, ListView):
model = Todolist
template_name = 'todolist.html'
def get_queryset(self):
return Todolist.objects.all().filter(user=self.request.user)
def get(self, request, *args, **kwargs):
todolist_objects = Todolist.objects.all()
return render(request, 'todolist.html', {'todolist_objects': todolist_objects})
todolist.html
{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% block content %}
<p>Add new task</p>
{% for todo in todolist_objects %}
<div>
<form action="" method="post">
<li> {{ todo }} see details</l>
</form>
</div>
{% endfor %}
{% endblock %}

Django templates iterate model fields with indices

I have the follow model:
class UserProfile(...):
...
photo1 = models.URLField()
photo2 = models.URLField()
photo3 = models.URLField()
photo4 = models.URLField()
photo5 = models.URLField()
And in the Create/Update template, I have to write five copies of the following div for file1 to file5:
<div>
Photo 1:
{% if userProfileForm.instance.file1 %}
<a href="{{ userProfileForm.instance.file1 }}" target=_blank>View</a>
{% endif %}
<input type=file name=file1>
{% if userProfileForm.instance.file1 %}
Delete
{% endif %}
</div>
Is there a way to iterate field file<i>?
{% for i in '12345' %}
<div>
Photo {{ forloop.counter }}:
...
</div>
{% endfor %}
in django you have _meta API. So I think this solves your problem if you use get_fields method (and maybe you will filter desired fields out).
hope it helps.
update with example
let me show how you should solve your problem:
desired_fields = []
for field in UserProfile._meta.get_fields()
if "photo" in field.name:
desired_fields.append(field.name)
context.update(fields=desired_fields) # pass it in the context
at this point you have your desired fields which should be used with for loop in the template. And one more thing, you would need to add some template tag to get real field from string representation:
# custom template tag
def from_string_to_field(instance, field_str):
return getattr(instance, field_str, None)
and in the template code will look like this
{% for field in fields %}
{{userProfileForm.instance|from_string_to_field:"field"}}
{% endfor %}

How to change dynamically "Site administration" string in Django's admin?

I want to replace dynamically "Site administration" by a custom string in my admin.
I've already overridden "base.html" for some other purpose, but now I need to pass a variable to this template to replace {{ title }} in
{% block content_title %}{% if title %}<h1>{{ title }}</h1>{% endif %}{% endblock %}
I've seen from this question that a variable can be passed to the change list template by overriding changelist_view and adding an extra_context in the model admin, but how can I pass an extra context to the "main" page of the admin"?
The index() view is inside django.contrib.admin.site.AdminSite class and supports extra_context as well, you could override it, something like:
def index(self, *args, **kwargs):
return admin.site.__class__.index(self, extra_context={'title':'customized title'}, *args, **kwargs)
admin.site.index = index.__get__(admin.site, admin.site.__class__)
Also you could override AdminSite directly and use customized_site instead of admin.site:
class CustomizedAdminSite(AdminSite):
def index(self, *args, **kwargs):
return super(CustomizedAdminSite, self).index(extra_context={...}, *args, **kwargs)
customized_site = CustomizedAdminSite()
If you want to have title in all Admin pages, better to use context processor or customize some template tag if you can.
You override the "admin/base_site.html" template:
{% extends "admin/base.html" %}
{% load i18n %}
{% block title %} {{ title }} | {% trans 'YOUR TITLE HERE' %} {% endblock %}
{% block branding %}
<h1 id="site-name">{% trans 'STUFF HERE PERHAPS' %} </h1>
{% endblock %}
{% block nav-global %}
{% endblock %}