How to have 2 Models/Views/Templates on one Page in Django? - python

I know this has probably been asked a 1000 times but I still for the life of me can't find a decent answer. Reading tutorials, Stack and even looking at GitHub for examples - nothing is helping or even guiding me in the right direction.
I have 2 separate Models/Views/Templates which each work beautifully on their own URLS.
I want these Models/Views/Templates to work on a single URL ie
url(r'^$', 'chrometask.views.index', name='home'),
(ie my homepage.)
How??? This seems to be way overly complicated for such a simple ask.
here is my views.py
items = Task.objects.all()
form = TaskForm(request.POST or None)
task_list = Task.objects.order_by('priority')
context_dict = { 'Tasks' : task_list}
if form.is_valid():
save_it = form.save(commit=False)
save_it.save()
return HttpResponseRedirect('')
return render_to_response('home.html', #Don't know how to render 2 html files or add the context_dict
locals(),
context_instance=RequestContext(request))
render_to_resonse can only take 3 arguments, and when I put the table inside 'home.html' with {% blockquote %} it wont show on the page.
<div class="collapsible-header"><i class="mdi-hardware-laptop-"></i>Title</a></div>
<div class="collapsible-body">
<div class="intro grey lighten-5">
{% block content %}{% endblock %} <--This is the table.html, which extends fine with {% entends 'home.html' %}-->
</br>
Please don't direct me to tutorials, These haven't resolved the issue, I would rather you spelt it out in layman's terms if possible, this may help drill the answer into my thick skull.
note - I am New to Django.
(*apologies for the frankness - this is really beginning to drive me up the wall)

