How can I check which subcclass the object is in a template? - python

Obligatory, I'm a django beginner and I don't understand why my code isn't working.
I'm trying to sort through a parent class in a view to get an object, then pass that object to a template. In the template, I have certain fields showing for each subclass and some which are inherited from the parent class.
I have tried using isinstance() in my template but it raised errors. After that I tried to add a static attribute to each subclass to check via an if statement in my template. When doing this, none of the subclass specific fields show. So I tried to set the attribute in the view and still had none of the subclass specific fields display.
Here are the parent object class and one of the subclasses (models):
class Chunk(models.Model):
name = models.CharField(max_length=250)
text = models.CharField(max_length=500)
images = models.FileField()
question = models.CharField(max_length=250)
expected_completion_time = models.IntegerField(default=1)
keywords = models.CharField(max_length=250, blank=True, null=True)
topic = models.CharField(max_length=250, blank=True, null=True)
course = models.CharField(max_length=250, blank=True, null=True)
def get_absolute_url(self):
return reverse('detail', kwargs={'pk':self.pk})
def __str__(self):
return self.name
class Concept(Chunk):
application = models.CharField(max_length=500)
subconcept1 = models.CharField(max_length=500, blank=True, null=True)
subconcept2 = models.CharField(max_length=500, blank=True, null=True)
subconcept3 = models.CharField(max_length=500, blank=True, null=True)
subconcept4 = models.CharField(max_length=500, blank=True, null=True)
subconcept5 = models.CharField(max_length=500, blank=True, null=True)
subconcept6 = models.CharField(max_length=500, blank=True, null=True)
subconcept7 = models.CharField(max_length=500, blank=True, null=True)
subconcept8 = models.CharField(max_length=500, blank=True, null=True)
subconcept9 = models.CharField(max_length=500, blank=True, null=True)
subconcept10 = models.CharField(max_length=500, blank=True, null=True)
conceptimage = models.FileField(blank=True, null=True)
#property
def mode(self):
return "concept"
Here is the view:
def startpomodoro(request):
key = getpriority(Chunk.objects.all())
object = Chunk.objects.get(id=key)
a = random() > 0.5
mode = str()
if isinstance(object, Problem):
if a:
mode = "problemoutline"
else:
mode = "problemfull"
elif isinstance(object, Concept):
mode = "concept"
elif isinstance(object, Formula):
mode = "formula"
elif isinstance(object, Code):
mode = "code"
context = dict(object=object, mode=mode)
return render(request, 'pomodoro/pomodorogo.html', context)
Here is the relevant part of the template:
<center>
<p>{{ object.text }}</p>
{% if mode == concept %}
<p>{{ object.application }}</p>
<p>{{ object.subconcept1 }}</p>
{% if object.subconcept2 %}
<p>{{ object.subconcept2 }}</p>
{% elif mode == formula %}
I don't understand why I haven't got any of these methods to work. I'm sure it's an issue in implementation on my part but I don't know what I'm doing incorrectly.

