Django how to iterate querysets of two subclasses in template? - django

I am using django-model-utils for inheritance Managers. I want to get result of both sub-classes with one dictionary without getting duplicates.
models.py
class Images(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='images_created', on_delete=models.CASCADE)
created = models.DateTimeField(auto_now_add=True, null=True, blank=True)
objects = InheritanceManager()
class Postimg(Images):
user_img= models.ImageField(upload_to='images/%Y/%m/%d', null=True, blank=True)
class Postsms(Images):
user_message = models.CharField(max_length=500,blank=True)
views.py
def home(request):
all_post = Images.objects.all().order_by('-created').select_subclasses()
return render(request, 'copybook/home.html',{ 'all_post':all_post})
copybook/home.html
{% for foo in all_post %}
<hr>
<br> SMS by: <p>{{ foo.user}} __ {{ foo.created }}</p>
<h2>{{ foo.user_message }}</h2>
<hr>
<br> IMAGE by: <p>{{ foo.user}} __ {{ foo.created }}</p>
<img src="{{ foo.user_img.url }}"width="250">
{% endfor %}
I expect the result when I upload an image or message that should get top at home page, but now when I upload an image, a blank message also gets iterated.
I think the problem is in my home.html, because I do not know how to iterate
over two sub-classes with a single for loop without getting duplicates.

In your template, you are processing every item as if it were both a message and an image. That's why you get empty image sections for messages and empty message sections for images.
The simplest workaround would be to check if user_img or user_message evaluates to True:
{% for foo in all_post %}
<hr>
{% if foo.user_message %}
<br> SMS by: <p>{{ foo.user}} __ {{ foo.created }}</p>
<h2>{{ foo.user_message }}</h2>
{% else %}
<br> IMAGE by: <p>{{ foo.user}} __ {{ foo.created }}</p>
<img src="{{ foo.user_img.url }}"width="250">
{% endif %}
{% endfor %}
Instead of else you can do a separate if foo.user_img to avoid message objects with empty messages to be interpreted as images.

Related

How to delete a record through a button in django

I have created a model Announcement in models.py file
class Announcement(models.Model):
title = models.CharField(max_length=30)
content = models.TextField()
date_posted = models.DateTimeField(default=timezone.now)
teacher = models.ForeignKey(Teacher, on_delete=models.CASCADE)
def __str__(self):
return self.title
And for deleting a record of Announcement I have created the following view
def AnnouncementDelete(request, pk):
announcement = get_object_or_404(Announcement, pk=pk)
if request.method=='POST':
announcement.delete()
return redirect('/')
return render(request, 'classroom/announcement_confirm_delete.html', {'announcement': announcement})
The delete view of announcement (that is AnnouncementDelete) has the following url
path("delete/<int:pk>/", view=views.AnnouncementDelete, name="AnnouncementDelete"),
If i enter
http://127.0.0.1:8000/classroom/delete/3
on browser it is deleting the Announcement having pk = 3
Now I want a button to directly delete my record without the need of typing http://127.0.0.1:8000/classroom/delete/3 on browser
I have tried the following methods in my allannouncement.html file
{% extends "classroom/base.html" %}
{% block content %}
<h1>Announcements</h1>
{% for announcement in announcements %}
<!-- starting loop (posts is keyword from view) -->
<div style="border-style: solid;">
{% if announcement.teacher.user == request.user %}
<div>
Delete
</div>
{% endif %}
{{ announcement.pk }}
<a class="mr-2">Posted by: {{ announcement.teacher }}</a>
<h2><a class="article-title">{{ announcement.title }}</a></h2>
<p class="article-content">{{ announcement.content}}</p>
</div>
{% endfor %}
{% endblock content %}
but it is giving the following error
NoReverseMatch at /classroom/allannouncement/
Reverse for 'AnnouncementDelete' with no arguments not found. 1 pattern(s) tried: ['classroom/delete/(?P<pk>[0-9]+)/$']
then I also tried passing pk with url like
Delete
But it is giving the following error
TemplateSyntaxError at /classroom/allannouncement/
Could not parse the remainder: ',' from ','
Remove common #refer this
Delete
instead of a link add a form.
Add
{% load crispy_forms_tags %}
in your html file and then add
{% if announcement.teacher.user == request.user %}
<div>
<form action="{% url 'classroom:AnnouncementDelete' announcement.id %}"
method="post">
{% csrf_token %}
<input type="submit" value="Delete">
</form>
</div>
{% endif %}

