How to use Django slugs creatively - django

In my frontpage.html. I have two buttons that link to the different categories of products I have I was using a for loop to get the slug needed for the URL link In the button, but this causes issues because it renders two buttons for each category i created in the models. My question: Is there a way for Django to only use one of these category slugs so I can specifically pick which URL it will render? I attached a picture of the frontpage.html file notice the for loop I am using to get the category slug that is being used to render the correct detail page. a for loop won't work since i have multiple categories
HTML
{% for category in menu_categories %}
Get Started
{% endfor %}
models.py for categories
class Category(models.Model):
title = models.CharField(max_length=255)
slug = models.SlugField(max_length=255)
ordering = models.IntegerField(default=0)
Here is the models.py as well. I was thinking there should be a way to explicitly call a specific slug and not render both buttons right next to each other

Related

related items in loop creates many duplicate queries

Rendering a page gets really slow when related objects are requested in a template.
class Item(models.Model):
name = models.CharField(max_length=160)
...
class Box(models.Model):
...
items = models.ForeignKey(Item, on_delete=models.CASCADE, null=True)
#template
{% for item in items %}
{{ item.box_set.first }}
{{ item.box_set.latest }}
{% endfor %}
Debug toolbar shows there many duplicate queries.
Why is this happening? Is there a way to speed this up?
The Django ORM has to make a request to the database when accessing a related field unless it's already cached. The main ways of caching the related objects are via select_related and prefetch_related.
What you're trying to do is a bit more difficult; you're trying to get two specific items from a collection. You can use .annotate() and Subquery to pull singular fields from a related model. This would be useful if you just wanted to display single field from box, but if you need the whole box instance this won't work.

Django form validation/saving for a template with varying quantity and order of text, images, and forms

I am trying to create a Django app where a user (say a researcher or a teacher) can create content for other users (participants or students) where any given page may include any number of content items (such as surveys questions, text, and/or images), and these items can be arranged by the teacher in any order on a page.
I'm taking an approach similar to the last chapters (10-12) of the book Django by Example. The app from those chapters comes very close to giving an example of my case using an e-Learning platform app, but they only allow teachers to create Content like Text and Images, they do not allow teachers to create survey questions for students. Here is the general approach that I am following.
The book models content for text and images for a given page like so:
class Content(models.Model):
page = models.ForeignKey(Page, related_name='contents')
content_type = models.ForeignKey(ContentType,
limit_choices_to={'model__in':('text',
'image')})
object_id = models.PositiveIntegerField()
item = GenericForeignKey('content_type', 'object_id')
order = OrderField(blank=True, for_fields=['page'])
class Meta:
ordering = ['order']
class ItemBase(models.Model):
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
class Meta:
abstract = True
def render(self):
return render_to_string('courses/content/{}.html'.format(
self._meta.model_name), {'item': self})
class Text(ItemBase):
content = models.TextField()
class Image(ItemBase):
file = models.FileField(upload_to='images')
There's an interface for teachers to fill out and order this content for a page.
Content is rendered within a template like so:
<div class="page">
{% for content in page.contents.all %}
{% with item=content.item %}
<h2>{{ item.title }}</h2>
{{ item.render }}
{% endwith %}
{% endfor %}
</div>
And the html used in the render method for a Text Content is simply:
{{item.content|linebreaks|safe }}
I don't find it difficult to extend this with QuestionTypes that extend ItemBase (similar to Text and Image models), as well as creating a StudentAnswer model for storing answers in the database.
I would probably override ItemBase render and put it into the QuestionType model so that I could pass a StudentAnswer model form into the context for the QuestionType html file.
I could then just have the html that is rendered contain {{ form }} for simplicity sake, and we now have a question that acts like any other content item and can be ordered with all of the others. This assumes that the HTML that contains the content has a form tag that encompass all of the rendered content items.
My problem is handling the POST request in the view. I have no idea how to validate and save answers from multiple forms on any given single page generated in this way. Examples I find assume a consistent number of forms that you know by name and are of different types.
I've also played around with the idea of creating a single dynamically generated form, but the examples I've seen for that assume you will loop through the fields in the template and display them in order rather than my requirement that a teacher determines the order which may include text or images in-between questions.
Is there a way to create what I'm looking for or can someone point me in the right direction?

How to display multiple forms of a single model in Django templates?

