I run into problems while setting up a user profile for our application. Imagine a linkedIn-like user profile with basic information, work- and education positions.
the model (simplified)
class UserProfile(models.Model):
about_me = models.TextField(blank=True, null=True)
formatted_name = models.CharField(max_length=120, null=True, blank=True)
username_slug = models.SlugField(null=True, blank=True, unique=True)
location_name = models.CharField(max_length=120, null=True, blank=True)
...
class JobPosition(models.Model):
user_profile = models.ForeignKey(UserProfile)
company_name = models.CharField(max_length=150, null=True, blank=True)
title = models.CharField(max_length=150, null=True, blank=True)
job_description = models.CharField(max_length=1000, null=True, blank=True)
start_date = models.DateField(blank=True, null=True)
end_date = models.DateField(blank=True, null=True)
class Education(models.Model):
user_profile= models.ForeignKey(UserProfile)
degree = models.CharField(max_length=60, null=True, blank=True)
field_of_study = models.CharField(max_length=120, null=True, blank=True)
school_name = models.CharField(max_length=150, null=True, blank=True)
start_date = models.DateField(blank=True, null=True)
end_date = models.DateField(blank=True, null=True)
Ok so obviously a user can have 0-n work positions ans 0-n education positions.
forms.py
class BasicForm(ModelForm):
class Meta:
model = UserProfile
fields = ['id', 'about_me', 'linkedin_headline', 'location_name']
# enter code here
class EducationForm(ModelForm):
class Meta:
model = Education
fields = ['id', 'degree', 'field_of_study', 'school_name',
'start_date','end_date']
class WorkForm(ModelForm):
class Meta:
model = JobPosition
fields = ['id','company_name', 'title', 'job_description',
'start_date','end_date']
views.py
- I wanted to have everything in one function as I want to call no other URL. (see later in template). The user should be able to edit his positions on the site, click 'update' and get redirected back on the profile site.
- I tried applying the apporach of distinguishing the post income via the name of the update button as seen here: How can I build multiple submit buttons django form?
- it's currently not doing a lot of validation stuff
def detail(request, slug):
u = get_object_or_404(UserProfile, username_slug=slug)
#checking the request on Post
if request.method == 'POST':
# Battery of IF statements to determine which form has been used
# if it's updating basic info
if 'updateBasic' in request.POST:
form = BasicForm(request.POST)
if form.is_valid():
form.save()
# if its a Work Position
if 'updateWork' in request.POST:
form = WorkForm(request.POST)
if form.is_valid():
form.save()
# ... same for education...
# if there is no POST request, then the profile is just called to be displayed
else:
basicForm = BasicForm()
educForm = EducationForm()
workForm = WorkForm()
#CSRF Token generation
c = {'user': u,
'years' : range( datetime.now().year, 1980, -1),
'months' : range( 1,13),
'basicForm': basicForm,
'educForm': educForm,
'workForm': workForm}
#CSRF Token generation
c.update(csrf(request))
return render(request, 'userprofile/detail.html', c)
The template:
Pretty straight forward. Looping over the work and education positions:
{% for work in user.positions %}
<div id="work{{ forloop.counter }}" class="row">
<div class="large-2 small-3 columns">
<h6> {{ work.end_date|date:'M Y'|default:"NOW" }}<br>{{ work.start_date|date:'M Y' }}</h6>
</div>
<div class="large-10 small-9 columns">
<h6>{{ work.title }}
<a class="show_hide editIcon" href="#" rel="#editWork{{ forloop.counter }} #work{{ forloop.counter }}" title="Edit"><i class="icon-edit pull-right editIcon icon-large"></i></a>
</h6>
<h6 class="dblue ">{{ work.company_name }}</h6>
{% if work.job_description %}
<p> {{ work.job_description}} </p>
{% endif %}
{% if not forloop.last %}
<hr>
{% endif %}
</div>
</div>
<div id="editWork{{ forloop.counter }}" style="display: none;" class="row editForm">
<div class="large-10 large-centered columns">
<h5>Edit</h5>
<form class="custom" action="#" method="post" name="WorkForm"> {% csrf_token %}
<div class="row">
<div class="large-6 columns">
<label for="company">Company:</label>
<input type="text" name="company" id="company" placeholder="Example Ltd" required value="{{ work.company_name }}"/>
</div>
<div class="large-6 columns">
<label for="title">Title:</label>
<input type="text" name="title" id="title" placeholder="Example position" required value="{{ work.title }}"/>
</div>
</div>
...
<div class="row">
<div class="large-12 columns">
<label for="desc">Description</label>
<textarea name="desc" id="desc" cols="40" rows="6" value="{{ edu.field_of_study_description }}"></textarea>
</div>
</div>
<div class="row">
<div class="large-2 small-3 columns">
<button class="tiny submit" type="submit" name="updateWork" title="Update this position" >update</button>
</div>
<div class="large-2 small-3 columns">
<button class="tiny submit" type="reset" title"Clear the form">Reset</button>
</div>
<div class="large-2 small-3 columns">
<a class="show_hide button tiny" href="#" rel="#editWork{{ forloop.counter }} #work{{ forloop.counter }}" title="Close the edit panel">Cancel</a>
</div>
<div class="large-3 columns">
<a class="button tiny secondary" href="#" title="Delete this position"> Delete</a>
</div>
</div>
</form>
</div>
</div>
{% endfor %}
So what I do:
I loop over all work positions and generate a div for editing this
exact position.
the div is shown when clicking on a 'edit Button' and javascript
kicks in to make the div visible (slides over the non-edit div)
The user should then be able to edit this exact position. click update and I call the detail action to handle the update request. (not yet implemented)
I do the same for education
I know the forms are not integrated yet. As I really have no idea how to do this in a proper way...
Questions
How can I properly display one of my modelforms for each position? (Formests are not really what I think I should use as they only allow a battery of forms rather then single instances)
how can I fill it with the corresponding value? (can that even be done at runtime or do I habe to make an array of forms filled with the values already in the view and then pass this array to the template?)
Am I in general on the right path? :)
Sorry for the lengthy post but I thought id rather give you as much info as possible so you can hopefully direct me the right way.
Already now lots of thanks in advance
Phil
Related
I am trying to manually render options for a select filed in a django template. When I submit the form I get an error: "Select a valid choice. That choice is not one of the available choices." The error message also asks for required fields which I have provided.
locations models.py
class Location(models.Model):
name = models.CharField(max_length=20)
is_source = models.BooleanField(default=False)
is_destination = models.BooleanField(default=False)
def __str__(self):
return self.name
orders models.py
class Order(models.Model):
order_number = models.IntegerField(unique=True)
order_date = models.DateField(auto_now_add=True)
type = models.CharField(max_length=15, choices=TYPES)
source = models.ForeignKey(Location, default=1, on_delete=models.SET_DEFAULT, related_name='ordered_here')
destination = models.ForeignKey(Location, default=1, on_delete=models.SET_DEFAULT, related_name='delivered_here')
items = models.TextField()
assigned_to = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, blank=True, on_delete=models.SET_NULL, related_name='orders_to_serve')
customer = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, blank=True, on_delete=models.SET_NULL, related_name='orders_made')
status = models.CharField(max_length=15, choices=STATUSES)
orders forms.py
class OrderForm(ModelForm):
source = forms.ModelChoiceField(queryset=Location.objects.filter(is_source=True))
destination = forms.ModelChoiceField(queryset=Location.objects.filter(is_destination=True))
class Meta:
model = Order
fields = ['source', 'destination', 'items']
def save(self, commit=True):
instance = super().save(commit=False)
instance.order_number = math.floor(time.time())
instance.type = 'Purchase'
instance.customer = self.context.get('request').user
instance.status = 'New'
if commit:
instance.save()
return instance
orders create.html
<form class="" method="POST">
{% csrf_token %}
<h1 class='text-center'>Make an order</h1>
<div class='row'>
<div class='col-md-6 px-2'>
<span class="fw-bold mx-2">Buy from</span>
<div class="control-container border-primary d-flex align-items-center">
<i class="fa fa-map"></i>
<select class="control ms-1 flex-grow-1" type="text" name="{{form.source.html_name}}" required >
{% for value,label in form.source.field.choices %}
<option value="{{value}}">{{label}}</option>
{% endfor %}
</select>
</div>
</div>
<div class='col-md-6 px-2'>
<span class="fw-bold mx-2">Receive in</span>
<div class="control-container border-primary d-flex align-items-center">
<i class="fa fa-map"></i>
<select class="control ms-1 flex-grow-1" type="text" name="{{form.destination.html_name}}" required >
{% for value,label in form.destination.field.choices %}
<option value="{{value}}">{{label}}</option>
{% endfor %}
</select>
</div>
</div>
</div>
<div class='row'>
<div class='col-12 px-2'>
<span class="fw-bold mx-2">List items (e.g. 2 X Luxaire Double Bed matress)</span>
<div class="control-container border-primary d-flex align-items-center">
<textarea class="control ms-1 flex-grow-1" rows="10" name="{{form.items.html_name}}" placeholder='e.g. 2 X Luxaire Double Bed matress' required></textarea>
</div>
</div>
</div>
<button type="submit" class="btn btn-primary w-100 ">Order</button>
</form>
orders view.py
class OrderUpdateView(generic.edit.UpdateView):
model = Order
template_name = 'orders/update.html'
context_object_name = 'order'
form_class = OrderForm
I have eventually solved the problem by making the customer field in the order model nullable. I also had given my textarea in the order create template a wrong field name. All is well now.
you cannot do this even if you managed to make the form ignore this error the model will raise the same error elso because you just tell him to select a value from given values ... if you wanna make it dynammic then make it as noraml CharFied()
I have a view complaints page where a user can view the complaints he/she have submitted. When the user clicks on one of the cards, I need a new page to open where the user can view the details of that complaint and edit it as well.
It should go from here:
to here: Where they can view details and make changes as well:
This is my models.py:
class Complaint(models.Model):
user = models.ForeignKey(User, on_delete= models.CASCADE, null = True, blank=True)
id = models.AutoField(blank=False, primary_key=True)
reportnumber = models.CharField(max_length=500 ,null = True, blank= False)
eventdate = models.DateField(null=True, blank=False)
event_type = models.CharField(max_length=300, null=True, blank=True)
device_problem = models.CharField(max_length=300, null=True, blank=True)
manufacturer = models.CharField(max_length=300, null=True, blank=True)
product_code = models.CharField(max_length=300, null=True, blank=True)
brand_name = models.CharField(max_length = 300, null=True, blank=True)
exemption = models.CharField(max_length=300, null=True, blank=True)
patient_problem = models.CharField(max_length=500, null=True, blank=True)
event_text = models.TextField(null=True, blank= True)
document = models.FileField(upload_to='static/documents', blank=True, null=True)
def __str__(self):
return self.reportnumber
views.py:
def EditComplaints(request):
complaint = request.user.complaint
form = ComplaintForm(instance=complaint)
if request.method == 'POST':
form = ComplaintForm(request.POST, request.FILES, instance=complaint)
if form.is_valid():
form.save()
context = {'form': form}
return render(request, 'newcomplaint.html', context)
template (the view history page):
<div class="col right-pro-con">
<div class="img-cir">
<form method='POST' action="" enctype="multipart/form-data">
{% csrf_token %} {% if request.user.profile.profile_pic.url %}
<img src={{request.user.profile.profile_pic.url}} alt="" width="100px" height="100px" class="pro-img"> {% else %}
<img src="{% static 'profileimages/msi.jpg' %}" alt="" width="100px" height="100px" class="pro-img"> {% endif %}
<p class="my-name">{{request.user.profile.first}}
<p>
<p class="my-email-id">{{request.user.profile.email}}</p>
</form>
</div>
CONTACT US
</div>
template(edit complaint page):
<div class="col-lg middle middle-complaint-con">
<i class="fas fa-folder-open fa-4x comp-folder-icon"></i>
<h1 class="all-comp">New Complaint</h1>
<form class="" action="" method="POST" enctype="multipart/form-data">
{% csrf_token %}
<p class="sub-typ-wr">Submit Type</p>
<button type="button" class="btn btn-secondary document-btn">Document</button>
<div class="rep-num">
<label class="written-label" for="">Report Number</label>
<div class="written-txt-field">{{form.reportnumber}}</div>
</div>
<div class="eve-dte">
<label class="written-label" for="">Event Date</label>
<div class="written-txt-field">{{form.eventdate}}</div>
</div>
<div class="eve-typ">
<label class="written-label" for="">Event Type</label>
<div class="written-txt-field">{{form.event_type}}</div>
</div>
<div class="dev-pro">
<label class="written-label" for="">Device Problem</label>
<div class="written-txt-field">{{form.device_problem}}</div>
</div>
<label class="written-label eve-txt" for="">Event Text</label>
<div class="Manufacturer">
<label class="written-label" for="">Manufacturer</label>
<div class="written-txt-field">{{form.manufacturer}}</div>
</div>
<div class="pro-code">
<label class="written-label" for="">Product Code</label>
<div class="written-txt-field">{{form.product_code}}</div>
</div>
<div class="brand-name">
<label class="written-label" for="">Brand Name</label>
<div class="written-txt-field">{{form.brand_name}}</div>
</div>
<div class="exem">
<label class="written-label" for="">Exemption</label>
<div class="written-txt-field">{{form.exemption}}</div>
</div>
<div class="pat-pro">
<label class="written-label" for="">Patient Problem</label>
<div class="written-txt-field">{{form.patient_problem}}</div>
</div>
<div class="comp-textarea">{{form.event_text}}</div>
<button type="button" class="btn btn-secondary attach-btn-1"><div class="fas fa-file-upload">{{form.document}}</div></button>
<button type="submit" name="submit" class="btn btn-secondary save-btn-1"><i class="fas fa-save"></i> Save</button>
</form>
</div>
url:
urlpatterns = [
path('admin/', admin.site.urls),
path('Home/', landing_page.views1.landing, name= 'Home'),
path('Registration/', accounts.views.RegisterPage),
path('Login/', accounts.views.LoginPage, name='Login'),
path('Login/Profile/', accounts.views.profile, name='Profile'),
path('Logout/', accounts.views.LogoutUser, name='Logout'),
path('Login/Add-Complaint/', accounts.views.NewComplaint, name = 'New'),
path('Login/Add-Complaint/Document-Style/', accounts.views.DocComplaint, name='doc'),
path('My-History/', accounts.views.History, name='MyHistory'),
path('Complaint/', accounts.views.EditComplaints, name='Complaint')
]
How do I do this? What should I add in the code for the code to open that particular complaints details and for that complaints page to edit?
okay, so you already have a view. What you need is some sort of unique identifier to help you figure out the actual object that the user wants to edit.
So, in your urls.py you will have to add a pattern similar to:
urlpatterns = [
...
path('complain/<int:pk>/edit/', views.EditComplaint.as_view(), name='edit-complain'),
...
]
Inside your views.py, handle it in a manner something similar to:
from django.views.generics import UpdateView
from django.contrib.auth.mixins import UserPassesTestMixin
from django.http import Http404
from django.utils.translation import gettext_lazy as _
from .models import Complaint
class EditComplaint(UserPassesTestMixin, UpdateView):
model = Complaint
fields = ('info', ) # define whatever field that you want to render
def form_valid(self, form):
# do your form validation here
def test_func(self):
"""ensuring the reporter themselves is updating the complain"""
complain = self.get_object()
if self.request.user == complain.user:
return True
raise Http404(_('This complain does not exist'))
def success_url(self):
# this is only required if your model doesn't have a `get_absolute_url` method
# return the actual url of the instance
All you need now is to add a link inside your template for the EditComplaint view(assuming you already have the list of donations inside your list template as donations).
Something along the lines should do the job
{% for complaint in complaints %}
Edit Complaint
{% endfor %}
I am learning django. I am working on a blog. When user reply to a comment it is showing time of its parent comment. It should show actual time of reply. I attached a picture with this post.Please have a look , you will better understand my question. How can I fix? I tried but all in vain. may be it is a silly mistake from me or i am not getting it. Thanks in advance
view.py
def blogPost(request, slug):
post = Post.objects.filter(slug=slug).first()
comments = BlogComment.objects.filter(post=post, parent=None)
replies = BlogComment.objects.filter(post=post).exclude(parent=None)
replyDict = {}
for reply in replies:
if reply.parent.sno not in replyDict.keys():
replyDict[reply.parent.sno] = [reply]
else:
replyDict[reply.parent.sno].append(reply)
context = {'post':post, 'comments':comments, 'user': request.user, 'replyDict': replyDict}
return render(request, 'blog/blogPost.html',context)
def postComments(request):
if request.method == 'POST':
comment = request.POST.get('comment')
user = request.user
postSno = request.POST.get('postSno')
post = Post.objects.get(sno=postSno)
parentSno = request.POST.get('parentSno')
if parentSno == "":
comments = BlogComment(comment=comment, user=user, post=post)
comments.save()
messages.success(request, 'Your Comment has been posted Successfully')
else:
parent = BlogComment.objects.get(sno=parentSno)
comments = BlogComment(comment=comment, user=user, post=post, parent=parent)
comments.save()
messages.success(request, 'Your reply has been posted Successfully')
return redirect(f"/blog/{post.slug}")
models.py
class Post(models.Model):
sno = models.AutoField(primary_key=True)
title = models.CharField(max_length=200)
content = models.TextField(max_length=10000)
author = models.CharField(max_length=20)
region = models.CharField(max_length=20)
slug = models.CharField(max_length=50, default="")
timestamp = models.DateTimeField(blank=True)
thumbnail = models.ImageField(upload_to="images", default="")
def __str__(self):
return self.title + 'by' + self.author
class BlogComment(models.Model):
sno = models.AutoField(primary_key=True)
comment = models.TextField()
user = models.ForeignKey(User, on_delete=models.CASCADE)
post = models.ForeignKey(Post, on_delete=models.CASCADE)
parent = models.ForeignKey('self', on_delete=models.CASCADE, null=True) #it is pointing the value of blogcomment so we use 'self'
timestamp = models.DateTimeField(default=now)
replytimestamp = models.DateTimeField(default=now)
def __str__(self):
return self.comment[0:10] + "..." + "by " + self.user.username
blogPost.html
{% for comment in comments %}
<div class="row border border-dark mx-0 my-3">
<div class="col-md-1"><img src="/media/images/usr.png" height="55px" width="55px"></div>
<div class="col-md-11"><b> {{comment.user.username}} </b>
<span class="badge badge-secondary">{{comment.timestamp | naturaltime}}</span>
<!--this will show time in 2 hours ago or x hour ago like-->
<div>
<p class="font-italic">{{comment.comment}}</p>
</div>
<div class="reply mx-0">
<p>
{% if user.is_authenticated %}
<button class="btn btn-primary btn-sm" type="button" data-toggle="collapse"
data-target="#replyBox{{comment.sno}}" aria-expanded="false" aria-controls="collapseExample">
reply
</button>
</p>
<div class="collapse" id="replyBox{{comment.sno}}">
<div class="card card-body mb-2">
<form action="/blog/postComments" method="POST">{% csrf_token %}
<div class="form-group">
<label for="comment">Post a Reply</label>
<input type="text" class="form-control" id="comment" name="comment"
placeholder="Write a reply Here">
<input type="hidden" name="parentSno" value="{{comment.sno}}">
</div>
<input type="hidden" name="postSno" value="{{post.sno}}">
<button type="submit" class="btn btn-primary">Submit</button>
</form>
</div>
</div>
{% endif %}
<div class="replies my-2">
{% for reply in replyDict|get_val:comment.sno %}
<!-- this will return replies associated with comment.sno in the replyDict[] -->
<div class="row my-2">
<div class="col-md-1"><img src="/media/images/usr.png" height="35px" width="35px"></div>
<div class="col-md-11">
<b> {{comment.user.username}} </b><span
class="badge badge-secondary">{{comment.timestamp | naturaltime}}</span>
<div>{{reply.comment}}</div>
</div>
<br>
</div>
{% endfor %}
</div>
</div>
</div>
</div>
{% endfor %}
</div>
{% endblock %}
commentand reply pictures
My template
{% for follow in my_followers %}
<div class="col s12 m8 offset-m2 l6 offset-l3">
<div class="card-panel grey lighten-5 z-depth-1">
<div class="row valign-wrapper">
<div class="col s2">
<img src="{{user.appUser_set.all.0.avatar.url}}" alt="" class="circle responsive-img">
<!-- notice the "circle" class -->
</div>
<div class="col s10">
<span class="black-text">
{{follow }} <br>
</span>
</div>
</div>
</div>
</div>
{% endfor %}
my views
def followers(request):
a = appUsers.objects.get(users=request.user)
my_followers = a.follow_people.all()
my_obj = appUsers.objects.all()
return render(request, 'parsifal_users/followers.html', {'my_followers': my_followers, 'my_obj': my_obj})
My models:
class appUsers(models.Model):
users = models.OneToOneField(User, on_delete=models.CASCADE)
profile_url = models.URLField()
location = models.CharField(max_length=100)
institution = models.CharField(max_length=100)
avatar = models.ImageField(
default='default.jpg', upload_to='profile_pics')
follow_people = models.ManyToManyField(
User, related_name='followed_by', blank=True)
def __str__(self):
return self.users.username
Now how could i get display pictures of all the followers in this template any ideas or suggestions for the query?Thanks in advance!!
PS:I am a begineer ,please also suggest some good reference and some good projects so that i could practice django successfully.
Coming from Angular, this was easy to do, but I am not sure where to begin on creating a dropdown form that will filter from a list of objects. Basically, I have the code below, that will pull in and display all real estate listings; I would like to create a dropdown that will have 2 selections, 'Featured' and 'New Listing' and when a user selects one, the list will filter out and display only those listings that match. Thank you for your help.
Here is my model
from django.db import models
from django.utils import timezone
class Listing(models.Model):
FAIR = 'FAIR'
GOOD = 'GOOD'
VERY_GOOD = 'VERY_GOOD'
EXCELLENT = 'EXCELLENT'
NEW_LISTING = 'NEW_LISTING'
PRICE_REDUCED = 'PRICE_REDUCED'
UNDER_AGREEMENT = 'UNDER_AGREEMENT'
SOLD = 'SOLD'
YES = 'YES'
NO = 'NO'
FULL_SERVICE = 'FULL_SERVICE'
FOR_LEASE = 'FOR_LEASE'
WITH_REAL = 'WITH_REAL'
QUICK_SERVE = 'QUICK_SERVE'
CONDITION_CHOICES = (
('FAIR', 'Fair'),
('GOOD', 'Good'),
('VERY_GOOD', 'Very Good'),
('EXCELLENT', 'Excellent'),
)
STATUS_CHOICES = (
('NEW_LISTING', 'New Listing'),
('PRICE_REDUCED', 'Price Reduced'),
('UNDER_AGREEMENT', 'Under Agreement'),
('SOLD', 'Sold'),
)
FEATURED_CHOICES = (
('YES', 'Yes'),
('NO', 'No'),
)
LOCATION_TYPE = (
('FULL_SERVICE', 'Full Service'),
('FOR_LEASE', 'For Lease'),
('WITH_REAL', 'With Real'),
('QUICK_SERVE', 'Quick Serve'),
)
photo = models.ImageField(upload_to="media/properties/", max_length=250, blank=True, null=True)
broker = models.ForeignKey('auth.User')
phone = models.CharField(max_length=20, null=True)
title = models.CharField(max_length=250, null=True)
description = models.TextField(null=True)
concept = models.CharField(max_length=250, null=True)
location = models.CharField(max_length=250, null=True)
size = models.CharField(max_length=250, null=True)
seating = models.CharField(max_length=250, null=True)
condition_choices = models.CharField(max_length=20, choices=CONDITION_CHOICES, blank=True)
hours = models.CharField(max_length=250, null=True)
asking_price = models.CharField(max_length=250, null=True)
sales_price = models.CharField(max_length=250, null=True)
rent_price = models.CharField(max_length=250, null=True)
lease_terms = models.CharField(max_length=250, null=True)
licenses = models.CharField(max_length=250, null=True)
parking = models.CharField(max_length=250, null=True)
status_choices = models.CharField(max_length=20, choices=STATUS_CHOICES, blank=True, null=True)
featured_choices = models.CharField(max_length=5, choices=FEATURED_CHOICES, blank=True, null=True)
location_type = models.CharField(max_length=20, choices=LOCATION_TYPE, blank=True, null=True)
created_date = models.DateTimeField(default=timezone.now, null=True)
published_date = models.DateTimeField(default=timezone.now, null=True)
listing_order = models.PositiveIntegerField(default=0, blank=False, null=False)
class Meta(object):
ordering = ('listing_order',)
def publish(self):
"""This is a docstring"""
self.published_date = timezone.now()
self.save()
def __str__(self):
return self.title
And here is my template
{% extends "listing/base.html" %}{% load staticfiles %}
{% block content %}
<section class="listings mt64 mb64">
<div class="container">
{% for listing in listings %}
<div class="row">
<div class="col-md-4">
<div class="listings-photo" style="background: #ccc url('{{ MEDIA_URL }}{{ listing.photo.name }}')no-repeat 50% 50%; background-size: cover; width: 350px; height: 220px"></div>
</div>
<div class="col-md-8">
<h3 class="uppercase">{{ listing.title }}</h3>
<p><span class="listings-title">Description:</span> {{ listing.description }}</p>
<div class="row">
<div class="col-md-6">
<ul>
<li><span class="listings-title">Concept:</span> {{ listing.concept }}</li>
<li><span class="listings-title">Location:</span> {{ listing.location }}</li>
<li><span class="listings-title">Size:</span> {{ listing.size }}</li>
<li><span class="listings-title">Seating:</span> {{ listing.seating }}</li>
<li><span class="listings-title">Condition:</span> {{ listing.condition_choices }}
</li>
<li><span class="listings-title">Hours:</span> {{ listing.hours }}</li>
</ul>
</div>
<div class="col-md-6">
<ul>
<li><span class="listings-title">Asking Price:</span> {{ listing.asking_price }}
</li>
<li><span class="listings-title">Sales:</span> {{ listing.sales_price }}</li>
<li><span class="listings-title">Rent:</span> {{ listing.rent_price }}</li>
<li><span class="listings-title">Lease Terms:</span> {{ listing.lease_terms }}</li>
<li><span class="listings-title">Licenses:</span> {{ listing.licenses }}</li>
<li><span class="listings-title">Parking:</span> {{ listing.parking }}</li>
</ul>
</div>
</div>
<p>For more information please contact {{ user.first_name }} {{ user.last_name }} at {{ listing.phone }}.</p>
</div>
</div>
{% endfor %}
</div>
</section>
{% endblock content %}
I can see what you mean coming from Angular. The most classical way of doing that in Django would be creating a form with all the fields you need, then passing it to the view to process the data, filter records and pass them back to the template. I'll try to provide a basic example so you can hopefully get the idea:
Index.html:
<form action="{% url 'index' %}" method="get">
<label for="featured">Format</label>
<select name="featured">
<option value="Yes" />Yes</option>
<option value="No" />No</option>
<input type="submit" name="featured" value="Filter" />
</form>
Views.py
def index(request, template_name='index.html'):
if request.GET.get('featured'):
featured_filter = request.GET.get('featured')
listings = Listing.objects.filter(featured_choices=featured_filter)
else:
listings = Listing.objects.all()
context_dict = {'listings': listings}
return render(request, template_name, context_dict)
This is pretty self-explanatory. If there's a "featured" parameter in GET, list will get filtered, otherwise it will pass all objects. Obviously we're looking at page refresh every filter request, if you expect a bit more of a one-page experience, you have to go for ajax and post requests, or something. Also, keep in mind this snippet is just a hard-coded example. Ideally, you would want to create a ModelForm class and instantiate that, then pass it to the template - a lot more readable and maintainable if you have more filter fields. If there's complex filtering involved, you would also probably want to have an additional view for filtering purposes, but this works too, it just gets messy really quick.
Thanks for Zephi, your tip helped me a lot, but for me, only worked after I changed index.html to this:
index.html
<form action="{% url 'index' %}" method="get">
<label for="featured">Format</label>
<select name="featured">
<option value="Yes" />Yes</option>
<option value="No" />No</option>
</select> <!-- ADDED THIS LINE -->
<input type="submit" value="Filter" /> <!-- DELETE name="featured" FROM ORIGINAL CODE -->
</form>
here fragments from my app's code:
index.html
<form action="{% url 'index' %}" method="get">
<label for="featured">Format</label>
<select name="featured">
{% for adoption in typeList %}
<option value="{{ adoption }}">{{ adoption }}</option>
{% endfor %}
</select>
<input type="submit" value="Filter" />
</form>
views.py
def index(request, template_name='index.html'):
if request.GET.get('featured'):
featured_filter = request.GET.get('featured')
query = Unit.listType.filter(unitType=featured_filter)
else:
query = Unit.listType.all()
typeList = query.order_by('unitType').values_list('unitType',flat=True).distinct()
_dict = {}
for x in range(len(typeList)):
_dict[typeList[x]] = typeList[x]
return render(request, 'index.html', {'query':query, 'typeList':_dict})