Display the content of many to many fields in django template - django

I want to know how it is possible to display many-to-many relations in the django template. I posted my views.py and my models.py. I tried to find the solution by myself but I didn't really understand how to solve the problem :/
models.py
class topic(models.Model):
topic = models.TextField(verbose_name = 'Thema')
learningObjectivesTopic = models.ManyToManyField(learningObjective, verbose_name = "Lernziel")
class learningObjective(models.Model):
learningObjectives = models.TextField(verbose_name = 'Lernziel')
views.py
#login_required(login_url='login')
def themen(request):
return render(request, 'themen.html')
#login_required(login_url='login')
def create_themen(request):
neueThemen=topic(topic=request.POST['thema'])
neueThemen.save()
neueThemen_Lernziel=learningObjective(learningObjectives=request.POST['Lernziel'])
neueThemen_Lernziel.save()
neueThemen.learningObjectivesTopic.add(neueThemen_Lernziel)
return render(request, 'themen.html', {'thema': topic.objects.all(), 'lernziel': learningObjective.objects.all()})
and my unfinished template "themen.html"
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<form action="{% url 'create_themen' %}" method="post">
{% csrf_token %}
<br>Hallo Benutzer: {{ user.username }}</br>
<br>Thema: <textarea name="thema" rows="3" cols="45"></textarea></br>
<br>Lernziel: <textarea name="Lernziel" rows="3" cols="45"></textarea></br>
<input type="submit" value="Absenden" />
<br>Aktuelle Themen:</br>
</form>
{% for thema_ in thema %}
{{ thema_.topic }}<br/>
{{ thema_.
{% endfor %}
</body>
</html>

Given the thema object, if you want to display the many to many fields,
{% for topic in thema %}
{{topic.topic}}
{% for lo in topic.learningObjectivesTopic.all %}
{{lo.learningObjectivesTopic}}
{% endfor %}
{% endfor %}

Related

BootstrapError: Parameter "form" should contain a valid Django Form

I keep getting the above error (in the title) for my DeleteView.
Strangely my UpdateView, UpdateObject form and update_object template are identical to my DeleteView, DeleteObject form and delete_object template respectively. I'm not sure why bootstrap is giving me an error for this form and not my update form?
Here are the files:
forms.py:
from django import forms
from . import models
from django.forms import ModelForm
class CreateBouquetForm(ModelForm):
class Meta:
model = models.Bouquet
exclude = ('price',)
def __init__(self,*args,**kwargs):
super().__init__(*args,**kwargs)
class UpdateBouquetForm(ModelForm):
class Meta:
model = models.Bouquet
exclude = ('price',)
class DeleteBouquetForm(ModelForm):
class Meta:
model = models.Bouquet
exclude = ('price',)
`
views.py:
class UpdateBouquet(UpdateView):
model = models.Bouquet
form_class = forms.UpdateBouquetForm
template_name = 'products/update_bouquet.html'
success_url = reverse_lazy('products:shop')
def form_valid(self,form):
self.object = form.save(commit=False)
result = 0
for flower in self.object.flower.all():
result += flower.price
self.object.price = result
self.object.save()
return super().form_valid(form)
class DeleteBouquet(DeleteView):
model = models.Bouquet
form_class = forms.DeleteBouquetForm
template_name = 'products/delete_bouquet.html'
success_url = reverse_lazy('products:shop')
products/update_bouquet.html:
{% extends 'site_base.html' %}
{% load bootstrap3 %}
{% block content_block %}
<form method="post">
{% csrf_token %}
{% bootstrap_form form %}
<input type="submit" class="btn btn-outline-success" value="Save bouquet and continue shopping">
</form>
<h6>Back to bouquet</h6>
{% endblock %}
products/delete_bouquet.html:
{% extends 'site_base.html' %}
{% load bootstrap3 %}
{% block content_block %}
<h5>Are you sure you want to delete your bouquet?</h5>
<form method="POST">
{% csrf_token %}
{% bootstrap_form form %}
<input type="submit" class="btn btn-outline-success" value="Delete">
</form>
<h6><a class="btn btn-outline-danger" href="{% url 'products:detail_bouquet' pk=bouquet.pk %}">Cancel</a></h6>
{% endblock %}
urls.py:
url(r'^bouquet/(?P<pk>\d+)/update/$',views.UpdateBouquet.as_view(),name="update_bouquet"),
url(r'^bouquet/(?P<pk>\d+)/delete/$',views.DeleteBouquet.as_view(),name="delete_bouquet"),
Here's what the error page says:
Error during template rendering
In template C:\Users\joann\Desktop\Flowers_Storefront\storefront\templates\site_base.html, error at line 8
Parameter "form" should contain a valid Django Form.
1 <!DOCTYPE html>
2 {% load static %}
3 {% load bootstrap3 %}
4 <html lang="en" dir="ltr">
5 <head>
6 <meta charset="utf-8">
7 <title></title>
8 <link href="https://cdn.jsdelivr.net/**npm/bootstrap#5.0.0-beta1/dist/css/boo**tstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous">
9 <link rel="stylesheet" href="{% static "/css/css_master.css" %}">
10 <link rel="preconnect" href="https://fonts.gstatic.com">
11 class="container-fluid">
...etc....
Thanks in advance if you can help!
DeleteView does not do any form handling and so does not add a "form" key to the context. Remove form_class from your view and remove the bootstrap_form tag from your template
class DeleteBouquet(DeleteView):
model = models.Bouquet
template_name = 'products/delete_bouquet.html'
success_url = reverse_lazy('products:shop')
{% extends 'site_base.html' %}
{% block content_block %}
<h5>Are you sure you want to delete your bouquet?</h5>
<form method="POST">
{% csrf_token %}
<input type="submit" class="btn btn-outline-success" value="Delete">
</form>
<h6><a class="btn btn-outline-danger" href="{% url 'products:detail_bouquet' pk=bouquet.pk %}">Cancel</a></h6>
{% endblock %}

Why is my Update URL link kicking me to the CreateNew html view

so this is a tag on from my previous stackoverflow post:
Django updateView saving another instance instead of updating
and i think i've narrowed it down. Whats happening is that when i click on the link to update my view, it sends me to the "create new" page. my problem is that I cant figure out why its doing that.
Any and all help is appreciated.
here is the code:
question_form.html
{% extends "base.html" %}
{% load bootstrap3 %}
{% block content %}
<h4>Create New Question</h4>
<form method="POST" action="{% url 'questions:create' %}" id="questionForm">
{% csrf_token %}
{% bootstrap_form form %}
<input type="submit" value="Post" class="btn btn-primary btn-large">
</form>
{% endblock %}
question_update.html
{% extends "base.html" %}
{% load bootstrap3 %}
{% block content %}
<h4>Update Question</h4>
<form method="POST" action="{% url 'questions:update' pk=question.pk %}" id="questionForm">
{% csrf_token %}
{% bootstrap_form form %}
<input type="submit" value="Update" class="btn btn-primary btn-large">
</form>
{% endblock %}
question_detail.html
{% block content %}
this is the question detail view
<h3>{{ question.question_html|safe }}</h3>
<h3>{{ question.answer_html|safe }}</h3>
Update Question
{% endblock %}
urls.py
url(r'new/$', views.CreateQuestion.as_view(), name='create'),
url(r'questionupdate/(?P<pk>\d+)/$', views.QuestionUpdate.as_view(), name='update'),
url(r'questiondetail/(?P<pk>\d+)/$', views.QuestionDetail.as_view(), name='single'),
views.py
class CreateQuestion(generic.CreateView):
model = models.Question
form = QuestionForm
fields = ('question', 'answer')
success_url = reverse_lazy('questions:all')
def form_valid(self, form):
self.object = form.save(commit=False)
self.object.user = self.request.user
self.object.save()
return super().form_valid(form)
class QuestionDetail(generic.DetailView):
model = models.Question
class QuestionUpdate(generic.UpdateView):
model = models.Question
form_class = QuestionForm
context_object_name = 'question'
From your urls.py the name of update view is only update. You can try only update tag in html file Like
{% extends "base.html" %}
{% load bootstrap3 %}
{% block content %}
<h4>Update Question</h4>
<form method="POST" action="{% url 'update' pk=question.pk %}" id="questionForm">
{% csrf_token %}
{% bootstrap_form form %}
<input type="submit" value="Update" class="btn btn-primary btn-large">
</form>
{% endblock %}
I've figured it out. it turns out I was missing the template name part under my Create and update views which directs them to their own html templates:
class CreateQuestion(generic.CreateView):
model = models.Question
form_class = QuestionForm
fields = ('question', 'answer')
template_name = "questions/question_form_create.html"
success_url = reverse_lazy('questions:all')
class QuestionUpdate(generic.UpdateView):
model = models.Question
form_class = QuestionForm
template_name = "questions/question_form_update.html"

How do I style my user registration form using Bootstrap in DJango?

So I have the following user registration form which I want to style. My forms.py look something like this. :
from django.contrib.auth.models import User
from django import forms
class UserForm(forms.ModelForm):
password = forms.CharField(widget=forms.PasswordInput())
class Meta:
model = User
fields = ['username','email','password']
Now this is my views.py:
class UserFormView(View):
form_class =UserForm
template_name = 'visit/registration/register.html'
def get(self,request):
form = self.form_class(None)
return render(request,self.template_name,{'form':form})
def post(self, request):
form = self.form_class(request.POST)
if form.is_valid():
user =form.save(commit=False)
username = form.cleaned_data['username']
password = form.cleaned_data['password']
user.set_password(password)
user.save()
user = authenticate(username=username, password=password)
if user is not None:
if user.is_active:
login(request,user)
return redirect('visit:index')
return render(request, 'visit/registration/register.html', {'form': form})
Now What I am getting a bit confused in HTML, since there is only one line which passes all these fields in the page together. So how M I supposed to style these fields separately.
{% extends 'visit/base.html'%}
{%block content%}
<!DOCTYPE html>
<html>
{% load staticfiles %}
<link rel = "stylesheet" type = "text/css" href = "{% static "visit/registration.css"%}">
<head>
<title></title>
</head>
<body>
<form method="POST" class = "sign-up-form">
{% csrf_token %} {{ form.as_p }}
<button type="submit">Submit</button>
</form>
</body>
</html>
{%endblock%}
You have multiple options, each one with its pros and cons:
1. Add custom css classes within forms.py
To use the simplicity of {{ form.as_p }} approach you could manually add classes to all your forms fields, e.g.:
class UserForm(forms.ModelForm):
password = forms.CharField(widget=forms.PasswordInput(
attrs={'class' : 'your-custom-class'})
)
Note that it could be a challenge to render the form to be perfectly aligned with Bootstrap's style.
2. Render the form manually
You could write your form by hand within your template, e.g.:
<div class="form-group">
<label for="{{ form.password.id_for_label }}">
{% trans 'Password' %}
</label>
<input type="text" id="{{ form.password.id_for_label }}"
name="{{ form.password.html_name }}"
{% if form.password.field.required %}required{% endif %}
class="form-control{% if form.password.errors %} is-invalid{% endif %}"
value="{% if form.password.value %}{{ form.password.value }}{% endif %}">
{% if form.password.help_text %}
<small class="text-muted">
{{ form.password.help_text }}
</small>
{% endif %}
{% for err in form.password.errors %}
<span class="invalid-feedback">{{ err }}</span>
{% endfor %}
</div>
More info on rendering form fields manually can be found here.
The above snippet will use most of the functionality existing in the default django form renders methods, but on the other hand forces you to write a lot of boilerplate code which is harden to maintain in the long run.
3. Use 3rd party app as a mix of the first two options
You could use custom app to handle the rendering of the forms, a good example would be django-crispy-forms.
You can simply use django-bootstrap
This will automatically render the bootstrap form for you.
{% extends 'visit/base.html'%}
{% load bootstrap3 %}
{%block content%}
<!DOCTYPE html>
<html>
{% load staticfiles %}
<link rel = "stylesheet" type = "text/css" href = "{% static "visit/registration.css"%}">
<head>
<title></title>
</head>
<body>
<form method="POST" class = "sign-up-form">
{% csrf_token %}
{% bootstrap_form form %}
<button type="submit">Submit</button>
</form>
</body>
</html>
{%endblock%}

How to GET data by search word Django

I have problem getting the data to the home page.
I would like to filter out all the books based on Genre. I'm following the
MDN site for this.
index.html
{% extends "base_generic.html" %}
{% block content %}
<h1>Local Library Home</h1>
<p>Welcome to <em>Local Library</em>, a very basic Django website.</p>
<h2>Dynamic content</h2>
<form action="" method="get">
<input type="text" name="genre" placeholder="Search">
<input type="submit" value="Search">
</form>
{% endblock %}
urls.py
urlpatterns = [
url(r'^$', views.index, name='index'),
url(r'^books/$', views.BookListView.as_view(), name='books'),
url(r'^(?P<string>[-\w]+)$', views.GenreListView.as_view(), name='index'),
]
GenreListView class
class GenreListView(generic.ListView):
model = Book
def get(request, string):
try:
book = Book.objects.all().filter(genre=string)
except Book.DoesNotExist:
raise Http404("Book does not exist")
return render(
request,
'index.html',
context={'book': book,}
)
I can't figure out what I'm missing or what else I have to do to get all the date based on genre?
EDIT:
whole index.html
{% extends "base_generic.html" %}
{% block content %}
<h1> Book List </h1>
<form action="" method="get">
<input type="text" name="genre" placeholder="Search">
<input type="submit" value="Search">
</form>
{% if book_list %}
<ul>
{% for book in book_list %}
<li>
{{ book.title }} ({{ book.author }})
</li>
{% endfor %}
</ul>
{% else %}
<p>There are no books in the library</p>
{% endif %}
{% endblock %}
You should override get_queryset, No need to rewrite get
class GenreListView(generic.ListView):
model = Book
template_name = 'index.html'
def get_queryset(self):
books = Book.objects.all()
query = self.request.GET.get('genre', None)
if query:
return books.filter(genre=query)
return books
The exception Book.DoesNotExist will never
occur if you filter() queryset. it will always return a empty queryset in case of no object found

add text field on button click and pack into jsonfield with django

I have a jsonfield in my django project and i was wondering how i can have button to add textfields
for example:
i have a list of steps and i want to click a button to add a step (simillarly to adding attachments in email) and then i want to pack all of these into a jsonfield
so my two questions are
how do i add a text field via button and how do i pack the text fields together into a jsonfield
thanks a lot no code is included because i don't think it is necessary
katie
edit: added code:
here is thew view where I create a new recipe object for my cookbook. this is also the view that handles the form that would contain the jsonfields:
def createrecipe(request):
if request.method == 'POST':
form = RecipeForm(request.POST)
if form.is_valid():
form = RecipeForm(initial = {'original_cookbook' : request.user.cookbooks.all()[0]})
form = form.save()
t = loader.get_template('cookbook/create_form.html')
c = RequestContext(request, {
'form': form,
})
data = {
'replace': True,
'form': t.render(c),
'success': True,
}
json = simplejson.dumps(data)
return HttpResponse(json, mimetype='text/plain')
else:
form = RecipeForm(request.POST)
t = loader.get_template('cookbook/create_form.html')
c = RequestContext(request, {
'form':form,
})
data ={
'form': t.render(c),
'success': False,
}
json = simplejson.dumps(data)
return HttpResponse(json, mimetype='text/plain')
here is the model.py for my recipe (where the jsonfields are located):
class Recipe(models.Model):
def __unicode__(self):
return self.name
original_cookbook = models.ForeignKey(Cookbook)
name = models.CharField(max_length=200)
author = models.CharField(max_length= 100)
picture = models.ImageField(upload_to = 'Downloads', blank=True)
pub_date = models.DateTimeField('date published', auto_now_add=True, blank=True)
type = models.CharField(max_length = 2, choices=TYPE_CHOICES)
ingredients = JSONField()
steps = JSONField()
prep_time = models.IntegerField()
here is my account view:
def account(request):
user = request.user
if request.user.is_authenticated():
cookbooks = user.cookbooks
if cookbooks.all().exists():
cookbook = cookbooks.all()[0]
form = RecipeForm(initial = {'original_cookbook' : request.user.cookbooks.all()[0]})
recipe_list = cookbook.recipes.all()
else:
raise Http404
else:
return HttpResponseRedirect('/accounts/login')
t = loader.get_template('cookbook/account.html')
c = RequestContext(request, {
'form': form,
'recipe_list': recipe_list
})
return HttpResponse(t.render(c))
this is the template for the form:
create_form.html the action of the form points to the create recipe view
<body>
<form action="{% url cookbook.views.createrecipe %}" method="POST" name="recipeform" id="createrecipeform">
<table>
{% csrf_token %}
{{ form.as_table }}
</table>
<p><input type="submit" value="Submit"></p>
</form>
<form class="task-form" action="." method="POST">
<button class=".task-add-button" value="Add Task">
{% csrf_token %}
{{ TaskFormSet.as_p }}
</form>
</body>
here is the template for the account page that handles the create_recipe page...
account.html
{% extends "cookbook/base.html" %}
{% load pagination_tags %}
{% load comments %}
<h1>{{ user }}'s Cookbook</h1>
<ul>
{% block nav-cookbooks %}
<li><a class="nav-inactive" href="/cookbooks/">Cookbooks</a></li>
{% endblock %}
{% block nav-account %}
<li><a class="nav-active" href="/account/">My Cookbook</a></li>
{% endblock %}
</ul>
{% block content %}
{% autopaginate recipe_list 6 %}
<div id="recipe_cont">
{% for recipe in recipe_list %}
<div class="recipe">
<div class="button">
<img src="{{ STATIC_URL }}chicknbraw.jpg" alt="" height="70" width="70" style="display:inline;" />
<h4>{{ recipe.name }}</h4>
</div>
<h5>{{ recipe.author }}</h5>
<h5>Prep Time: {{ recipe.prep_time }} minutes</h5>
<h6>Add Recipe
Remove Recipe</h6>
</div>
{% endfor %}
</div>
<div id="popupContact" class="popup">
<a id="popupContactClose" style="cursor:pointer;float:right;">x</a>
<p id="contactArea">
<h1 style="text-align:center">Create New Recipe</h1>
{% include 'cookbook/create_form.html' %}
</p>
</div>
<div id="backgroundPopup">
</div>
<div id="col2-footer">
{% paginate %}
<p id="recipe_order_text"> order by: abc|date
</div>
{% endblock %}
{% block footer %}
<a class="create" style="cursor:pointer" >Create New Recipe</a>
{% endblock %}
base.html:
{% load i18n %}
{% block doctype %}<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
{% endblock %}
{% block head %}
<head>
<title>{% block title %}Recipeek{% endblock %}</title>
<script type="text/javascript">
$(document).ready(function(){
var form = $('form#createrecipeform');
form.submit(function(e) {
e.preventDefault();
console.log('ajax form submission function called successfully.');
//form = $(this);
console.log(form)
var serialized_form = form.serialize();
$.ajax({ type: "POST", 
url: $(this).attr('action'),
data: serialized_form, 
success: (function(data) { 
console.log('ajax success function called successfully.');
data = $.parseJSON(data);
if (data.success) {
console.log('success');
var newForm = data.form;
form.replaceWith(newForm);
} else {
console.log('failure');
var newForm = data.form;
form.replaceWith(newForm);
}
})
});
return false;
});
});
</script>
</head>
{% endblock %}
{% block body %}
<body>
{% block header %}
<div id="header"></div>
{% endblock %}
<div id="left_pane">
<div id="left_pane-container">
<div id="logo"><img src= "/static/recipeek_logo.png" style="padding-left:10px;" /></div>
<div id="left_pane-items">
<div id="nav_out">
<ul id="nav_outlist">
<li>about us</li>
<li>contact</li>
<li>glossary</li>
</ul>
</div><!--nav_out-->
</div><!--left_pane-items-->
</div><!--left_pane-container-->
</div><!--left_pane-->
{% block container %}
<div id="container">
<div id="container_header">
<div id="horz_nav">
<ol>
<li id="cookbook_link">{% block nav-cookbooks %}Cookbooks {% endblock %}</li>
<li id="account_link">{% block nav-account %}My Cookbook{% endblock %}</li>
</ol>
</div>
<div id="container_header-items">
{% trans "Home" %} |
{% if user.is_authenticated %}
{{ user.username }}
({% trans "Log out" %} |
{% trans "Change password" %})
<form action="/search/" method="get">
<input type="text" name="q" id="id_q" value="Search" onfocus="if(this.value==this.defaultValue)this.value='';" onblur="if(this.value=='')this.value=this.defaultValue;"/>
</form>
{% else %}
{% trans "Log in" %}
{% endif %}
</div><!--header-items-->
</div><!--header-->
<div id="col2">
<div id="col2-header"></div>
{% block content %}{% endblock %}
</div>
<div id="footer">
{% block footer %}
{% endblock %}
</div>
</div>
{% endblock %}
</body>
{% endblock %}
</html>
i think that is all of the relevant code.
i think i should also mention I am using ajax to submit the form - im not sure this will make any difference in how to implement this idea. thanks again for the help tom :)
Well katie, what you're going to want to do is set up some javascript on the frontend.
<form class="task-form" action="." method="POST">
<button class=".task-add-button" value="Add Task">
{{ TaskFormSet.as_p }}
</form>
<script>
var $form = $('.task-form')
, $button = $form.find('.task-add-button')
, template = '{{ TaskFormSet.empty_form.as_p }}'
, num_formsets = $form.find('input[name=TOTAL_FORMS]').val();
$button.on('click', function(){
var formset_html = template.replace('__prefix__', 'form-'+(++num_formsets);
$(formset_html).appendTo($form); // Creates new input
return false;
});
</script>
Then you will want a form that will be able to process this list.
https://docs.djangoproject.com/en/dev/topics/forms/formsets/
from django.forms.formsets import formset_factory
class TaskForm(Form):
title = CharField()
... any number of extra fields
TaskFormSet = formset_factory(TaskForm, can_order=True, can_delete=True, extra=1)
# In your view
instance = TaskModel.objects.get(...)
tasks_formset = TaskFormSet(request.POST, initial=instance.tasks_json)
context['TaskFormSet'] = tasks_formset
if request.method == 'POST' and tasks_formset.is_valid():
instance.tasks_json = [task.cleaned_data for task in tasks_formset]
instance.save()
I Hope this helps you, and welcome to StackOverflow!