The problem is this:
I have two classes Posts and Pubs in models.py, I need them to be displayed simultaneously on the main page,
I have in views.py file:
def pubs_list(request):
publications = Pubs.objects.filter(published_date__lte=timezone.now()).order_by('published_date')
return render(request, 'app/pubs_list.html', {'publications': publications})
def posts_list(request):
posts = Posts.objects.filter(published_date__lte=timezone.now()).order_by('published_date')
return render(request, 'app/posts_list.html', {'posts': posts})
in urls.py:
path('', views.posts_list, name='posts_list'),
# path('', views.pubs_list, name='pubs_list'),
accordingly, if we uncomment the second condition, then the first will work.
The question is, is it possible to make 2 views have one path, or is it somehow necessary to register in the view? Thanks.
No, each URL can only be handled by one view.
For the example in your question, it would be straight forward to make a single view that fetches the posts and publications.
def pubs_and_posts(request):
publications = Pubs.objects.filter(published_date__lte=timezone.now()).order_by('published_date')
posts = Posts.objects.filter(published_date__lte=timezone.now()).order_by('published_date')
return render(request, 'app/pubs_.html', {'publications': publications, 'posts': posts})
You can use a unique view with both models:
urls.py
path('', views.posts_and_pubs, name='posts_and_pubs_list'),
views.py
def posts_and_pubs(request):
posts = Posts.objects.filter(published_date__lte=timezone.now()).order_by('published_date')
publications = Pubs.objects.filter(published_date__lte=timezone.now()).order_by('published_date')
return render(request, 'app/posts_list.html', {'posts': posts, 'publications': publications})
Related
I am Building a BlogApp and I implement a feature to count the views of Post. BUT views are not showing in post page in Browser.
What i am trying to do
I am trying to count the number of views which post will got whenever the user visits.
The Problem
Post views are not showing in post page in browser.
What have i tried
1). I also tried models.IntegerField BUT that didn't worked for me , because whenever user refresh the page then it increase one view everytime for single user.
2). I followed some tutorials BUT the all of them were on Class Based Views and I am using Function Based Views.
3). Then i thought of IP address BUT that also didn't worked for me because it wasn't working for my server.
Then i think of a ManyToManyField in views variable. BUT it also not working for me, I don't know where is the problem.
views.py
def detail_view(request,pk):
data = get_object_or_404(BlogPost,pk=pk)
queryset = BlogPost.objects.order_by('viewers')
context = {'queryset':queryset,'data':data}
return render(request, 'mains/show_more.html', context )
models.py
class BloPost(models.Model):
post_owner = models.ForeignKey(User,default='',null=True,on_delete = models.CASCADE)
date_added = models
viewers = models.ManyToManyField(settings.AUTH_USER_MODEL,related_name='viewed_posts',editable=False)
show_more.html
1). This is showing auth.User.None
{{ data.viewers }}
2). This is showing all the posts.
{{ queryset }}
I don't what am i doing wrong.
Any help would be appreciated.
Thank You in Advance.
You should annotate your queryset, so:
from django.db.models import Count
def detail_view(request,pk):
queryset = BlogPost.objects.annotate(
num_views=Count('viewers')
).order_by('-num_views')
data = get_object_or_404(queryset, pk=pk)
context = {'queryset':queryset,'data':data}
return render(request, 'mains/show_more.html', context )
and then you can render this with:
{{ data.num_views }}
If you want to add the user to the viewers, you can run the logic to add the user to the viewers:
from django.db.models import Count
def detail_view(request,pk):
queryset = BlogPost.objects.annotate(
num_views=Count('viewers')
).order_by('-num_views')
data = get_object_or_404(queryset, pk=pk)
if self.user.is_authenticated:
__, created = Post.viewers.through.objects.get_or_create(
post=data,
user=self.request.user
)
if created:
data.num_views += 1
context = {'queryset':queryset,'data':data}
return render(request, 'mains/show_more.html', context )
That being said, this to some extent demonstrates that function-based views are often not well-suited for a view that requires to run logic that consists out of a number of separate parts. In that case it is better to work with mixins and define a class-based view in terms of these mixins.
According to django docs:
class MyModelAdmin(admin.ModelAdmin):
def get_urls(self):
urls = super(MyModelAdmin, self).get_urls()
my_urls = [
url(r'^my_view/$', self.my_view),
]
return my_urls + urls
def my_view(self, request):
# ...
context = dict(
# Include common variables for rendering the admin template.
self.admin_site.each_context(request),
# Anything else you want in the context...
key=value,
)
return TemplateResponse(request, "sometemplate.html", context)
If I am not wrong, we can do the same thing by adding url in urls.py and the views in views.py as it is normally done then, what is the use of introducing this way? I am a newbie to django and I may be missing something here.
Can you please provide an example where we cannot do it in views.py and we must use the above method?
Any guidance/help would be appreciated.
I think I figured out, both of them can be used to do the same thing but the key difference is that the views which you write using above method will belong to admin app while the general views in views.py belongs to the particular app in you have written.
Hence, the url in ModelAdmin need to be called using name admin:url_name since the url goes as admin/my_views/ in given example.
my task is to create on main page of my web site two list one list for my post
and second list categories titles which belong my post.
i create that and work fine,and i create post details connect and again work fine.
but i cant to work category details if i want to see list from my post which belong specific category i cant show me error page not found.
my code
my model
class Category(models.Model):
categorytitle =models.CharField(max_length=1,choices=CAT_CHOICES,unique=True)
slug= models.SlugField()
class Posts(models.Model):
Title = models.CharField(max_length=100,blank=True)
slug= models.SlugField()
category = models.ManyToManyField(Category)
my view category
def view_category(request, slug):
category = get_object_or_404(Category, slug=slug)
return render_to_response('blog/view_category.html', {
'category': category,
'posts': Posts.objects.filter(category=category)
})
my urls category
url(r'^(?P<slug>[^\.]+)/$', views.view_category, name='view_category'),
main template tags
{% for category in categories %}
<li>{{ category.categorytitle }}</li>
{% endfor %}
error message
Page not found (404)
Request Method:
GET
Request URL:
http://127.0.0.1:8000/category1/
Raised by:
blog.views.view_post
No Posts matches the given query.
my view post
def view_post(request, slug):
return render_to_response('blog/movies_details.html', {
'post': get_object_or_404(Movies,slug=slug)
})
my urls view
url(r'^(?P<slug>[^\.]+)/$', views.view_post, name='view_post'),
if i use browser db for sqlite view
Change your regex in urls.py to:
url(r'^(?P<slug>[\w-]+)/$', views.view_category, name='view_category'),
\w = alphanumeric signs + underscore
- = hyphen
(These characters are now allowed in the slug)
And change the Post filter to:
Posts.objects.filter(category_id=category.id)
NOTE:
Posts filtering have to placed before rendering, not in it (do it in the same way like "category")
How do you create slugs in the Category model? In admin? Manually or automatically via prepopulated_fields? Because I don'ลง like in the categorytitle field the max_length=1
If your error message shows: "Raised by: blog.views.view_post" Than obviously django is hitting view_post function in your views and not view_category.
Due to wrong function call view_post can't find the post with slug:"category1" so gives a 404 error ( obviously!! ).
So i will suggest to check out if there is a url mismatch that is causing this first.
So I had a similar problem, did all I could by reading various solutions and none was helpful. My solution was real funny(ironic) since I spent an hour to find out what was wrong.
In the urls.py, the order of the url s is pretty important.
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^', include('shop.urls')),
url(r'^shpcart/', include('shpcart.urls')),
]
The above pattern kept saying 404 shpcart/ not found, but shpcart was already there.
Just as I was about to find myself trying to persuade the pc, I moved the shpcart url 1 line above, everything started to sound. If anyone is stuck like I was, hope this helps
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^shpcart/', include('shpcart.urls')),
url(r'^', include('shop.urls')),
]
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.
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.