Search Field in Django Python - python

First, I have to say that is this my first application in Django. So my knowledge is still limited.
I have this home page where it shows all the data in my model. The model name is "Asset".
I am trying to have a search field inside the home page.
models.py
class Asset(models.Model):
asset_desc = models.CharField(max_length=120, null=False)
BEIRUT = 'Beirut'
SAIDA = 'Saida'
HALBA = "Halba"
base_choice = ((SAIDA, "Saida"), (BEIRUT, "Beirut"), (HALBA, "Halba"))
asset_base = models.CharField(max_length=120, null=False, choices=base_choice)
created_date = models.DateField(auto_now_add=True)
update_date = models.DateTimeField(auto_now=True)
asset_user = models.CharField(max_length=120, blank=True)
slug = models.SlugField()
def save(self, *args, **kwargs):
self.slug = slugify(self.asset_desc)
super(Asset, self).save(*args, **kwargs)
def __str__(self):
return self.asset_desc
views.py
def search_asset(request):
if 'q' in request.GET and request.GET['q']:
q = request.GET['q']
assets = Asset.objects.filter(asset_desc__icontains=q)
context = {'desc': assets}
return render(request, 'home.html', context)
html for the search field:
<form method="GET" class="navbar-form navbar-right">
<input type="text" class="form-control" placeholder="Search..."id="search_box" name="q">
urls.py
url(r'^search/$', "asset.views.search_asset", name="home")
Please any help on why it is not showing the result. I am using Django 1.9.

some corrections:
you dont need null=False for TextField() and CharField(), since they never save Null to database but empty string. so you can remove null=False
the search url name is home which logically not really approriate. it should be changed to search or search_view and then you can refer to it via url tag:
action="{% url 'search' %}"
this is useful if someone should look over your code. "Readability counts" ;)
and finally, put this to your home.html (actually you must already have it)
{% for asset in desc %}
<div>
{{ asset.asset_desc }} <br>
{{ asset.base_choice }} <br>
{{ asset.asset_user }}
</div>
{% endfor %}
I hope, this helps

You have not provided the template or the HTML portion where you list the results. You should consider the name of you context variable, but by following your name, you should list the results like this:
{% for asset in desc %}
<div>
{{ asset }}
</div>
{% endfor %}
Anything else looks correct.
Hope it helps

Related

Django - Auto populating Many-To-Many-Field relation

