My for loop does not work as expected - Data does not show up in my django template - django

I am trying to use a for loop in my Django template to show the data stored in the models of a table but for some reason , the data does not show up in the template.
Views.py
def add_part(request):
parts = Parts.objects.all()
context = {
"parts": parts
}
return render(request, 'admintemplate/add_parts_template.html', context)
def add_part_save(request):
if request.method != "POST":
messages.error(request, "Method Not Allowed!")
return redirect('add_part')
else:
part_name = request.POST.get('part_name')
part_type = request.POST.get('part_type')
supplier_id = request.POST.get('suppliers')
suppliers = Suppliers.objects.get(id=supplier_id)
try:
part = Parts(part_name=part_name, part_type=part_type, supplier_id=supplier)
part.save()
messages.success(request, "Part Added Successfully!")
return redirect('add_part')
except:
messages.error(request, "Failed to Add Part!")
return redirect('add_part')
models.py
The parts and the services model are exactly the same with different column names, so I think the functionality for both should be the same.
Suppliers models
class Suppliers(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=20)
Parts model
class Parts(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=20)
part_type = models.CharField(max_length=20)
supplier_id = models.ForeignKey(Suppliers, on_delete=models.CASCADE)
Services model
class Services(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=20)
service_type = models.CharField(max_length=20)
supplier_id = models.ForeignKey(Suppliers, on_delete=models.CASCADE)
Part template
{% extends 'admintemplate/base_template.html' %}
{% block page_title %}
Add Parts
{% endblock page_title %}
{% block main_content %}
{% load static %}
<section class="content">
<div class="container-fluid">
<div class="row">
<div class="col-md-12">
<!-- general form elements -->
<div class="card card-primary">
<div class="card-header">
<h3 class="card-title">Add Parts</h3>
</div>
<!-- /.card-header -->
<!-- form start -->
<form role="form" method="POST" action="{% url 'add_part_save' %}">
{% csrf_token %}
{% comment %} Display Messages {% endcomment %}
{% if messages %}
<div class="form-group">
<div class="col-12">
{% for message in messages %}
{% if message.tags == "error" %}
<div class="alert alert-danger alert-dismissible fade show" role="alert" style="margin-top: 10px;">
{{ message }}
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
{% elif message.tags == "success" %}
<div class="alert alert-success alert-dismissible fade show" role="alert" style="margin-top: 10px;">
{{ message }}
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
{% endif %}
{% endfor %}
</div>
</div>
{% endif %}
<div class="card-body">
<div class="form-group">
<label>Part Name </label>
<input type="text" class="form-control" name="part_name" placeholder="Part Name">
</div>
<div class="form-group">
<label>Part Type </label>
<input type="text" class="form-control" name="part_type" placeholder="Part Type">
</div>
<div class="form-group">
<label>Supplier Name</label>
<select class="form-control" name="suppliers">
{% for supplier in suppliers %}
<option value="{{ supplier.id }}">{{ supplier.name }}</option>
{% endfor %}
</select>
</div>
</div>
<!-- /.card-body -->
<div class="card-footer">
<button type="submit" class="btn btn-primary">Add Part</button>
</div>
</form>
</div>
<!-- /.card -->
</div>
</div>
</div><!-- /.container-fluid -->
</section>
{% endblock main_content %}
Now the services in parts template does not show up at all. There is no choices on the form. But, for the add services template, it does populate. I have no idea why this happens because I have used the exact same code for both templates.

Changing the view to this solved the issue
def add_part(request):
parts = Parts.objects.all()
context = {
"suppliers": suppliers
}
return render(request, 'admintemplate/add_parts_template.html', context)

Related

Problems with a backend part of search line in Django

who can explain me why my SearchView doesn't work. I have some code like this.It doesn't show me any mistakes, but it doesn't work. The page is clear. Seems like it doesn't see the input.
search.html
<div class="justify-content-center mb-3">
<div class="row">
<div class="col-md-8 offset-2">
<form action="{% url 'search' %}" method="get">
<div class="input-group">
<input type="text" name="q" class="form-control" placeholder="Search..." />
<div class="input-group-append">
<button class="btn btn-dark" type="submit" id="button-addon2">Search</button>
</div>
</div>
</form>
</div>
</div>
</div>
search/urls.py
path('search/', SearchView.as_view(), name='search')
search/views.py
class SearchView(ListView):
model = Question
template_name = 'forum/question_list.html'
def get_queryset(self):
query = self.request.GET.get("q")
object_list = Question.objects.filter(
Q(title__icontains=query) | Q(detail__icontains=query)
)
return object_list
forum/question_list.html
{% extends 'main/base.html' %}
{% block content %}
{% for question in object_list %}
<div class="card mb-3">
<div class="card-body">
<h4 class="card-title">{{ question.title }}</h4>
<p class="card-text">{{ question.detail }}</p>
<p>
{{ question.user.username }}
5 answers
10 comments
</p>
</div>
</div>
{% endfor %}
{% endblock %}

