I dont know how to pass two queryset parameters into one URL - django

I really struggled to explain my problem and the only way I found it would be possible is - through screenshots as I have a lot of code and I am not sure what is really needed here. So if you want any code, tell me I will add.
The numbers on the pictures indicate the order.
Choosing the category
Selecting the category it redirects me to - /products_list?category=(that category_id)
Filtering through brand in that category
Now please pay attention to the URL and what happens after I have chosen the brand I want to filter with.
Back on the first page
Problem is here:
Now I am back on the first page, where are all the products but I wanted it to stay on that URL where are that kind of category products.
What I wanted to happen? Instead of it taking me to the page where are ALL the products and then doing the filtering, I want it to stay on that category page and return the filtered products there.
The brand dropdown menu also should only show that category products that I am in, not all.

You need to pass the other parameters as well. So that means that for two parameters category_id and brand, you create a URL that looks like:
{% url 'product-list' %}?category={{ category_id|urlencode }}&brand={{ brand|urlencode }}
If you thus already filtered the category down, you pass the category_id to the template, and render the URLs with the ?category={{ category_id|urlencode }} part.

Related

Django - Field by Field Restrictions on Which Users Can view Certain Fields

I'm learning Django and building a simple CRUD application. I have a model for cars, and this contains a number of fields. When a user loads a car page, I'd like some fields to be displayed and others hidden, depending on whether the user has a high enough score for the car they are viewing. So for each field (engine, wheels, headlights, etc), or for some groups of fields, there would be a corresponding visibility score. If the user's score for that particular car exceeded the visibility for a particular field, then the data for that field would be displayed in the view.
I could add a DecimalField variable for each component to denote this minimum score, the Car model would have a calc_score(user) method. In the view the current user's score would be compared against each of these, but I'm guessing there may be a better way to do this. Can anyone recommend a better approach?
Thank you.
You should just pass in the user's score as context when rendering the page from your views.py. It would look something like this:
def car_page_view(request):
current_user_score = getUserScore()
context = {
'user_score': current_user_score
}
return render(request, 'car-page.html', context)
Then, in your html, put a check like this to only show certain elements:
{% if user_score > 10 %}
<text>This text is only visible to users with scores higher than 10.</text>
{% endif %}
This is better than, say, loading all html elements and setting certain elements to "hidden". Instead, this causes the html you want hidden to never be loaded at all. So even if they use the inspect tool they won't see it :)

Filtering a queryset across a foreign key, using a parameter e.g. as argument from the view