Problem with CheckboxSelectMultiple from a CharField ModelForm in Django

I'm having trouble getting my form to save in Dajngo due to the following error on validation:
<ul class="errorlist"><li>pt_medical_condition<ul class="errorlist"><li>Select a valid choice.
['anx', 'Bip'] is not one of the available choices.
>pt_surgical_history<ul class="errorlist"><li>Select a valid choice.
['bre', 'pca'] is not one of the available choices.
I've got this model:
class pt_data(models.Model):
condition_choices = [('ane', 'Anemia'), ('anx', 'Anxiety'), ('art', 'Arthritis'),
('ast', 'Asthma'), ('Bip', 'Bipolar'), ('ca', 'Cancer'), ('clo', 'Clotting disorder'),
('chf', 'CHF'), ('mdd', 'Depression'), ('cop', 'COPD'), ('ger', 'GERD'),
('gla', 'Glaucome'), ('hiv', 'HIV/AIDS'), ('ibs', 'IBS/Crohn\'s'),
('hld', 'High cholesterol'), ('ckd', 'Kidney disease'), ('ner', 'Nerve/Muscle disease'),
('ocd', 'OCD'), ('ost', 'Osteoporosis'), ('pai', 'Pain disorder'), ('pts', 'PTSD'),
('sch', 'Schizophrenia'), ('sei', 'Seizures'), ('sca', 'Sickle cell anemia'),
('su', 'Substance use disorder'), ('thy', 'Thyroid disease')]
surgery_choices = [('app', 'Appendix removal'), ('bra', 'Brain surgery'),
('bre', 'Breast surgery'), ('cabg', 'CABG'), ('pca', 'Cardiac stent'),
('cho', 'Gallbladder removal'), ('col', 'Bowel surgery'), ('csec', 'C-section'),
('fra', 'Bone fracture repair'), ('her', 'Hernia repair'), ('hys', 'Uterus removal'),
('joi', 'Joint replacement'), ('lun', 'Lung surgery'), ('spi', 'Spine/back surgery'),
('thy', 'Thyroid surgery'), ('ton', 'Tonsil removal'), ('strf', 'Tubal ligation'),
('strm', 'Vasectomy'), ('wei', 'Weight reduction surgery')]
pt_medical_condition = models.CharField(max_length=100, blank=True, null=True,
choices=condition_choices)
pt_surgical_history = models.CharField(max_length=100, blank=True, null=True, choices=surgery_choices)
And this form:
class ptForm(forms.ModelForm):
class Meta:
model = pt_data
fields = ('__all__')
widgets = {
'pt_medical_condition': CheckboxSelectMultiple(attrs={'class': 'cond_checkbox'}),
'pt_surgical_history': CheckboxSelectMultiple(attrs={'class': 'surg_checkbox'}),
}
And this is my HTML:
{% for check in form.pt_medical_condition %}
{% if forloop.counter|divisibleby:3 %}
<div> </div>
{% endif %}
<label class='mx-2' id="{{ check.choice_label }}">
{{ check.tag }} {{ check.choice_label }}
</label>
{% endfor %}
{% for check in form.pt_surgical_history %}
{% if forloop.counter|divisibleby:2 %}
<div> </div>
{% endif %}
<label class='mx-2' id="{{ check.choice_label }}">
{{ check.tag }} {{ check.choice_label }}
</label>
{% endfor %}
The HTML is rendered just fine, the problem seems to arise on submit. It looks like the correct characters are there, however they are surrounded by incorrect characters. The following "anx" is appropriate but won't be validatated by Django because everything else that has been tacked on 'anx&#x27. Could it be a problem with posting the information with AJAX? Or maybe using a CSRF cookie to POST? Has anyone else encountered this problem? Any suggestions would be helpful.