How to render error or validation messages to ModelForm in 2022

I've spent several hours researching on the internet, especially the official Django documentation, but still it is not clear to me which is the best option in 2022 (since almost all questions I read on SO are > 6 yo)
and there are diverse opinions on whether crispy forms is better or not.
Is still crispy forms a recommended option?
How can I (and what is the most recommended way to) get the typical validation error messages?
Like: "this field is mandatory" or "this input accepts numbers only"? I've seen some Django pages using those default messages but I don't know how to show them in my ModelForm fields.
Lets say I have the following model:
class Project(models.Model):
project_name = models.CharField(max_length=250, null=False, blank=False)
status = models.CharField(
max_length=250,
null=True,
blank=True,
default=PROJECT_STATUS_DEFAULT,
choices=PROJECT_STATUS,
)
creation_date = models.DateField(max_length=250, null=False, blank=False)
project_code = models.IntegerField(null=True, blank=True)
notes = models.CharField(max_length=250, null=True, blank=True)
And for the Project model I have the following ModelForm:
class CreateNewProjectForm(ModelForm):
creation_date = forms.DateField(widget=forms.DateInput(format = '%d/%m/%Y'), input_formats=settings.DATE_INPUT_FORMATS) #UK Date format
class Meta:
model = Project
fields = '__all__'
The view, when I try to create a new object Project:
def add_new_project(request):
context = {}
if request.method == 'POST':
form = CreateNewProjectForm(request.POST)
if form.is_valid():
form.save()
return redirect('project_page')
else:
print (form.errors)
form = CreateNewProjectForm()
context['form'] = form
return render(request, 'new_project.html', context)
HTML part:
<div class="card h-100">
<div class="card-header project-page-header">
<h3>Create A New Project</h3>
</div>
<div class="card-body px-0 new-project-card-body">
<div class="cardItem">
<div class="row">
<div class="col">
<div class="row">
<div class="tab-pane fade show active" id="general">
<form id="newProjectForm" method="POST" action="new_project">
{% csrf_token %}
<div class="accordion accordion-flush" id="accordionGeneral">
<div class="accordion-item">
<h2 class="accordion-header" id="general-headingOne">
<button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#general-collapseOne" aria-expanded="false" aria-controls="general-collapseOne">
Details
</button>
</h2>
<div id="general-collapseOne" class="accordion-collapse collapse show" aria-labelledby="general-headingOne" data-bs-parent="#accordionGeneral">
<div class="accordion-body">
<div class="row">
<div class="col-5">
<ul class="list-unstyled">
<li class="mt-3">
<div class="row">
<div class="col-sm ph-tabs-field-label">
Project Name
</div>
<div class="col-sm">
<input type="text" name="project_name" class="form-control" aria-label="Project Name">
</div>
</div>
</li>
<li class="mt-3">
<div class="row">
<div class="col-sm ph-tabs-field-label">
Status
</div>
<div class="col-sm">
<select name="status" class="selectpicker show-tick w-100" aria-label="Status">
{% for status in project_status %}
{% if forloop.first %}
<option value="{{ status.id }}" selected>{{ status.text }}</option>
{% else %}
<option value="{{ status.id }}">{{ status.text }}</option>
{% endif %}
{% endfor %}
</select>
</div>
</div>
</li>
<li class="mt-3">
<div class="row">
<div class="col-sm ph-tabs-field-label">
Creation Date
</div>
<div class="col-sm">
<input type="text" name="creation_date" class="form-control">
</div>
</div>
</li>
<li class="mt-3">
<div class="row">
<div class="col-sm ph-tabs-field-label">
Project Code
</div>
<div class="col-sm">
<input type="text" name="project_code" class="form-control">
</div>
</div>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
<div class="accordion-item">
<h2 class="accordion-header" id="general-headingThree">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#general-collapseThree" aria-expanded="false" aria-controls="general-collapseThree">
Note
</button>
</h2>
<div id="general-collapseThree" class="accordion-collapse collapse" aria-labelledby="general-headingThree" data-bs-parent="#accordionGeneral">
<div class="accordion-body"><textarea name="notes" class="form-control" rows="7"></textarea></div>
</div>
</div>
<button type="submit" id="projectEditBtn" form="newProjectForm" class="btn btn-info rounded-0">Save</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
I saw solutions like this, but the problem is that my form fields are spread over different accordions, I can't use something like {% if form.errors %}, I need something more specific for each field.
First update your views like this
def add_new_project(request):
context = {}
if request.method == 'POST':
form = CreateNewProjectForm(request.POST)
if form.is_valid():
form.save()
return redirect('project_page')
else:
print (form.errors)
context['form'] = form
return render(request, 'new_project.html', context)
context['form'] = CreateNewProjectForm()
return render(request, 'new_project.html', context)
You can specify error for each field like this
{% if form.field_name.errors %}
{{ form.field_name.errors }}
{% endif %}

