Django parsing values of fields in models - Extracting pk - python

I'm completely lost on part of my Django website. I finally figured out a way to have the same model create a template and then use that template and create another post. This works and is ideal. Now I need to put them in different locations on the screen so I basically need two for-loops and a way to decipher the two(templates and posts off of templates) apart from each other. The model has a title and a content field. When a template is created the title always starts with "Temp: ". I'm completely lost on this because I need to parse through the model and not just use an HTML parser because the content won't already be on the page and there is more than just the title that needs to be moved. I need a way I think in the views.py file to get the pk of ALL titles that start with "Temp: " and the content field tied with it and return it in a variable to the HTML file. I have been working on this for 3 days now and I just really need help.
views.py
def docpostlistview(request):
field = DocPost.objects.all()
return render(request, 'my_app/docpost_list.html', {'field': field})
HTML
<div class="blocks">
<div class="row">
<div class="col">
TESTESTESTESTESTESTESTES
</div>
{% if user.Doc.all %}
{% for post in user.Doc.all %}
<div class="col">
<div class="card card_template hoverable">
<div class="card-image">
<a href="{% url 'use_template' pk=post.pk %}" style="color: black">
<p>
{{ post.content|safe }}
</p>
</a>
</div>
<div class="card-content">
<p>
</p>
</div>
<div class="card-action">
<div class="bottom_text">
{{ post.title }}
<div class="bottom_button">
<form action="{% url 'use_template' pk=post.pk %}" method="POST">
{% csrf_token %}
<div class="card-body">
<a style="background-color: #2f3d50; border-radius: 18px; height: 30px; position: relative; top: 5px;" href="{% url 'use_template' pk=post.pk %}" class="btn btn-primary"><div style="position: relative; top: -3px;">Create</div></a><!--use_template pk=post.pk - post-list-->
</div>
</form>
</div>
</div>
</div>
</div>
<div class="wrapper">
<ul>
<li><a class="dots_img"> <img src="{% static 'threedots.png' %}" alt=""</a>
<ul>
<div class="edit_drop">
<form action="{% url 'doc-post-update' pk=post.pk %}" method="POST">
{% csrf_token %}
<div class="card-body">
<a style="background-color: #2f3d50; border-radius: 18px;" href="{% url 'doc-post-update' pk=post.pk %}" class="btn btn-primary">EDIT</a>
</div>
</form>
</div>
<div class="delete_drop">
<a style="background-color: #2f3d50; border-radius: 18px;" href="{% url 'delete_post' pk=post.pk %}" class="btn btn-danger">Delete</a>
<!--<form action="{% url 'reset' %}" method="POST">{% csrf_token %}
<button type="submit" class="btn btn-danger">Delete</button>
</form>-->
</div>
</ul>
</li>
</ul>
</div>
</div>
{% endfor %}
<hr class="hline">
{% else %}
<div class="no_template">
<p>Your new templates will appear here!</p>
</div>
<div class="no_post">
<p>Your new documents will appear here!</p>
</div>
<hr class="hline-non">
{% endif %}
<div class="blocks2">
<div class="row">

You might be interested in field lookups which utilizes the SQL WHERE clause.
https://docs.djangoproject.com/en/3.2/ref/models/querysets/#startswith
https://docs.djangoproject.com/en/3.2/ref/models/querysets/#field-lookups
https://docs.djangoproject.com/en/3.2/topics/db/queries/#field-lookups
Sample:
doc_posts = DocPost.objects.filter(title__startswith="Temp: ")
Here, doc_posts is an iterable QuerySet object containing a sequence of DocPost objects where each item's title starts with "Temp: ".
If all you want are the id and the content fields, you may use values().
https://docs.djangoproject.com/en/3.2/ref/models/querysets/#values
Sample:
id_content_seq = DocPost.objects.filter(title__startswith="Temp: ").values("id", "content")
Here, id_content_seq is an iterable QuerySet object containing a sequence of dict objects containing id and content as keys for all items where the title starts with "Temp: ".

Related

Is it possible to edit a crispy form using styles.css? Like change the background color, etc.? Because I can't make mine work. Thanks