Accessing additional fields from a grouper in a Django group_by

How can I access fields other than the grouper in a Django group_by function?
class dateEvent(models.Model):
event = models.ForeignKey('Event', on_delete=models.CASCADE)
start_date_time = models.DateTimeField(auto_now=False, auto_now_add=False)
def __str__(self):
return "%s" % (self.event.title)
def description(self):
return "%s" % (self.event.description)
class Event(models.Model):
description = RichTextUploadingField(max_length=200)
view:
def my_view(request):
events = dateEvent.objects.all()
context = {
'events': events,
}
return render(request, 'view.html', context)
template:
<ul>
{% for event in dateEvents_list %}
<li><h5>Event: {{ event.grouper }}</h5>
<h6>Description: {{ event.description }}</h6> #How can access the description of the main event?
<ul>
{% for dateEvent in event.list %}
<li>date: {{ dateEvent.start_date_time }}</li>
{% endfor %}
</ul>
</li>
{% endfor %}
</ul>
I'd like to have the title, which is the grouper so it's fine, but also the description.
You can also access your grouper's list objects to get details about the "first record" in your group. So using:
event.grouper.list.0.<any_model_field_you_want>
Will work just fine. I have this in production and it solved my needs immediatly. I found this in a rejected feature request for Django here: https://code.djangoproject.com/ticket/13452
If you need to traverse your model's relationship tree you can do the following.
event.grouper.list.0.<related_model_name>.<any_model_field_you_want>
You can access model attributes from the grouper directly using event.grouper.<any-model-attribute>.
In your example here is how it would look:
<ul>
{% for event in dateEvents_list %}
<li><h5>Event: {{ event.grouper }}</h5>
<h6>Description: {{ event.grouper.description }}</h6>
<ul>
{% for dateEvent in event.list %}
<li>date: {{ dateEvent.start_date_time }}</li>
{% endfor %}
</ul>
</li>
{% endfor %}
</ul>
I can't find any documentation around this usage.

How to display in Django Templates Embedded Models?