How to filter out Friends of user in search users function Django

I'm trying to filter out the friends of a user and also the current logged in user from a "search_users" function, I've tried using exclude() but keep getting an error I'm not sure whats wrong. I also wanted to add a "add friend" button next to the users, which I think I've done correctly on 'search_users.html.
Error
views.py
#login_required
def search_users(request):
query = request.GET.get('q')
object_list = User.objects.filter(username__icontains=query).exclude(friends=request.user.profile.friends.all())
context ={
'users': object_list
}
return render(request, "users/search_users.html", context)
search_users.html
{% extends "feed/layout.html" %} {% load static %}
{% block searchform %}
<form
class="form-inline my-2 my-lg-0 ml-5"
action="{% url 'search_users' %}"
method="get"
>
<input name="q" type="text" placeholder="Search users.." />
<button class="btn btn-success my-2 my-sm-0 ml-10" type="submit">
Search
</button>
</form>
{% endblock searchform %} {% block content %}
<div class="container">
<div class="row">
<div class="col-md-8">
{% if not users %}
<br /><br />
<h2><i>No such users found!</i></h2>
{% else %}
<div class="card card-signin my-5">
<div class="card-body">
{% for user_p in users %}
<a href="{{ user_p.profile.get_absolute_url }}"
><img
src="{{ user_p.profile.image.url }}"
class="rounded mr-2"
width="40"
height="40"
alt=""
/></a>
<a class="text-dark" href="{{ user_p.profile.get_absolute_url }}"
><b>{{ user_p }}</b></a
>
<small class="float-right">
<a
class="btn btn-primary mr-2"
href="/users/friend-request/send/{{ user_p.username }}"
>Add Friend</a>
</small>
<br/><br />
{% endfor %}
</div>
</div>
{% endif %}
</div>
<div class="col-md-4">
<div class="card card-signin my-5">
<a href="{{ request.user.profile.get_absolute_url }}"
><img
class="card-img-top"
src="{{ request.user.profile.image.url }}"
alt=""
/></a>
<div class="card-body">
<h5 class="card-title text-center">{{ request.user }}</h5>
<h6 class="text-center">
{{ request.user.profile.friends.count }}
<p class="text-muted">Friends</p>
</h6>
<p class="card-text text-center">{{ request.user.profile.bio }}</p>
</div>
</div>
</div>
</div>
{% endblock content %}
</div>
models.py
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
image = models.ImageField(default='default.png', upload_to='profile_pics')
slug = AutoSlugField(populate_from='user')
bio = models.CharField(max_length=255, blank=True)
friends = models.ManyToManyField('Profile', blank=True)
I would have done like this :
object_list = User.objects\
.filter(username__icontains=query)\
.exclude(profile__friends__in=request.user.profile.friends.all())\
.exclude(id=request.user.id)
It should be
User.profile.objects.filter(username__icontains=query).exclude(friends=request.user.profile.friends.all())
You were getting an error earlier because you referred to the user object earlier and not the profile itself. User.profile gives the one to one related model profile instead.
You can read more about one to one relationships here. https://docs.djangoproject.com/en/3.1/topics/db/examples/one_to_one/

Django Threaded Comments template