I am a beginner in studying Python Django and I am trying to create a login page for my website using crispy forms. But I can't control the styling of it, I am wondering if it is possible and if it is, how can I possibly do it? Thanks.
Here is the Django HTML codes:
{% extends 'users/base.html' %}
{% load crispy_forms_tags %}
{% block content %}
{% load static %}
<link rel="stylesheet" href="{% static 'users/register.css' %}">
<div class="register-container">
<form method="POST">
{% csrf_token %}
<fieldset class="form-group">
<legend class="border-bottom mb-4">
Create An Acount
</legend>
{{ form|crispy }}
</fieldset>
<div class="form-group">
<button class="btn btn-outline-info" type="submit">
Sign Up
</button>
</div>
</form>
<div class="border-top pt-3">
<small class="text-muted">
Already Have An Account?
<a class="ml-2" href="#">Log In</a>
</small>
</div>
</div>
{% endblock content %}
CSS:
base.css
transition: margin-left .5s;
padding: 16px;
background: rgb(255,255,255);
background: radial-gradient(circle,
rgba(255,255,255,1) 0%,
rgba(33,208,178,1) 100%);
}
Yes its possible, you can simply add javascript code which adds class to desired input field and then you can add styling for that class.
For e.g :-
# if you want to add styling to the username input then
# use this javascript
const inp_field = document.querySelector("#input_username"); # enter the id/class of that element
inp_field.classList.add("custom__css");
# css code
.custom__css {
# whatever css you need
}

Django search view not generating html page I set

I am having trouble getting my search form to work in Django. When I search anything in the search bar I have set, I get an html page that just has the words Search on it. It's not the html page I set, though. My search template is in my projects templates directory. I am trying to search through my blog posts, and have attached my views and urls code.
This portion of my base template is within a navbar I grabbed from a sample Bootstrap blog template. This is the sample template. I've changed some things within my form.
base.html
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
<link href="http://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.3.0/css/font-awesome.css" rel="stylesheet" type='text/css'>
{% load static %}
<!-- Navbar here -->
<nav class="navbar navbar-expand-lg navbar-dark fixed-top bg-dark">
<a class="navbar-brand" href="{% url 'index' %}">ChairBlog</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse">
<ul class="navbar-nav mr-auto">
<li class="nav-item">
<a class="nav-link {% if request.resolver_match.view_name == 'index' %}active{% endif %}" href="{% url 'index' %}">Home</a>
</li>
<li class="nav-item">
<a class="nav-link {% if request.resolver_match.view_name == 'project_index' %}active{% endif %}" href="{% url 'project_index' %}">Projects </a>
</li>
<li class="nav-item">
<a class="nav-link {% if request.resolver_match.view_name == 'blog_index' %}active{% endif %}" href="{% url 'blog_index' %}">Blog </a>
</li>
</ul>
<form class="form-inline my-2 my-lg-0" action="{% url 'search' %}" method="GET">
<input class="form-control mr-sm-2" type="search" name="q" placeholder="Search blog posts...">
<button class="btn my-2 my-sm-0" type="submit">Search</button>
</form>
</div>
</nav>
<!-- Jumbotron stuff here -->
<div class="jumbotron d-flex align-items-center" style="margin-top: 56px;">
<div class="container text-center">
{% block jumbo_content %}
{% endblock %}
</div>
</div>
<!-- Main content goes here -->
<div class="container" style="padding-bottom: 200px;">
{% block page_content %}{% endblock %}
</div>
<!-- Footere here -->
<footer style="position: relative;">
<div class= "page-footer bg-dark" style="padding-top: 20px; margin-top: 50px;">
<div class="container" style="display: flex; justify-content: center;">
<div class= "row">
<div class="mb-10 flex-center">
<a class="github" href="https://github.com/ChairMane"><i class="fa fa-github-square fa-2x"></i></a>
</div>
</div>
</div>
<div class="footer-copyright text-center py-3" style="color: white;">Chair Birds Co.</div>
</div>
</footer>
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js" integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js" integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy" crossorigin="anonymous"></script>
Nothing within my blocks shows up when I view it. The tags <p>TEST</p> and <p>Is this working?</p> are not showing up. Neither is the block for the jumbo_content. I have set those correctly in my base.html, because they work with my other pages. It's just the search page it doesn't work on.
search.html
{% extends "base.html" %}
{% load static %}
{% block jumbo_content %}
<h1 class="display-4">Search Results</h1>
{% endblock %}
{% block page_content %}
<p>TEST</p>
{% if query %}
{% if results %}
<ul>
{% for post in results %}
<p>Is this working?</p>
<li>
{{ post.title }}, {{ post.body }}
</li>
{% endfor %}
</ul>
{% else %}
<p>Query returned no results.</p>
{% endif %}
{% endif %}
{% endblock %}
app/views.py
...
def search_posts(request):
query = request.GET.get('q', '')
if query:
queryset = (Q(title__icontains=query) | Q(body__icontains=query))
results = Post.objects.filter(queryset).distinct()
else:
results = []
context = {
'results' : results,
'query' : query
}
return render(request, 'search.html', context)
...
app/urls.py
from django.urls import path
from . import views
urlpatterns = [
path('', views.blog_index, name='blog_index'),
path('<int:pk>/', views.blog_detail, name='blog_detail'),
path('<category>/', views.blog_category, name='blog_category'),
path('search/', views.search_posts, name='search'),
]
Here is how the search template is being viewed, I believe. My issues are as shown in the image. The inspector shows nothing within the blocks I've set. I have jumbo_content and page_content, and yet none of what I set within each block shows up.
Can anyone see anything immediately wrong here? I've tried this tutorial as well, and the same thing happens.
EDIT It seems my search_posts(request) function in my views is not even being called when I search something in the search bar. I tried tracebacks, and printing and nothing showed up in my terminal. Am I not correctly calling search_posts(request)?
I finally got my answer. I looked at this post and decided to try something. Apparently, if I change my app/urls.py line from this:
path('search/', views.search_posts, name='search'),
to this:
path('search', views.search_posts, name='search'),
then my whole view works.
Can anyone explain why that is? I had no idea removing a / could help.