models.py
class Decomposicao(models.Model):
tirosina = models.BooleanField('tirosina')
fenilalanina = models.BooleanField('fenilalanina')
class Meta:
abstract = True
class SDF(models.Model):
numero = models.IntegerField('SDF', unique=True, primary_key=True)
decomposicao = models.EmbeddedModelField(
model_container=Decomposicao,
)
data_insercao = models.DateTimeField(auto_now_add=True)
def __str__(self):
return str(self.numero)
views.py
def search(request):
data = {}
if request.method == 'GET':
search = request.GET
search = search['sdf']
if search.startswith("SDF") or search.startswith("sdf"):
sdf = SDF.objects.get(pk=search[3:])
else:
sdf = SDF.objects.get(pk=search)
data['sdf'] = sdf
data['numero'] = format(sdf.numero, '04d')
return render(request, 'app/busca.html', data)
I'm using mongodb and django, so I decided to utilize djongo as the connector - djongo doc - that been said I'm trying to display the content I find on querys in django templates - busca.html - but I can't find a way to display the Embedded models.
busca.html
{% extends 'app/base.html' %}
{% block cabecalho %}
{% load staticfiles %}
<title>SDF{{ numero }}</title>
{% endblock%}
{% block conteudo %}
<section class="bg-light">
<div class="container ">
<div class="col-lg-12 h-100 text-center text-lg-left my-auto">
<h1 class="text-muted medium mb-4 mb-lg-0">SDF{{ numero }</h1>
<br>
{{ sdf }}
</div>
</div>
</section>
{% endblock %}
Doing that only display the number - 'numero' - of the sdf.
Thanks.
{{ sdf }} calls the __str__ method of your model, which returns numero as defined. To display all the fields use {{ sdf.numero }}, {{ sdf.decomposicao }}, {{ sdf.data_insercao }}. I believe that you could access fields of your embedded model with dot notation, for example {{ sdf.decomposicao.tirosina }}.

Display of data in HTML

Suppose I have an object called "comment_list", which is just a list of comments & related info. I'd like to display that to the page, so I do this:
page.html
{% for comment in comment_list %}
<b>ID:{{ comment.id }} - {{ comment.name }} (on {{ comment.submit_date }})</b><br>
<h4>{{ comment.comment }}</h4><br><br>
{% endfor %}
I used the django-comments add-on for this, and it works very well, no problem at all. Now, here's the thing - I wanted to add a special feature to the comments so that if activated, this special feature will display in place of that particular comment. I built a new table that connected to Comments, and linked it via comment_id.
What I then want to do is implement an "if-else" thing in the HTML to replace the comment as it loops. Just to be clear, "comment_list" has multiple objects within. So...:
page.html
{% if special_feature.comment_id = comment.id %}
<b>ID:{{ comment.id }} (on {{ comment.submit_date }})</b><br>
<h4>YES SPECIAL FEATURE!</h4><br><br>
{% else %}
<b>ID:{{ comment.id }} - {{ comment.name }} (on {{ comment.submit_date }})</b><br>
<h4>{{ comment.comment }}</h4><br><br>
{% endif %}
"special_feature" also has multiple objects within. But I can't seem to make it work. "special_feature.comment_id" will not appear, because I expect it to have more than one objects inside. I have to specifically state it as "special_feature.X.comment_id", where "X" is a number.
So the solution is to somehow use the "forloop.counter" for that. In which case, the final code could look like so:
page.html
{% for comment in comment_list %}
{% if special_feature.(forloop.counter|add:"-1").comment_id = comment.id %}
<b>ID:{{ comment.id }} (on {{ comment.submit_date }})</b><br>
<h4>YES SPECIAL FEATURE!</h4><br><br>
{% else %}
<b>ID:{{ comment.id }} - {{ comment.name }} (on {{ comment.submit_date }})</b><br>
<h4>{{ comment.comment }}</h4><br><br>
{% endif %}
{% endfor %}
"add:-1" is so that the counter starts from "0" rather than "1". "special_feature.(forloop.counter|add:"-1").comment_id" doesn't work obviously, is there a better way to handle this?
EDIT:
Here's the view.py
#login_required(login_url='sign_in')
def display_comments(request, magazine_slug, art_id):
context = {}
populateContext(request, context)
magazine_data = get_object_or_404(Magazine, slug=magazine_slug)
article_data = get_object_or_404(Article, project_id=magazine_data.id, id=art_id)
special_feature = CommentSpecial.objects.all().filter(user_id=request.user.id)
context = {'article':article_data, 'magazine':magazine_data, 'special_feature':special_feature}
return render(request, 'projsapp/page.html', context)
#login_required(login_url='sign_in')
def add_special_feature_comments(request, art_id):
context = {}
populateContext(request, context)
# Acquire data from post
data = request.POST
special_type = data.get('id_special')
date_time=datetime.datetime.now()
# Confirm whether article exists
article_data = get_object_or_404(Article, id=art_id)
content_type = ContentType.objects.get_for_model(article_data)
# Save a new comment manually
save_comment=Comment.objects.create(object_pk=art_id, user_name="SYSTEM", user_email="lala#lala.com", comment="SPECIAL", ip_address="127.0.0.1", is_public=1, is_removed=0, content_type_id=content_type.id, site_id=settings.SITE_ID, user_id=request.user.id, submit_date=date_time)
# Save to CommentSpecial as well!
CommentSpecial.objects.create(special_type=0, user_id=request.user.id, text="SUPER", comment_id=save_comment.id)
return HttpResponseR blah blah....
And here's model.py for CommentSpecial:
class CommentSpecial(models.Model):
comment = models.ForeignKey(Comment)
user_id = models.ForeignKey(User)
creation_date = models.DateTimeField(auto_now_add=True)
text = models.CharField(max_length=100, blank=True, null=True, default='')
special_type = models.BooleanField(default=False)
# False = Super Special, True = Typical Special