I think you have some unnecessary complications in your models, try a simplified model:
class SubConcept(models.Model):
name = models.CharField(max_length=200)
class Chunk(models.Model):
CHUNK_TYPES = [('P', 'Problem'),
('C', 'Concept'),
('I', 'Idea'),
('K', 'Code'),
('F', 'Formula')]
name = models.CharField(max_length=250)
text = models.CharField(max_length=500)
image = models.FileField()
question = models.CharField(max_length=250)
expected_completion_time = models.IntegerField(default=1)
keywords = models.CharField(max_length=250, blank=True, null=True)
topic = models.CharField(max_length=250, blank=True, null=True)
course = models.CharField(max_length=250, blank=True, null=True)
chunk_type = models.CharField(max_length=1, choices=CHUNK_TYPES)
application = models.CharField(max_length=200)
subs = models.ManyToManyField(SubConcept, blank=True, null=True)
def get_absolute_url(self):
return reverse('detail', kwargs={'pk':self.pk})
def __str__(self):
return '{}'.format(self.name or '')
#property
def mode(self):
return dict(CHUNK_TYPES)[self.chunk_type]
Now, your view is quite simple (I'm ignoring the getpriority method because I have no idea what it does):
def pomodoro(request):
obj = get_object_or_404(Chunk, pk=1)
return render(request, 'foo.html', {'obj': obj})
Here is your template:
<center>
<p>{{ obj.text }}</p>
{% if obj.mode == 'Concept' %}
<p>{{ object.application }}</p>
{% for sub in obj.subs.all %}
<p>{{ sub.name }}</p>
{% endfor %}
{% elif obj.mode == 'Formula' %}
...
</center>

On one Django project I was working on we had a similar issue to this with inherited model classes. The solution we used was to add a type to the parent class.
class Chunk(models.Model):
CONCEPT_TYPES = (
('Problem', 'Problem'),
('Concept', 'Concept'),
('Formula', 'Formula'),
('Code', 'Code'),
)
concept_type = models.CharField(max_length=7, choices=CONCEPT_TYPES)
...
Then in our templates we would do something like:
{% if object.concept_type == 'Concept' %}
<p>{{ object.concept.application }}</p>
<p>{{ object.concept.subconcept1 }}</p>
{% elif object.type == 'Problem' %}
...
{% endif %}
Things to note are that in the future I wouldn't structure my database like this again unless there was a very compelling reason and there are almost certainly better solutions.
You should also try changing your if statement in views.py to something like:
if object.problem:
...
elif object.concept:
....
This might mean that you don't need to put a type row in your models.

Related

How to categorize content in Django ? Where is the problem with my work?

I wanted to categorize my site content. Show the category titles in the menu and the contents of each category in the body. I have used these codes.
#urls
path('category/<slug:slug>', views.category, name="category")
#views
def category(request, slug):
context = {
"categorys": get_object_or_404(Category, slug=slug, status=True)
}
return render(request, "blog/category.html", context)
#models
class PostManager(models.Manager):
def published(self):
return self.filter(status='p')
class Category(models.Model):
title = models.CharField(max_length=100, verbose_name="عنوان دسته بندی")
slug = models.SlugField(max_length=200, unique=True, verbose_name="آدرس")
status = models.BooleanField(
default=True, verbose_name="آیا نمایش داده شود؟")
position = models.IntegerField(verbose_name="پوزیشن")
class Meta:
verbose_name = "دسته بندی"
verbose_name_plural = "دسته بندی ها"
ordering = ['position']
def __str__(self):
return self.title
class Post(models.Model):
STATUS_CHOICES = [
('d', 'پیش نویس'),
('p', 'منتشر شده'),
]
title = models.CharField(max_length=100, verbose_name="عنوان")
slug = models.SlugField(max_length=200, unique=True, verbose_name="آدرس")
category = models.ManyToManyField(
Category, verbose_name="دسته بندی", related_name="postcat")
description = models.TextField(verbose_name="توضیحات")
thumbnail = models.ImageField(
upload_to="imgpost", height_field=None, width_field=None, max_length=None, verbose_name="تصویر")
publish = models.DateTimeField(
default=timezone.now, verbose_name="زمان انتشار")
created = models.DateTimeField(
auto_now_add=True, verbose_name="زمان ایجاد")
updated = models.DateTimeField(
auto_now=True, verbose_name="زمان بروزرسانی")
status = models.CharField(
max_length=1, choices=STATUS_CHOICES, verbose_name="وضعیت")
def __str__(self):
return self.title
class Meta:
verbose_name = "پست"
verbose_name_plural = "پست ها"
objects = PostManager()
#template
{% for posts in categorys.postcat.published %}
<p>
posts.title
</p>
<p>
posts.description
</p>
{%endfor%}
The problem is that despite the filter I have set for not displaying draft posts, that post is not displayed in the category section. If you can help. my project in my github
{% for posts in categorys.postcat.published %}
<p>
{{ posts.title }}
</p>
<p>
{{ posts.description }}
</p>
{%endfor%}
try this!
We have to put this line of code in the model, the post class. It was a back fever.
objects = PostManager()

Django unable to iterate prefetch_related objects at template

I'm unable to access my prefetch_related objects at my template, can smb help
views.py
def support(request, pk=None):
...
else:
list_support_tickets = sorted(
chain(
SupportTickets.objects.filter(Q(status=0) | Q(status=1), requester=request.user).prefetch_related('reply_relation'), #Can't iter object
), key=attrgetter('creation_date'), reverse=True
)
paginator = Paginator(list_support_tickets, 10)
page = request.GET.get('page')
support_tickets = paginator.get_page(page)
args = {'support_tickets': support_tickets,
'form': form
}
print(list_support_tickets)
return render(request, template, args)
At my template I do the following:
{% for support_ticket in support_tickets %}
...
{% for reply in support_ticket.reply_relation %}
<span class="font-size-small">We have a query, yeah</span>
{% endfor %}
{% endfor %}
But I'm unable get a query here, error:
TypeError: 'GenericRelatedObjectManager' object is not iterable
models.py
class SupportTicketMessages(models.Model):
content_type = models.ForeignKey(ContentType, limit_choices_to=referential_models, on_delete=models.CASCADE)
object_id = models.CharField(max_length=36)
content_object = GenericForeignKey('content_type', 'object_id')
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
author = models.ForeignKey(User, on_delete=models.CASCADE, related_name='support_ticket_reply_author', verbose_name='Author', blank=True)
reply = models.TextField(verbose_name="Reply Content", max_length=2000)
date = models.DateTimeField(auto_now_add=True, blank=False)
class SupportTickets(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False, unique=True)
ticket_id = models.IntegerField(default=ticket_id_generator, unique=True, blank=False, null=False, editable=False)
requester = models.ForeignKey(User, on_delete=models.CASCADE, null=False, blank=False)
category = models.IntegerField(choices=TICKET_CATEGORY, verbose_name='Ticket Category')
subject = models.CharField(max_length=40)
problem_description = models.TextField(max_length=5000)
status = models.IntegerField(choices=STATUS_OF_TICKET, verbose_name='Ticket Status', default=0)
reply_relation = GenericRelation(SupportTicketMessages, related_query_name='reply_relation')
creation_date = models.DateTimeField(auto_now_add=True, null=True)
Thanks in advance
support_ticket.reply_relation is a manager, not a QuerySet, so you can not iterate over it, you use .all() [Django-doc] to iterate over this:
{% for support_ticket in support_tickets %}
…
{% for reply_relation in support_ticket.reply_relation.all %}
…
{% endfor %}
{% endfor %}

How to render data from multiple models django

I want to render data to my webpage from my django app however only two of the required slots are being rendered
my models are:
class Order(models.Model):
customer = models.ForeignKey(Customer, on_delete=models.SET_NULL, null=True, blank=True)
date_ordered = models.DateTimeField(auto_now_add=True)
complete = models.BooleanField(default=False)
transaction_id = models.CharField(max_length=100, null=True)
class OrderItem(models.Model):
product = models.ForeignKey(Product, on_delete=models.SET_NULL, null=True)
order = models.ForeignKey(Order, on_delete=models.SET_NULL, null=True)
quantity = models.IntegerField(default=0, null=True, blank=True)
date_added = models.DateTimeField(auto_now_add=True)
class Customer(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, null=True, blank=True)
name = models.CharField(max_length=200, null=True)
email = models.CharField(max_length=200, null=True)
class Product(models.Model):
name = models.CharField(max_length=200)
price = models.DecimalField(max_digits=7, decimal_places=2)
digital = models.BooleanField(default=False,null=True, blank=True)
image = models.ImageField(null=True , blank=True)
description = models.TextField(max_length=5000, null=True)
points = models.DecimalField(max_digits=5,decimal_places=0, null=True)
and my views are
def admin_dashboard (request):
order_list = Order.objects.all()
context = {'order':order_list}
template = "admin_dashboard.html"
return render(request, 'store/admin_dashboard.html', context)
my HTML is:
{% extends 'store/admin_main.html' %}
{% load static %}
{% block content %}
{% for order in order %}
<h6>{{ order.transaction_id }}</h6>
<p>{{ order.customer }}</p>
<p>{{ order.shippingaddress }}</p>
<p>{{ order.orderitem }}</p>
{% endfor%}
{% endblock content %}
1598061443.212917
userNew
which is just the transaction id and user.
how can I have all the rest of fields filled

Need to build a Django queryset based on more models

So what I say might seem complicated, but I think the answer is easy. I just can't figure it out. I have a form for a Lecture model, which a logged in teacher can use to post a lecture for his specific courses only. Thing is that in my database I have a TeacherData model which contains a teacher_ID field used for verification, so a teacher cannot create his account on the other Teacher model, if teacher_ID entered doesn't match. But when a course is created in database, the teacher used is the one from TeacherData. So to create my query I have to filter the courses based on TeacherData and then using teacher_ID, to link to Teacher model. I just don't know how to build this queryset but I replicated the wanted behaviour in the template:
{% if user.is_authenticated and user.is_teacher %}
<ul>
{% for data in teacher_data %}
{% if data.teacher_ID == user.teacher.teacher_ID %}
{% for course in courses %}
{% if course.teacher1 == data or course.teacher2 == data %}
<li>
{{ course.name }}
</li>
{% endif %}
{% endfor %}
{% endif %}
{% endfor %}
</ul>
{% endif %}
class Teacher(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True)
name = models.CharField(max_length=30, null=True, blank=True, default=None)
surname = models.CharField(max_length=50, null=True, blank=True, default=None)
email = models.EmailField(unique=True, null=True, blank=True, default=None)
teacher_ID = models.CharField(unique=True, max_length=14,
validators=[RegexValidator(regex='^.{14}$',
message='The ID needs to be 14 characters long.')],
null=True, blank=True, default=None)
class TeacherData(models.Model):
name = models.CharField(max_length=30)
surname = models.CharField(max_length=50)
teacher_ID = models.CharField(unique=True, max_length=14)
notes = models.CharField(max_length=255, default=None, blank=True)
class Lecture(models.Model):
LECTURE_CHOICES = (
('Courses', 'Courses'),
('Seminars', 'Seminars'),
)
course = models.ForeignKey('Course', on_delete=models.CASCADE, default='', related_name='lectures', )
lecture_category = models.CharField(max_length=10, choices=LECTURE_CHOICES, default='Courses', )
lecture_title = models.CharField(max_length=100, blank=True, null=True)
content = models.TextField(blank=False, default=None)
class Course(models.Model):
study_programme = models.ForeignKey('StudyProgramme', on_delete=models.CASCADE, default='')
name = models.CharField(max_length=50, unique=True)
ects = models.PositiveSmallIntegerField(validators=[MaxValueValidator(99)])
description = models.TextField()
year = models.PositiveSmallIntegerField(validators=[MaxValueValidator(99)])
semester = models.IntegerField(choices=((1, "1"),
(2, "2"),
), default=None)
teacher1 = models.ForeignKey('TeacherData', on_delete=models.CASCADE, default=None,
verbose_name="Course Teacher", related_name='%(class)s_course_teacher')
teacher2 = models.ForeignKey('TeacherData', on_delete=models.CASCADE, default=None, null=True,
verbose_name="Seminar Teacher", related_name='%(class)s_seminar_teacher')
class LectureForm(forms.ModelForm):
lecture_title = forms.CharField(max_length=100, required=True)
course = forms.ModelChoiceField(initial=Course.objects.first(), queryset=Course.objects.filter(
Q(teacher1__id__in=[t.id for t in TeacherData.objects.filter(
teacher_ID__iexact=[t.teacher_ID for t in Teacher.objects.all()])])))
class Meta:
model = Lecture
fields = ('course', 'lecture_category', 'lecture_title', 'content')
try this,
from django.contrib.auth.decorators import permission_required
from .models import Teacher
#permission_required( # permission class to check 'is_authenticated' and 'is_teacher')
def my_view(request):
queryset = Teacher.objects.filter(teacher_ID=request.user.teacher_ID)
if queryset:
# do something with teacher data ('queryset' holds those data)
else:
return HttpResponse("teacher id not found")

Display only creator's files - Django/Python

I would like to display only the pictures uploaded by the creator (user) on their individual profiles.
How would I alter my code to display that?
Thank you!
models.py:
class Photo(models.Model):
creator = models.ForeignKey(MyUser, null=False, blank=False)
category = models.ForeignKey("Category", default=1, null=True, blank=True)
title = models.CharField(max_length=30, null=True, blank=True)
description = models.TextField(max_length=120, null=True, blank=True)
image = models.ImageField(upload_to='user/photos/', null=True, blank=True)
slug = models.SlugField(null=False, blank=False)
active = models.BooleanField(default=True)
timestamp = models.DateTimeField(auto_now_add=True, auto_now=False, null=True)
updated = models.DateTimeField(auto_now_add=False, auto_now=True, null=True)
class Meta:
unique_together = ('slug', 'category')
ordering = ['-timestamp']
def __unicode__(self):
return "%s" %(self.creator)
def get_image_url(self):
return "%s/%s" %(settings.MEDIA_URL, self.image)
def get_absolute_url(self):
return "%s/%s" %(self.creator, self.slug)
views.py:
#login_required
def account_home(request, username):
try:
u = MyUser.objects.get(username=username)
except:
u = None
photo_set = Photo.objects.all()
context = {
"photo_set": photo_set,
"notifications": notifications,
"transactions": transactions
}
return render(request, "accounts/account_home.html", context)
.html:
{% for photo in photo_set %}
<img src="{{ photo.get_image_url }}" class='img-responsive'>
<hr/>
{% endfor %}
You have a ForeignKey to user, so you can just filter the photos by that:
photo_set = Photo.objects.filter(creator=u)
or even better use the reverse relationship:
photo_set = u.photo_set.all()
Also, never ever ever ever use a blank except statement in your code. The only exception you are expecting the get to raise is MyUser.DoesNotExist, so you should catch that only.

Categories

Resources