I am trying to make a form that auto populates a many-to-many relation for my user model. The goal is to have a submit button that adds the views instance object (the SingelWorkout object) to a many-to-many field relation within my user model.
The view accurately displays the correct object, and the form appears as intended within the template. I do not wish for the user to see the many-to-many field selection. Aside from the submit button, I am trying to have all logic to occur on the backend. How would I assign an object instance to a field within a form? Would this occur in the views.py or the forms.py?
Here is why my user model looks like:
class FitnessUser(AbstractUser):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
email = models.EmailField(max_length=60)
age_category = models.ForeignKey(
AgeGroup,
on_delete=models.CASCADE,
blank=True,
null=True
)
goal = models.IntegerField(default=1 ,choices=Purpose.choices)
weight = models.CharField(max_length=30)
height = models.CharField(max_length=30)
gender = models.ForeignKey(
Gender,
on_delete=models.CASCADE,
blank=True,
null=True
)
exercise_frequency = models.IntegerField(default=1 ,choices=Frequency.choices)
template_id = models.ForeignKey(
Workout_template,
on_delete=models.CASCADE,
blank=True,
null=True
)
completed_workouts = models.ManyToManyField(SingleWorkout)
def get_absolute_url(self):
return reverse('detail', args=[self.id])
This is my form in forms.py:
class CustomWorkoutChangeForm(UserChangeForm):
class Meta(UserChangeForm):
model = FitnessUser
fields = ('completed_workouts',)
exclude = ('completed_workouts',)
UserChangeForm.password = None
This is how my view looks:
class WorkoutUpdateView(LoginRequiredMixin, UpdateView):
model = SingleWorkout
template_name = 'workout/daily_view.html'
form_class = CustomWorkoutChangeForm
success_url = reverse_lazy("template")
def get_context_data(self, **kwargs):
context = super(WorkoutUpdateView, self).get_context_data(**kwargs)
context['workout'] = SingleWorkout.objects.get(slug = self.kwargs['slug'])
return context
My html template looks like this:
{{workout}}
<br>
workout:
<br>
{{ workout.exercise_1 }}
<br>
{{ workout.description_1 }}
<form method="POST">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Confirm">
</form>
Figured out a solution. I created a view that gets the instance object based on the objects url slug, and also gets the user by its pk. From there is adds the instance object to the users many to many field, then redirects back to the previous page.
New view created:
def update_workout_data(request, slug):
workout = SingleWorkout.objects.get(slug=slug)
endUser = FitnessUser.objects.get(pk = request.user.pk)
endUser.completed_workouts.add(workout)
endUser.save()
return redirect(reverse('daily', kwargs={'slug':workout.slug}))
Updated HTML appearance. I've also altered the html and its detail view so that the update link will redirect to a separate update view, depending on the need to add/remove the relation.
{% block content %}
Daily View
<br>
{{exercise}}
<br>
workout:
<br>
<br>
{% if exercise.name in workouts %}
<h5>Workout Already Completed</h5>
<form method="POST" action="{% url 'remove' slug=exercise.slug %}">
{% csrf_token %}
<button type="submit">Reset</button>
</form>
{% else %}
<form method="POST" action="{% url 'update' slug=exercise.slug %}">
{% csrf_token %}
<button type="submit">Complete</button>
</form>
{% endif %}
{% endblock content %}
Updated Detail View
def get_context_data(self, **kwargs):
context = super(WorkoutDetailView, self).get_context_data(**kwargs)
user = FitnessUser.objects.get(pk = self.request.user.pk)
context['exercise'] = SingleWorkout.objects.get(slug = self.kwargs['slug'])
context['workouts'] = {}
for workout in user.completed_workouts.all():
context['workouts'][workout.name] = workout
return context

Django - Can't access data from object in many to many relationship

In my Django project, I am trying to create a website that streams TV shows. Each show belongs in many categories, hence the use of many to many relations in my model. What I want to do with a certain page on my website is dynamically load a page of shows belonging to a specific category. However, all of my attempts have ended in failure as I am unable to figure out a way on how to access the actual category data from each show.
In views.py
def shows_in_category(request, category_slug):
category = get_object_or_404(Category, slug=category_slug)
showsall = theShow.objects.all()
shows = []
for show in showsall:
print(show.category.name, category.name)
if show.category.name == category.name:
shows.append(show)
print(shows)
return render(request, 'show/show_list_view.html', {'category':category, 'shows': shows})
In models.py
class Category(models.Model):
name = models.CharField(max_length=255, db_index=True)
slug = models.SlugField(max_length=255, unique=True)
class Meta:
verbose_name_plural = 'Categories'
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse("theshowapp:shows_in_category", args=[self.slug])
class theShow(models.Model):
english_name = models.CharField(max_length=400)
show_type = models.CharField(max_length=200, blank=True)
is_active = models.BooleanField(default=False)
category = models.ManyToManyField(Category)
slug = models.SlugField(max_length=400,unique=True)
class Meta:
verbose_name_plural = 'Shows Series'
def __str__(self):
return self.english_name
In the template (show_list_view.html)
{% for show in shows %}
<script> console.log("I'm trying to get in")</script>
<script> console.log("{{ show.name }} {{show.category.name}}")</script>
<script> console.log("I'm in")</script>
<div class="row">
<div class="col-lg-4 col-md-6 col-sm-6">
<div class="product__item">
<div class="product__item__text">
<ul>
{% for genre in show.category %}
<li>{{ show.category }}</li>
{% endfor %}
</ul>
<h5>{{ show.english_name }}</h5>
</div>
</div>
</div>
</div>
{% endfor %}
Any insight on this matter would be much appreciated.
What you're doing here violates some of the best practices of Django and also isn't using the Django ORM to its full potential. Please replace the lines
showsall = animeShow.objects.all()
shows = []
for show in showsall:
print(show.category.name, category.name)
if show.category.name == category.name:
shows.append(show)
print(shows)
with
shows = animeShow.objects.filter(category__name=category.name)
Also in the template change <li>{{ show.category }}</li> to <li>{{ genre }}</li> since that's the iterating variable.
I read up a bit more on the many to many fields examples in Django's documentation and figured out that I should use this:
shows = animeShow.objects.all().filter(category__name=category)

