Django Class Based Views keep url parameters in session - python

I have a django listview working fine.
Its receive url parameters to filter data.
Its paginated.
Now, I want to maintain these data along the user session. (page number and url parameters).
Example:
I'm in the products list view.
I search for 'foo'
I select page 2
And then, I click in any product detail.
The page will redirect to detail view.
When I return to product list view, I whant to keep the search argument 'foo' and selected page 2.
What is the better way to do this?
I'm using Django 2.0.6
Models.py
class Product(models.Model):
name= models.CharField(_('name'), max_length=150)
price = models.DecimalField(max_digits=10, decimal_places=2, default=0.0)
Views.py
class ProductList(ListView):
model = Product
paginated_by = 10
def get_queryset(self):
queryset = Product.objects.all()
name = self.request.GET.get('name', None)
if name:
queryset = queryset.filter(name__icontains=name)
return queryset
Urls.py
path('products/', views.ProductList.as_view(), name='product_list'),

For this you have to put the URL as a get request so that you can fetch the get values form the URL and use them in your filter to maintain your selection like:
url/?variable=value
Then in your Django view, you can access this by request.GET.get('variable') and pass this as the context in your HTML render page then use that variable in your filter selection.
Setting variable in session:
For setting the variable in the session you can set it by:
request.session['variable'] = 'value'
and this value can be retrieve by:
if 'variable' in request.session:
variable1 = request.session['variable']
You can refer this docs.

One common trick I use to do this is to use GET parameters and save directly the entire url in session (it saves time compared to saving each individual parameter individually)
class ProductList(ListView):
model = Product
paginated_by = 10
def get_queryset(self):
self.request.session['saved_product_list_url'] = self.request.get_full_path()
....
Then you can use it like this in templates :
product list
Or like this in views :
saved_product_list_url = self.request.session.get('saved_product_list_url')
if saved_product_list_url:
return redirect(saved_product_list_url)
else:
return redirect('product_list')
Also in your filter form you should add a "reset filters" like this :
reset filters

Related

Creating new model instance through views.py including args through a url