You haven't said what you have tried to do to solve this, why you think it's "way overly complicated", or why it's causing you frustration.
The thing to understand is that a view is entirely responsible for a page, ie the view creates the entire response when a URL is requested. You can't have two views on a URL; that simply doesn't make sense.
But the other thing to understand is that templates and models are not in any way connected to any particular view. One view can render any number of templates, one, many, or even none; and any of those templates can involve any number of models from any number of apps.
So, if you wanted to include tasks in your home page, one approach is just to include the Tasks in the context dictionary in your view, and include the relevant code to your template to display them.
Now, if you're doing this in multiple views, then clearly you want to put that code somewhere sensible so that you Don't Repeat Yourself. The ideal place for this is an inclusion tag: you can wrap up the code that queries the latest tasks, and the template fragment that renders them, into a single tag which you can then use on your home page template.
Edit
The context is the second argument to render_to_response: the place where you've currently put locals(). That's a horrible pattern which I hate, and which is confusing you unnecessarily. Instead of using locals, put all the things you require for the context specifically into context_dict and pass that there instead.
(Also note you should use the render shortcut rather than render_to_response, which accepts the request as the first parameter and doesn't need all that mucking around with RequestContext.)
context_dict = { 'Tasks' : task_list, 'form': form}
...
return render(request, 'home.html', context_dict)
The code you have posted for your template is confusing. Is the table in table.html or home.html? If you pass "home.html" in your call to render, then it's home.html that will be rendered, not table. If you want to render table so that it extends home, then pass "table.html" in your call to render.

My Code ended up looking like
def home(request):
items = Task.objects.all()
form = TaskForm(request.POST or None)
task_list = Task.objects.order_by('priority')
context_dict = { 'Tasks' : task_list, 'form': form}
if form.is_valid():
save_it = form.save()
save_it.save()
return HttpResponseRedirect('')
return render(request, 'table.html', context_dict)
This has both models workig in one view.

def tutlist(request,tut):
model = Tutorial
model = Codetut
template_name = 'backpages/tutorial.html'
temp = Parts.objects.get(pk = tut)
model = temp.tutorial_set.all()
print(model)
temp = Parts.objects.get(pk = tut)
code = temp.codetut_set.all()
print(code)
context = {'model' : model ,'something': code}
return render(request, template_name,context)
i was having a similar problem i wanted to display two different views on a single template with a single url so i did something like this which worked well for me.

Related

Django - add context to request to be used by the view

Using Django I want to implement some middleware that will calculate some context that is to be used by the view itself.
For example, I have a middleware that looks at the request, and adds the user's permissions to the request, or some user configuration. The view looks at these permissions and decides how to handle the request using it.
This saves the need for multiple views (and multiple parts within the view) to query for this information.
I'm wondering what is the correct way to do that. One option is to just add request.user_permissions=... directly on the request. But is there some documented and expected way to do that?
There's no real documented way to do that, but Middleware is the correct place to do it and just adding properties to the request object is also the correct way.
You can confirm this, because Django is already doing it:
LocaleMiddelware
AuthenticationMiddleware
RemoteUserMiddleware
CurrentSiteMiddleware
SessionMiddleware
So just pick whatever is the most convenient data structure for your use case and tack that on to the request object.
This is not a perfect answer but at my experience I use this code. Every permission is saved in a boolean value which is true or false. You can access it in a html template like.
{% if request.user.is_admin %}
"Your code here"
{% else %}
"Your code here"
{% endif %}
and to send extra context you should create and pass an dicionary and pass it as as an argument to the render method from the view.
For eg:
def view(request, slug):
context = {'administrator':True}
blog_post = get_object_or_404(BlogPost, slug=slug)
context['blog_post'] = blog_post
return render(request, 'blog/detail_blog.html', context)
and access it like
{% if context.administrator %}
"Your code here"
{% else %}
"Your code here"
{% endif %}
I believe, since your middleware will calculate context, it should be implemented as context processor.
https://docs.djangoproject.com/en/3.1/ref/templates/api/#using-requestcontext
https://docs.djangoproject.com/en/3.1/ref/templates/api/#writing-your-own-context-processors

Django_Filters and queryset

Hi guys I'm building a simple django website where the user can look for long play. The problem right now is that I can't figure out why the filter, built with the django_filters library, doesn't work.
If you type "Queen" in the search bar in the home you are redirected to the searches.html where are listed all the LPs by Queen (just 4). On the left there's a filter. If you type "kind" in the form and submit then you should just see the album "Kind of Magic". This doesn't work. And I think the problem is the queryset "sp":
class searchesView(TemplateView):
template_name = "search/searches.html"
def post(self, request, *args, **kwargs):
print('FORM POSTED WITH {}'.format(request.POST['srh']))
srch = request.POST.get('srh')
if srch:
sp = Info.objects.filter(Q(band__icontains=srch)) | Info.objects.filter(Q(disco__icontains=srch))
myFilter = InfoFilter(request.GET, queryset=sp)
sp = myFilter.qs
paginator = Paginator(sp, 10)
page_number = request.GET.get('page')
page_obj = paginator.get_page(page_number)
return render(self.request, 'search/searches.html', {'sp':sp, 'myFilter':myFilter,
'page_obj': page_obj
})
else:
return render(self.request, 'search/searches.html')
I think the problem is the queryset because then I tried to build a result.html page where I listed all the LPs in the database and applied the same filter above and here it works perfectly:
def result(request):
result = Info.objects.all()
myFilter = InfoFilter(request.GET, queryset=result)
result = myFilter.qs
return render (request, 'search/result.html', {'result':result, 'myFilter':myFilter})
The difference is that in the first case I've got a TemplateView with a certain queryset, and in the second case I've got a simple function with a different queryset. Someone know what the problem could be? I uploaded to code on repl if you want to try out the website: https://Django-Template.edwardradical.repl.co
Thanks a lot!
Issue has to do with the mix of POST/GET here.
You are reading parameters out of both post/get dictionaries here, which is not a great pattern to go down.
In this case, a POST request to the url with the filters should yield the correct results ie:
POST /searches/?band=kind&disco=
{
srh: data
}
In current solution, I believe the srh is not included in the post body, which causes issue in queryset.

merging a view with template view django

I want that the landing page of my homepage is a form with an input and the user puts in stuff. So I followed a couple of tutorials and now I have this:
views.py:
def create2(request):
if request.method =='POST':
form = LocationForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect('')
else:
form = LocationForm()
args = {}
args.update(csrf(request))
args['form'] = form
return render_to_response('location/index.html', args)
and in my urls.py:
url(r'^$', 'core.views.create2'),
which works perfectly fine, if I go to 127.0.0.1:8000 I get to index.html and when put in something in the input it gets saved in the database. However, the old part of my homepage looks like this
class LandingView(TemplateView):
model = Location
template_name="location/index.html"
def search
...
and the urls.py:
url(r'^$', core.views.LandingView.as_view(), name='index'),
which has a function search I So my question is, is there a way how I can merge the def create2 into my LandingView. I tried several things, but I am always ending up having the index.html without the input field. I also tried
def create2
...
def search
...
but didn't work.
Does anyone know how to merge that together?
EDIT
Thank you the working solution looks like this now
class Create(CreateView):
model = coremodels.Location
template_name = 'location/test.html'
fields = ['title']
def form_valid(self, form):
form.save()
return HttpResponseRedirect('')
return super(Create, self).form_valid(form)
Depending on the results you are looking for, there are multiple ways to solve this:
1. Use CreateView and UpdateView
Django already provides some classes that render a form for your model, submit it using POST, and re-render the form with errors if form validation was not successful.
Check the generic editing views documentation.
2. Override get_context_data
In LandingView, override TemplateView's get_context_data method, so that your context includes the form you are creating in create2.
3. Use FormView
If you still want to use your own defined form instead of the model form that CreateView and UpdateView generate for you, you can use FormView, which is pretty much the same as TemplateView except it also handles your form submission/errors automatically.
In any case, you can keep your search function inside the class-based view and call it from get_context_data to include its results in the template's context.

django-forms-builder. How do I update a form?

I am using django-forms-builder in my project and there is just one thing i cant get my head around. How do i set up an update form to edit a filled out form?
Here is my attempt at making an update form for django-forms-builder
urls.py
url('forms/update/(?P<pk>\d+)/$', FormUpdateView.as_view(),
name='form-update'),
views.py
class FormUpdateView(UpdateView):
model = FieldEntry
template_name = 'form/update_form.html'
form_class = FormForForm
success_url = '/assessments/all/'
update-form.py
{% render_built_form id=form_instance.id %}
I haven't used this software yet but it could fill a spot in my arsenal so I took a stab at it. I'm not using CBV because I'm still just poking around. This is the get part only, I can expand on how to handle the post part (and preferably do it with CBV) on the weekend. It's relatively straightforward to implement post with view functions (if request.METHOD == "POST":#update the row). The render is of course just plain raw HTML but forms_builder doesn't offer any styling input. You probably want to tack the user onto the FormEntry, I don't have a good idea about authorization yet. I'll give it some thought and amend the answer.
views.py
from forms_builder.forms.models import Form
def get_form(request, slug, pk):
form_obj = Form.objects.get(slug=slug)
form_instance = form_obj.entries.get(pk=pk)
form = FormForForm(form=form_obj, instance=form_instance, context=request)
return render_to_response('update_form.html', {'form':form_instance.form, 'request':request})
templates/update_form.html
{{ form.as_p }}

Passing variables to templates in Django

I have seen similar questions and answers but none that address my problem.
I want my view to perform a User Group check and then pass that via variable to the template. The template will then use that to appear differently to different user groups.
My views.py:
def cans(request):
is_canner = request.user.groups.filter(name='canner') #check if user group = canner
can_list = Can.objects.order_by('name')
context = {'can_list': can_list}
return render(request, 'cans/cans.html', context) #need to return is_canner variable here
And in my template I would use the variable like so:
{% if is_canner %} canner stuff goes here {% endif %}
I'm unsure how to pass this variable, I thought it used context to send it like so:
return render(request, 'cans/cans.html', context({"is_canner": is_canner}))
But this gives me errors - context is not callable.
context is not a function, its an argument to the render function, e.g.
context = {"is_canner": is_canner}
return render(request, 'cans/cans.html', context)
docs: https://docs.djangoproject.com/en/dev/topics/http/shortcuts/#render
more background info: Django - what is the difference between render(), render_to_response() and direct_to_template()?

Categories

Resources