Display aggregated sum in django html template using Model and Views

I have created a model.py as below
class overallAccountDetail(models.Model):
accountId = models.IntegerField(primary_key=True, unique=False, blank=False,
auto_created=True, null=False,
editable=False)
accountName = models.CharField(max_length=100)
countryName = models.CharField(max_length=100)
marketName = models.CharField(max_length=100)
Alarm_Count = models.CharField(max_length=255,default='',blank=True)
TT_Count = models.CharField ( max_length=255 , default='' , blank=True )
Views.py
def displayAlarmCount(request):
totalAlarmCount=overallAccountDetail.objects.filter(marketName='Market1', accountName= 'Account1').aggregate(Sum('Alarm_Count')).values()
ctx = {
'totalAlarmCount': totalAlarmCount
}
return render_to_response('overallaccountdetail_filter.html', ctx, context_instance=RequestContext(request))
In HTML template
{% block content %}
<form method="get">
{{ filter.form.as_p }}
<button type="submit">Search</button>
</form>
filter.qs.totalAlarmCount<br>
totalAlarmCount
<p><strong>Total Alarm_Count:</strong>{{totalAlarmCount}}</p>
<ul>
{% for overallAccountDetail in filter.qs %}
<li>{{ overallAccountDetail.Alarm_Count }}</li>
{% endfor %}
</ul>
Now the issue is when i am executing the below query in shell, i am getting the sum of all alarm count of Account1 corresponding to Market 1. But when i am displaying same on html .. it is showing nothing. Please advise what's the problem in my code. The below query shows the exact value in shell that i want to present on the webpage
totalAlarmCount=overallAccountDetail.objects.filter(marketName='Market1',
accountName= 'Account1').aggregate(Sum('Alarm_Count')).values()
HI your query returns dict value of decimal like dict_values([Decimal('308617')])
totalAlarmCount=overallAccountDetail.objects.filter(marketName='Market1',
accountName= 'Account1').aggregate(Sum('Alarm_Count')).values()
So you can change your below like that,
sum_count=overallAccountDetail.objects.filter(marketName='Market1',
accountName= 'Account1').aggregate(Sum('Alarm_Count'))
totalAlarmCount = sum_count['Alarm_Count__sum']
return render(request, 'overallaccountdetail_filter', {'totalAlarmCount': totalAlarmCount})
Django promotes the separation of concerns means filtering data should be performed in py file (in your case, same method written above) or in model class. It's still not clear what's filter object in your template from where qs is being fetched? If you can provide that detail then I would be able to help.

Django QuerySet in template for relational models