I am trying to create a new model instance every time a url is accessed. so far, I have the function working in my views.py, but when the new model instance is created, the fields are empty (because I have not specified what I'd like in those fields in views.)
views.py
def session_invent(self):
session = Session() # I can add field data in here, but I want to get it via the URL
session.save()
messages.success(self, f'session invented!')
return redirect('blog-home')
urls.py
path('session/invent/', views.session_invent, name="session-invent"),
models.py
class Session(models.Model):
uid = models.CharField(max_length=50)
cid = models.CharField(max_length=50)
qid = models.CharField(max_length=50)
aid = models.CharField(max_length=50)
session_date = models.DateTimeField(auto_now_add=True)
def qid_plus_aid(self):
return '{}_{}'.format(self.qid, self.aid)
def __str__(self):
return self.uid
def get_absolute_url(self):
return reverse('session-detail', kwargs={'pk': self.pk})
Ok, so here is what i am trying to pull off:
right now if i enter mywebsite.com/session/invent/ a new Session model instance is created with empty fields. Is there a way I can fill in those fields with args in the URL? For example, something like...
mywebsite.com/session/invent/?uid=test_uid&cid=test_cid&qid=test_qid&aid=test_aid
Finished Answered code:
From the answer below here is how the updated views.py should look:
def session_invent(request):
session = Session.objects.create(
uid=request.GET['uid'],
cid=request.GET['cid'],
qid=request.GET['qid'],
aid=request.GET['aid']
)
messages.success(request, f'session invented from URL!')
return redirect('blog-home')
So, If I enter the following URL, a new record is created in my database with the values in each field set from the URL:
mywebsite.com/session/invent/?uid=test_uid&cid=test_cid&qid=test_qid&aid=test_aidz
Yes, the parameters are stored in the querystring, and you can use request.GET for a dictionary-like representation of the querystring, so:
def session_invent(request):
session = Session.objects.create(
uid=request.GET['uid'],
cid=request.GET['cid'],
qid=request.GET['qid'],
aid=request.GET['aid']
)
messages.success(request, f'session invented!')
return redirect('blog-home')
This will raise a HTTP 500 in case one of the keys is missing in the request.GET. You can use request.GET.get(…) [Django-doc] to access an element with an optional default value.
A GET request is however not supposed to have side effects. It is furthermore quite odd for a POST request to have a querystring.

Returning a filter result in a different page - Django

I've searched up but nothing seams to do the trick or be on point.
Let's say i have two websites on page A.html I have a filter (djnago_filter) and B.html is empty. If the user submits the search form he is redirected from page A.html to page B.html where the results are displayed with for loop.
How do I to that?
I was thinking about passing the data from query set to another view but there must be better solution to this.
There are several ways to store and display information on the different views(pages):
You could use the Sessions:
#views.py
#set the session key in the view A:
request.session['info'] = {'key', 'value'}
#get the session key in the view B:
info = request.session['info']
del request.session['info']
You could use Models with JSONField:
#app/models.py
#model to store information from page A
from django.contrib.auth.models import User
class MyModel(models.Model):
user = models.ForeignKey(User,
on_delete=models.DELETE,
related_name="info")
info = models.JSONField()
#views.py
#store data in the view A:
from app.models import MyModel
MyModel.objects.create(user=request.user, info={'key', 'value'})
#retrieve data in the view B:
info = MyModel.objects.get(user=request.user)
But actually, all depends on the logic that you intent to achieve. There are actually other methods like using async Ajax, React, WebSockets...
you can pass it as an HTML request parameter inside the url, for example, in your pageA template will be
to page B
and inside pageb view, you can take the filter from the request object
def page_b_view(request):
some_filter = request.GET.get('some_filter')

How to redirect from a CreateView of model A to another CreateView of a model B while passing key information from model A to the next view?

I am new to Django and do not know what I need to know to do this task. I am tasked with creating a web app that has two models. Model A is the employee and model B is a company that contains many employees. During signup, I have a form for model A. Once model A form is filled out, I need to pass an id from the employee to the company signup url so that when I save the company model to the table, I can make sure that the employee id is stored and so the two tables are related. How do I go about sending the employee_id to the company form page? Do I need to use some sort of redirect?
Flow: dashboard/employee_signup -> dashboard/company_signup -> completed_signup
I've looked through multiple tutorials on Django and most seem to be too simple to solve what I need done.
Here is my EmployeeSignUpView. Right now it redirects to a 'login' page. I need to instead redirect to a CompanySignUpView while passing along an employee_id. A company can't have zero employees, so the first person to signup for the company needs to be stored in the company model. The company table includes a column that stores a list of employees in that company. So a OneToMany relationship.
class EmployeeSignUpView(CreateView):
form_class = FSPEmployeeCreationForm
success_url = reverse_lazy('login')
template_name = 'employee_signup.html'
You redirect to something like
reverse('b:create_b', kwargs={"pk":a.pk}
The URL (in app 'b') is something like
url(r'create/(?P<pk>\d+)/$', b_create.as_view(), name='create_b'),
And you can pick up this parsed pk and convrt it into a full object by subclassing the dispatch method in b_create:
def dispatch( self, request, *a, **kw):
# resolve kwarg to self.a_object
self.a_object = get_object_or_404( A_model, pk = self.kwargs.get('pk','?') )
return super().dispatch( request, *a, **kw)
Doing this early means that the rest of your view code can everywhere reference self.a_object. It might be more efficient to do this only in post or form_valid, if it's not needed to (say) generate default values for the initial get of the form, or not needed until all the posted data is valid.
Instead of providing a static success_url, you can define get_success_url to return a URL that depends on the created object.
Assuming your CompanySignUpView has a URL as follows:
path('company_sign_up/<int:employee_id>/', views.CompanySignUpView.as_view(), name='company_sign_up')
then you would do:
class EmployeeSignUpView(CreateView):
form_class = FSPEmployeeCreationForm
template_name = 'employee_signup.html'
def get_success_url(self):
return reverse('company_sign_up', kwargs={'employee_id': self.object.id})
Edit
In your CompanySignUpView you can get the employee ID in the form_valid method:
class CompanySignUpView(CreateView):
...
def form_valid(self, form):
form.instance.initial_employee_id = self.kwargs['employee_id'] # or whatever the field name is
return super().form_valid(form)

How to pass variable in url to Django List View

I have a Django generic List View that I want to filter based on the value entered into the URL.
For example, when someone enters mysite.com/defaults/41 I want the view to filter all of the values matching 41.
I have come accross a few ways of doing this with function based views, but not class based Django views.
I have tried:
views.py
class DefaultsListView(LoginRequiredMixin,ListView):
model = models.DefaultDMLSProcessParams
template_name = 'defaults_list.html'
login_url = 'login'
def get_queryset(self):
return models.DefaultDMLSProcessParams.objects.filter(device=self.kwargs[device])
urls.py
path('<int:device>', DefaultsListView.as_view(), name='Default_Listview'),
You are close, the self.kwargs is a dictionary that maps strings to the corresponding value extracted from the URL, so you need to use a string that contains 'device' here:
class DefaultsListView(LoginRequiredMixin,ListView):
model = models.DefaultDMLSProcessParams
template_name = 'defaults_list.html'
login_url = 'login'
def get_queryset(self):
return models.DefaultDMLSProcessParams.objects.filter(
device_id=self.kwargs['device']
)
It is probably better to use devide_id here, since then it is syntactically clear that we compare identifiers with identifiers.
It might also be more "idiomatic" to make a super() call, such that if you later add mixins, these can "pre-process" the get_queryset call:
class DefaultsListView(LoginRequiredMixin,ListView):
model = models.DefaultDMLSProcessParams
template_name = 'defaults_list.html'
login_url = 'login'
def get_queryset(self):
return super(DefaultsListView, self).get_queryset().filter(
device_id=self.kwargs['device']
)

How do I use DateDetailView with a slug to render a page with a single article?

I am new to Django, and I am trying to have a separate page where I can view individual articles. Currently I have:
#views.py
class ArticleView(DateDetailView):
template_name = 'blog/article.html'
model = Article
date_field = "pub_date"
#I am not sure which one to use
slug_field = "unique_url_suffix"
slug_url_kwarg = 'unique_url_suffix'
and
#urls.py
urlpatterns = [
url(r'^(index\.html)?$',views.IndexView.as_view(),name='index'),
url(r'^(?P<year>[0-9]{4})/(?P<month>[-\w]+)/(?P<day>[0-9]+)/(?P<slug>[-\w]+)/$',
views.ArticleView.as_view(),
name="article_detail"),
]
and in index.html inside a loop of objects from the Article class:
<h2>{{article.title}}</h2>
I have also tried manually inputting the arguments, like this:
<h2>{{article.title}}</h2>
I keep on getting a "NoReverseMatch at /blog/" error. What am I doing incorrectly?
Edit: On top of the changes recommended for the answer, there was a typo causing problems. It does not affect the answer below, though.
First off, you should not be generating this URL in your template. You should define a get_absolute_url method in your Article model that looks like this:
from django.core.urlresolvers import reverse
def get_absolute_url(self):
# Note - you have to supply each of the date components separately
# because you need to match the URL regex.
return reverse (
'blog:article_detail',
kwargs={'year': self.pub_date.strftime("%Y"), 'month': self.pub_date.strftime("%b"),
'day': self.pub_date.strftime("%d"), 'slug': self.unique_url_suffix}
)
And then in your template:
<h2>{{article.title}}</h2>

Categories