I code a social media site using Django. have a model for commenting my articles
class ArticleComment(models.Model):
parent = models.ForeignKey('self',
null=True,
blank=True,
related_name='replies',
on_delete=models.CASCADE)
article = models.ForeignKey(
Article,
on_delete=models.CASCADE,
related_name="comments")
created_at = models.DateTimeField(auto_now_add=True)
class Meta:
# sort comments in chronological order by default
ordering = ('created_at',)
def __str__(self):
return 'Comment by {}'.format(self.user.username)
Now I try to render my threaded comments in my template. But i can not figure how to render my sub-comments in the same level. This is how I ended but this means only first level of replies.
<ul class="comments-list style-3" id="articleComments">
{% for comment in comments %}
<li class="comment-item has-children moreList">
<div class="comments-content">
<p>{{comment.content}}</p>
//toggle answer reply form
<a data-toggle="collapse" href="#{{comment.id}}"class="reply" role="button" aria-expanded="false" aria-controls="collapseExample">{% trans 'Reply' %}</a>
Report
<div>
<form id="{{comment.id}}" class="collapse" method="post">
<br>
{% csrf_token %}
<input type="hidden" name="parent" value="{{comment.id}}">
<div class="crumina-module crumina-heading with-title-decoration">
<h5 class="heading-title">{% trans 'Write a Reply' %}</h5>
</div>
<div class="row">
<div class="col col-6 col-xl-6 col-lg-6 col-md-6 col-sm-6">
<div class="form-group label-floating is-empty">
<label class="control-label">{% trans 'Reply Comment' %}</label>
<textarea class="form-control" placeholder="" name="content"></textarea>
</div>
<button class="btn btn-primary btn-lg full-width" type="Submit">{% trans 'Post your Reply' %}</button>
</div>
</div>
</form>
</div>
</div>
//try to loop comments with parent
{% if parent %}
<ul class="children first-children-level">
{% for reply in comment.replies.all %}
<li class="comment-item">
<div class="comments-content">
<p>{{reply.content}}</p>
Report
</div>
</li>
{% endfor %}
</ul>
{% endif %}
</li>
{% endfor %}
</ul>
can you guide me how to loop through sublevels ?
Thanks

How to combine any fields in one in Django filters

I wonder how you combine search from multiple fields into one. The fields would be textoQuestao, perguntaQuestao, aOpcao, bOpcao, cOpcao, eOpcao, eOpcao.
I would like all of these fields to be combined into one called texto and to search all selected fields.
filters.py
class FiltroQuestoes(django_filters.FilterSet):
texto =
class Meta:
model = Questao
fields = ['textoQuestao','perguntaQuestao','aOpcao','bOpcao','cOpcao','dOpcao','eOpcao','idProva','idQuestao','idCategoria']
views.py
def FiltroDeQuestoesView(request):
qs = filter(request)
context = {
'queryset': qs,
'categorias': Categoria.objects.all(),
'provas': Prova.objects.all()
}
return render(request, "polls/pesquisa.html", context)
def filter(request):
qs = Questao.objects.all()
categorias = Categoria.objects.all()
prova = request.GET.get('prova')
provas = Prova.objects.all()
questao = request.GET.get('questao')
categoria = request.GET.get('categoria')
return qs
search.html
{% block content %}
<form method="get">
<div class="well">
<h4 style="margin-top: 0">Filter</h4>
<div class="row">
<div class="form-group col-sm-4 col-md-3">
{{ filter.form.texto.label_tag }}
{% render_field filter.form.texto class="form-control" %}
</div>
<div class="form-group col-sm-4 col-md-3">
{{ filter.form.idProva.label_tag }}
{% render_field filter.form.idProva class="form-control" %}
</div>
<div class="form-group col-sm-4 col-md-3">
{{ filter.form.idQuestao.label_tag }}
{% render_field filter.form.idQuestao class="form-control" %}
</div>
<div class="form-group col-sm-4 col-md-3">
{{ filter.form.idCategoria.label_tag }}
{% render_field filter.form.idCategoria class="form-control" %}
</div>
<button type="submit" class="btn btn-primary">
<span class="glyphicon glyphicon-search"></span> Search
</button>
</div>
</form>
{% endblock %}
I would suggest you should go with elasticsearch for this.
But you can use django Q objects to do OR query
qs = Questao.objects.filter(Q(textoQuestao__icontains=query_string)| Q(perguntaQuestao__icontains=query_string)|...