i'm having trouble with my django code while i deleting the data from the table form on click of the delete button

But it will showing an error which is (TypeError at /deletecase deletecase() missing 1 required positional argument: 'pk') please help me out this
Here is the url link of the page:
```path("deletecase",views.deletecase,name="deletecase")```
THE VIEW FILE FUNCTION:
```
def policcasesdetails(request):
cases=Case.objects.all()
return render(request,'policeside/policcasesdetails.html',{'cases':cases})
def deletecase(request,pk):
obj=Case.objects.get(id=pk)
obj.delete()
return HttpResponse("Data is Deleted")
```
AND THE FORM IS:-
<div class="container">
<div class="content-middle">
<div class="col-md-12 sed-in">
<h3>Cases Details</h3>
{% for i in cases %}
<div class="col-md-4 sed-top">
<div class="top-sed">
<!-- <img src="{{ i.image.url }}" class="img-responsive" alt=""> -->
<!-- <label><span>{{ i.oname }}</span></label> -->
</div>
<h4>
Case Number- <a>{{i.casenumber}}</a>
</h4>
<p>Case Name- {{i.casename}}</p>
<p>Case Result- {{ i.caseresult }}</p>
<p>Case Conclusion- {{ i.casecoclusion }}</p>
<p><a href="{% url 'deletecase' i.id %}">
<button type="submit" value="delete" class="btn btn-
danger">Delete</button>
</p>
</div>
{% endfor %}
<div class="clearfix"> </div>
</div>
<div class="clearfix"> </div>
</div>
</div>
In your URL, pk is missing.
path("deletecase/<id>/",views.deletecase,name="deletecase")
This should solve your issue

Django model id not changing through for loop