I'm trying to build a flexible queryset that gives a result size based on parameters I use, but currently I'm only accessing that data from across a foreign key. Here's the setup.
My first table is a set of "blog posts" - the model is pretty self explanatory:
class BlogPost(models.Model):
title = models.CharField(max_length=100)
dateStamp = models.DateTimeField(auto_now_add=True)
post = models.TextField()
The second is a table that holds all the images for all the posts in a one-to-many relationship:
class BlogImageSeqFilter(models.Manager):
def get_querySet(self):
## slice the first three images with sequence between 1 and 3
return self.filter(sequence__gte=1, sequence__lte=3)[:3]
class BlogImage(models.Model):
blog = models.ForeignKey(BlogPost, null=True, on_delete=models.SET_NULL)
img = models.ImageField(upload_to=imgFolder, blank=True)
sequence = models.IntegerField(null=False, blank=False, default=0)
objects = BlogImageSeqFilter() ## Custom Manager class BlogImageSeqFilter
(The manager method comes in a little later in my question - I don't even know if using it has been the right approach so far...)
In my view, the set of blog posts is included contextually in the rendering of the html tmeplate:
def blogPage(request, proj):
## Limit to the newest 5 posts
blogs = project.blogpost_set.all().order_by("-dateStamp")[:5]
return render(request, 'blog/blogPage.html', {"blogs":blogs})
So in my template, I am displaying each blog post in a separate container, and including the set of images relevant to that blog using blogimage_set. A simplification of what I've got so far would be:
{% for post in blogs %}
<div>
{{post.title}}
{{post.post}}
{% for image in post.blogimage_set.get_querySet %}
<img src="yada yada {{image.img}} yada yada></img>
{% endfor %}
</div>
{% endfor %}
Now, what I am stuck on. I want to change the model and the view, so that I can pass an argument somehow to limit the number of items in each post (as I understand it you can't really pass arguments from the template backwards, unless you start faffing with custom template tags which I don't want to do in this case because I'm sure there is a better way of doing it, and I want to learn that way.)
I want something flexible enough that I could re-use the blog images somewhere else, using a different parameter to represent the number of images returned. But it's not as simple as "Give me the first x images in the table".
Say I upload 10 images, I will assign them all sequence #s from 1-10 (hence the 'sequence' field in the model). But that sequence might not be in the same order that I uploaded. So overall I want to be able to choose in a given view which x images from the set of 10 will appear on that blog post. "Give me images between seq #1 and #3" or "Give me 5 images starting from seq #4" or something.
My first incremental attempt towards achieving this functionality was to create the BlogImageSeqFilter Manager and its method which gives a limited queryset of three items having sequence between 1 and 3.
Changing the model (or rather the Manager/its method) to accept an argument seems like the simple bit. But what I can't figure out is how to modify the view and the template to use parameters, in such a way that I can include "blogImages" in the render's context while still displaying them in the template as shown above ("for each post in the given blog ...do some html and... for each x images for that post...do some more html").
I appreciate that changing up the images displayed in a conventional "blog post" after the initial posting isn't a context that makes much sense - but as mentioned I want that flexibility to maybe use elsewhere, or reuse the code for something else at a later date. And I have a feeling I'm stuck because of a knowledge/skill gap or a wider problem with the way I'm currently working, so might as well identify it here.
I think you're overcomplicating things a bit. If you want to control how many images you display in a particular context, you can just slice the image queryset, at the point of use.
So in your template you would do something like this to render the first three images:
{% for image in post.blogimage_set.all|slice:":3" %}
<img src="yada yada {{image.img}} yada yada></img>
{% endfor %}
Note that querysets are lazy, so this will only fetch the first three images from your database.
If somewhere else you want to use more/fewer images, you just slice the queryset differently. I don't think you need a custom model manager to achieve this.

url with multiple optional arguments

right now I have a view to show info about some tickets and I'm trying to add a functionality to filter those tickets.
Say I will have 4 filters:
Date
Owner
Category
Status
Category Status
I want to give the option to use some of those filters, all or none, the thing is I'm kinda lost in how can I make it work in the urls. So far I found that you can add some optional arguments but they appear in some sort of succession like:
/May/Jack/Gas/Accepted
But if I only select 2 filters like /Jack/Accepted/ it grabs the filters incorrectly.
Is there a way I can achieve this? Or some other method I can use instead of this. Ty
Don't try and do this with URL arguments. Instead, use querystring arguments. The URL should be in the form:
my_path/?date=May&owner=Jack&category=Gas&status=accepted
and the URL pattern is just:
url(r'^my_path/$', views.my_view, 'my_url'),
and in the view you can access request.GET['date'] etc.

django form with multiple choice field with potentially infinite choices

I have a model with a many-to-many field that will expand as the user adds more entries for the model. In the form template if I use the conventional {{ form.field }} I get a multiple choice select as is expected, but the problem that will quickly become apparent is when there are 10, 100, 1000 or more choices. What I'd like to provide in the form is a search field where the user can search through all available entries and via AJAX return entries matching their search criteria where they can then select the individual entry choices to be saved in the database.
I'm assuming I will have to manually render the multiple choice form field, but after hours of research I cannot find an example of this anywhere online. Is there an example that exists and I just haven't been able to find? How is one supposed to manually create a form with a multiple choice field in Django? Or am I going about this all wrong?

Google Charts - Multiple Category Filters - Restricting options?

I have 3 suppliers, 40 brands and 120 products, all displayed in three category filters. When a user selects one supplier from the Supplier filter, I want the Brand filter to hide all brands that are not provided by that supplier. Likewise, when a brand is selected, I want to hide the irrelevant products from the Products filter. I don't really care about what's being shown in the table at this point.
Is there any way to implement something like this?
Heres an example for you -
http://jsfiddle.net/danabnormal/cjn2tbbm
You can do this by creating a Dashboard. At around line 61 you can see that the selection made in the 'Sex' drop down is bound to the 'Name' dropdown, thus limiting what Names can be selected.
dashboard.bind(filterSex, filterName);
dashboard.bind(filterSex, pieChart);