I am trying to setup a relation with another model using FK in django but I can't call FK related model fields in django templates. In template when I call "provider.name" it shows me "None" as result. I do have 5 different suppliers listed and can see from admin. I have providers and I got products like below:
class Product(models.Model):
title = models.CharField(max_length=500)
description = models.TextField(blank=True, null=True)
price = models.DecimalField(max_digits=20, decimal_places=2)
sku = models.CharField(null=True, max_length=100)
url = models.URLField(blank=True)
slug = models.SlugField(unique=True)
providers = models.ManyToManyField('Provider', blank=True)
def __unicode__(self):
return self.title
class Provider(models.Model):
name = models.CharField(max_length=200)
description = models.TextField(null=True, blank=True)
logo = models.ImageField(upload_to='products/')
shipping_method = models.CharField(max_length=250)
shipping_time = models.CharField(max_length=250)
return_policy = models.CharField(max_length=200)
free_delivery = models.CharField(max_length=200)
customer_service_number = models.CharField(max_length=200)
shipping_charges = models.CharField(max_length=200)
def __unicode__(self):
return self.name
In template the way I am calling it is:
{% with provider=object.providers %}
{{ provider.name }}
{% endwith %}
As result it shows "None". I am trying to call provider in a different template. In it's own List/Detail generic views it works just fine. I am trying to call it in different app templates. Please advise.
Update................
My search.html for whoosh search engine includes
{% for result in page.object_list %}
<div class="col-lg-1-5 col-md-3 col-sm-4 col-xs-12">
<div class="pbox">
<div class="photo">
<img src="{{ result.object.get_image_url }}" alt="product">
</div>
<div class="info">
<div class="url">
name
{% for item in result.object.providers.all %}
{{ result.provider.name }}
{% endfor %}
</div>
<div class="description">
{{ result.object.description|truncatewords:7 }}
</div>
<div class="price">
{{ result.object.price|intcomma }}
</div>
</div>
</div>
</div>
As I am not using any ModelManager or just using default Managers pre-defined for models. I've added a line of code under Product App model like this:
def get_provider(self):
item = self.providers.all()
return item
I case of calling provider you call related manager so it return None because manager have no method like this.
If you want to retrieve objects from managers, you should call self.providers.all()
In your case, template tags should looks like this:
{% for item in object.providers.all %}
{{ provider.name }}
{% endfor %}

Django: Check that row exists in list

I want to check that user_id exists in the profile_images table from my Django template.
My Model
class profiles(models.Model):
profile_id = models.AutoField(primary_key=True)
user = models.ForeignKey(User)
-----
class Profile_images(models.Model):
id = models.AutoField(primary_key=True)
user = models.ForeignKey(User)
image = models.ImageField(upload_to='uploads/',default = 'uploads/no-img.jpg')
My View
def view_profiles(request):
if request.user.is_authenticated():
view_all_profiles = profiles.objects.all()
profile_image = Profile_images.objects.all()
return render_to_response('profiles/all.html', {'profiles':view_all_profiles,'profile_image':profile_image}, context_instance=RequestContext(request),)
else:
return HttpResponseRedirect('/accounts/login/')
My Template
{% for profile in profiles %}
<li>
{% for image in profile_image %}
{% ifequal image.user_id profile.user_id %}
<img src="{{MEDIA_URL}}{{image.image}}" alt="image" />
{% endifequal %}
<!-- i want to check here if not user_id exist in profile_images table -->
{% if profile.user_id not in profile_image %}
<img src="{% static 'images/no-image.jpg' %}" alt="image" />
{% endif %}
{% endfor %}
</li>
{% endfor %}
{% if profile.user_id not in profile_image %} is not working. I'm new to Django & python and I'm stuck here. Please suggest better ways if my code is not correct.
in your view you could get all user_ids with a profile image, something like:
user_ids_with_profile_images = Profile_images.objects.all().values_list('user_id', flat=True)
Then in your template you could check if profile.user_id not in user_ids_with_profile_images.
It might actually be a little cleaner to loop through all the users with profiles in your system and get their profile images through the foreign key, instead of looping through all the profiles and trying to get the users...
This is really a design problem, you've got a separate model specifically for a profile image when that could just be a field on the profile model itself.
class Profile(models.Model): # convention is to use a non-plural name for models
# No need to explicitly set the primary key, this will be added automatically
# profile_id = models.AutoField(primary_key=True)
user = models.ForeignKey(User)
image = models.ImageField(upload_to='uploads/',default = 'uploads/no-img.jpg')
-----
Now it would just be a case of using {{ profile.image }} with no need for any additional looking up.

Categories