I have this model Note:
class Note(models.Model):
category = models.ForeignKey(Category)
author = models.ForeignKey('auth.User')
title = models.CharField(max_length=40)
text = models.TextField()
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
And I want to display this form:
class NoteEditForm(forms.ModelForm):
class Meta:
model = Note
fields = ('title', 'text')
in a template, but I want it to appear for each existing Note object in the database (it has to be that way). I've done something like that but then I hardcoded the form, pointing to the edit view URL with each object pk as a parameter; but I'm sure it has to be a clearer way, just I haven't found it. Could you guys help me with that? Thanks!
The easiest way to do this is to use a formset (also see model formsets).
For your Note model and NoteEditForm you could do something like this. You'd usually put this wherever you've defined your NoteEditForm but it can go in another file, such as views.py.
from django.forms import modelformset_factory
NoteEditFormSet = modelformset_factory(Note, form=NoteEditForm)
Using NoteEditFormSet in a view and template is almost the same as using a regular form, but there are a few differences to be aware of if you want to do anything complicated so have a look at the docs (view and template). If that's not clear enough, add a few details of what you're trying to do in your view and template and I'll try to help.
By default the formset will use Note.objects.all() as its queryset, which is what you say you want, but you can change that (details are covered in the docs).
Update:
To save an individual Note with an AJAX request I would add a second view to handle those requests. So if your formset for all Notes is served by a view at /notes/, you could add a view to handle your AJAX request at /notes/<note_id>/ (obviously just an example, adjust to fit your URL structure).
Then your JS on the /notes/ page is responsible for serializing the data for a single note and making the request to /notes/<note_id>/ (remember the CSRF token).
The HTML inputs generated for the formset have their IDs prefixed with something like id_form-<number>- and there are hidden inputs containing Note primary keys which will let you work out which ID prefix applies to each note.
I would think about doing it like this
{% for note in Notequeryset %}
<form action={% url 'url_name_to_form' pk={{note.pk}} %}>
{{form.as_p}}
</form>
{% endfor %}
Let me know what you think

How to select a specific related element in Django?

I have a model called 'Projects'.
Projects can be featured. If they are, they will be displayed on the home page
(Projects.filter(is_featured=True))
Each project contains several slides. These slides can be featured (Slide.is_featured=True), and contain an Image model which contains the actual image.
In my home page, I would like to display a slideshow in which each slide contains the project name, and the image contained in the featured slide.
I did that by adding a method called 'featured_slide()' in my Project Model, but now I realize that I've been hitting on the DB every time, and I would like to improve that by using the 'select_related' statement.
How can I do that?
Optimally, I would like to have a field like 'featured_slide' to represent the featured slide.
I was thinking of doing something along these lines:
Projects.filter(is_featured=True).annotate(featured_slide='slides__is_featured=True').select_related(slides__image)
I know it can't be that simple (slides__is_featured is not a database field), but you get the idea.
If you want a slideshow of only those Slides that themselves are featured as well as being related to a featured Projects:
class Project(...):
name = models.CharField()
is_featured = models.BooleanField()
class Slide(...):
project = models.ForeignKey(Project)
is_featured = models.BooleanField()
image = models.ImageField()
to query the slides (using select_related to avoid unnecessary queries):
slides = Slide.select_related("project").filter(is_featured=True, project__is_featured=True)
and template:
<ul>
{% for slide in slides %}
<li><img src="{{ slide.image.url }} /><span class="caption">{{ slide.project.name }}</caption></li>
{% endfor %}
</ul>
EDIT:
If you want to lookup the reverse relationship (i.e. get all the slides for a project), by default you can do the following:
project = Project.objects.get(...)
project_slides = project.slide_set.all()
You add _set to the model name. You can make this more intuitive by adding a related_name attribute to the relationship:
class Slide(...):
project = models.ForeignKey(Project, related_name="slideshow_slides")
and now use:
project = Project.objects.get(...)
project.slideshow_slides.all()

How to use Django build-in comment framework on any template

I just begin to study Django build-in comments function. at first I think the comment template should work well on any page just with get_comment_form or render_comment_form .but now it really annoying when i add these code to a ordinary page. It doesn't work. maybe in a other word. I don't know how to specify the object to attached to when it come to a normal page. below is the detail message :
models.py
class Entry(models.Model):
title = models.CharField(max_length=250)
body = models.TextField()
pub_date = models.DateTimeField()
enable_comments = models.BooleanField()
urls.py
urlpatterns = patterns('',
url(r'^profile/','django.views.generic.simple.direct_to_template',{
'template' : 'admin_ryu_blog/profile.html'},name='profile'),
)
now i just want to using comment framework on template profile.html. what should i do ? you could regard profile.html as a blank page now. then you can add any code you want if you can get a comment form displayed with build-in comment framework.
btw I have tried the below method :
{% load comments %}
{% render_comment_form for profile %}
then it prompt a error message. the same traceback on my previous question .
click here!
You can't. The comments framework expects an object to reference.
But an easy solution that comes to mind is building a model that maps to URLs like so:
class CommentAnchor(models.Model):
path = models.CharField(max_length=256)
Build a context processor that builds these objects and adds them to all template context . Remember to add your context processor to your settings.TEMPLATE_CONTEXT_PROCESSORS, and remember to use RequestContext when rendering templates.
def CommentAnchorProcessor(request):
comment_anchor, created = CommentAnchor.objects.get_or_create(path=request.path)
return {
'comment_anchor': comment_anchor, # now, this is available in every template.
}
Now you can render comments via these new objects.
{% render_comment_form for comment_anchor %}