So I have a for loop in my Django template that loops through a product in my products model. The product model has an amount attribute that is supposed to change when the user clicks on the 'add' button. I have made a hidden form that launches the upvote method which takes a request and a pk and increases the amount attribute by 1.
The problem is that when I click on the add button, only two of the products' amount increase. I can't get the rest of the products' amount attribute to increases.
Here's the Django template code:
<div class="card-deck d-flex justify-content-start container-fluid">
{% for product in products %}
<div class="card lead m-3" style="min-width: 18rem;">
<div class="card-body">
<h5 class="card-title">{{ product.name }}</h5>
<h6 class="card-subtitle mb-2 text-muted">{{ product.product_id }}</h6>
<hr>
<p class="card-text">
Expiration date: {{ product.expiration_date }}
</p>
<p class="card-text">
amount: {{ product.amount }} <button class="btn btn-primary btn-sm">+</button>
</p>
<p class="card-text">
tags:
{% for t in product.tag.all %}
<span class="badge badge-primary">{{ t.name }}</span>
{% endfor %}
</p>
</div>
</div>
<form action="{% url 'upvote' pid=product.id %}" method="POST" id="upvote">
{% csrf_token %}
<input type="hidden">
</form>
here's the upvote method in the views.py file:
def upvote(request, pid):
if request.method == "POST":
product = get_object_or_404(models.Product, pk=pid)
product.amount += 1
product.save()
return redirect('home')
You end up having multiple elements with the same id (upvote) which is not allowed, and the Javascript code always uses the first form element it finds and submits that one.
To have unique form ids, change the following line
<form action="{% url 'upvote' pid=product.id %}" method="POST" id="upvote">
to
<form action="{% url 'upvote' pid=product.id %}" method="POST" id="upvote_{{ product.id }}">
and the following line
<a href="javascript:{document.getElementById('upvote').submit();}">
to
<a href="javascript:{document.getElementById('upvote_{{ product.id }}').submit();}">

Django include template tag in for loop only catches first iteration

I have a comments section on some pages on my site that I build with a {% for ... %} loop (and another nested loop for comment replies. The section was hacked together, and I am still learning web development and Django, so please forgive any frustrating sloppiness or weirdness. I am not concerned with efficiency at the moment, only efficacy, and right now it is not working quite right.
For each comment I have a Bootstrap dropdown button that will bring up the options Edit and Delete. Edit will open a modal to edit the comment. The modals are rendered with an {% include %} tag. Below I have included part of my code unmodified, rather than trying to simplify my example and risk leaving something crucial out:
<div class="panel panel-default">
{% for comment in spot.ordered_comments %}
<div class="panel-heading row">
<div class="col-sm-10">
<strong>{{ comment.poster.username }}</strong>
<em style="margin-left: 2em">{{ comment.created|date:'M d \'y \a\t H:i' }}</em>
</div>
<div class="btn-group col-sm-2" role="group">
{% if comment.poster == user %}
<form id="delete-comment-form" class="form"
method="post" action="{% url 'delete_comment' spot.id comment.id %}">
{% csrf_token %}
</form>
{% include 'topspots/editmodal.html' with edit_type='comment' %}
<div class="btn-group">
<button type="button" class="btn btn-default dropdown-toggle"
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<i class="fa fa-edit"></i> <span class="caret"></span>
</button>
<ul class="dropdown-menu">
<li>Edit</li>
<li role="separator" class="divider"></li>
<li>
Delete
</li>
</ul>
</div>
{% endif %}
{% if user.is_authenticated %}
{% include 'topspots/replymodal.html' %}
<button type="button" class="btn btn-default" data-toggle="modal"
data-target="#replyModal">
Reply
</button>
{% endif %}
</div>
</div>
<div class="panel-body">
<div class ="row">
<div class="col-sm-8">
{{ comment.comment_text }}
</div>
</div>
<br/>
<!-- Comment replies -->
{% if comment.commentreply_set %}
{% for reply in comment.commentreply_set.all %}
<div class="row" style="padding-left: 1em">
<div class="col-sm-8 well">
<p>{{ reply.reply_text }}</p>
<div class="row">
<div class="col-sm-4">
<p>
<strong>{{ reply.poster.username }}</strong>
<em style="margin-left: 2em">{{ comment.created|date:'M d \'y \a\t H:i' }}</em>
</p>
</div>
{% if reply.poster == user %}
{% include 'topspots/editmodal.html' with edit_type='reply' %}
<form id="delete-reply-form" class="form"
method="post" action="{% url 'delete_reply' spot.id reply.id %}">
{% csrf_token %}
</form>
<div class="col-sm-2">
<div class="btn-group">
<button type="button" class="btn btn-default dropdown-toggle"
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<i class="fa fa-edit"></i> <span class="caret"></span>
</button>
<ul class="dropdown-menu">
<li><a href="#" data-toggle="modal"
data-target="#editModal">Edit</a></li>
<li role="separator" class="divider"></li>
<li>
<a href="javascript:;"
onclick="$('#delete-reply-form').submit();">Delete</a>
</li>
</ul>
</div>
</div>
{% endif %}
</div>
</div>
</div>
{% endfor %}
{% endif %}
</div>
{% endfor %}
</div>
Here is the edit modal:
<!-- editmodal.html -->
{% load static %}
<div class="modal fade" id="editModal" tabindex="-1" role="dialog" aria-labelledby="editModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span></button>
<h2 class="modal-title" id="editModalLabel">
Edit {{ edit_type }}:
</h2>
</div>
<form action="{% url 'edit_comment' spot.id comment.id %}" method="post">
<div class="modal-body">
<input class="form-control" name="text" value="{{ comment.comment_text }}" autofocus>
<input type="hidden" name="edit_type" value="{{ edit_type }}">
{% csrf_token %}
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-default">Finish editing</button>
</div>
</form>
</div>
</div>
</div>
<script>
$('.modal').on('shown.bs.modal', function() {
$(this).find('[autofocus]').focus();
});
</script>
and the reply modal:
<!-- replymodal.html -->
{% load static %}
<div class="modal fade" id="replyModal" tabindex="-1" role="dialog" aria-labelledby="replyModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span></button>
<h2 class="modal-title" id="replyModaLabel">
Reply to <strong>{{ comment.poster.username }}'s</strong> comment
</h2>
</div>
<div class="modal-body">
<form action="{% url 'reply_comment' spot.id comment.id %}" method="post">
<input class="form-control" name="reply_text" placeholder="Write a reply..." autofocus>
{% csrf_token %}
</form>
</div>
</div>
</div>
</div>
<script>
$('.modal').on('shown.bs.modal', function() {
$(this).find('[autofocus]').focus();
});
</script>
The issue I am having is that my reply and edit modals (e.g. {% include 'topspots/editmodal.html' with edit_type='reply' %} or {% include 'topspots/replymodal.html' %} seem to be only rendered once with the context of the first iteration of my for loop. So even though all the questions are correctly rendered on the page, when I click reply, edit or delete, regardless of which button I click (i.e., whether I click the button for the first comment, or the fifth comment, etc.) I can only reply to, edit, or delete the very first comment. I have a feeling that this has something to do with closures and scope in a way I am not quite understanding (I have gotten into trouble in the past with unexpected results using lambda in Python loops because of this or this), but I am not sure.
I did a test with the following view:
def test(request):
spots = Spot.objects.all()
return render(request, 'test.html', {'spots': spots})
and templates:
<!-- test.html -->
<h1>Hello world</h1>
{% for spot in spots %}
{% include 'testinclude.html' %}
{% endfor %}
and
<!-- testinclude.html -->
<h3>{{ spot.name }}</h3>
And it printed out a list of unique spot names, so why the difference with the modals?
As emulbreh postulates, a modal is in fact rendered for every comment. However, all of the modals have the same ID, so regardless of which comment’s edit button was clicked, the first modal gets triggered every time. IDs are supposed to be unique across an HTML document.
How can you fix this? You can make the IDs of the modals unique to each comment. You can get a unique identifier by writing id="editModal-{{ comment.id }}" or just id="editModal-{{ forloop.counter }} (documentation here).
But then your editModal.html template is coupled very tightly with your ‘master’ template. A better solution would be to use classes instead of IDs and put the identification where it belongs: the container of each comment. You can try:
adding an ID to each comment’s container:
<div class="panel panel-default">
{% for comment in spot.ordered_comments %}
<div class="panel-heading row" id="comment-{{ comment.id }}">
...
using classes instead of IDs in your modal templates as so:
<!-- editmodal.html -->
{% load static %}
<div class="modal fade editModal" tabindex="-1" ...>
...
changing data-target in your buttons from:
<li>Edit</li>
to:
<li>Edit</li>
It looks like all your edit modals will have the same id id="editModal" as well as your reply modals id="replyModal" if you are showing them based on id probably you will always open the first DOM element with that id. You could try appending a unique identifier like forloop.counter
https://docs.djangoproject.com/en/1.9/ref/templates/builtins/#for

Categories

Resources