for some reason I can't view pages which have a slug without a hyphen. For example:
This doesn't work:
/example1
This works:
/this-way-works
I have tried changing the regular expressions but had no joy. Any help would be appreciated!
urls
urlpatterns = patterns('',
url(r'^$', views.index, name='index'),
url(r'^register_profile/$', views.register_profile, name='register_profile'),
url(r'^update_profile/$', views.update_profile, name='update_profile'),
url(r'^create_project/$', views.CreateProject.as_view(), name='create_project'),
url(r'^(?P<username>\w+)/$', views.profile_page, name='user_profile'),
url(r'^(?P<slug>[-\w]+)/$', views.project_page, name='user_project'),
)
project_page view
def project_page(request, slug):
context_dict = {}
username = request.user.username
user = get_object_or_404(User, username=username)
context_dict['project_user'] = user
project = UserProject.objects.get(slug=slug)
context_dict['project'] = project
context_dict['project_title'] = project.title
return render(request, 'howdidu/project.html', context_dict)
models
class UserProject(models.Model):
user = models.ForeignKey(User)
title = models.CharField(max_length=100)
project_overview = models.CharField(max_length=1000)
project_picture = models.ImageField(upload_to='project_images', blank=True)
date_created = models.DateTimeField(auto_now_add=True)
project_views = models.IntegerField(default=0)
project_likes = models.IntegerField(default=0)
project_followers = models.IntegerField(default=0)
slug = models.SlugField(max_length=100, unique=True) #should this be unique or not?
def save(self, *args, **kwargs):
self.slug = slugify(self.title)
super(UserProject, self).save(*args, **kwargs)
def __unicode__(self):
return self.title
template
{% extends 'howdidu/base.html' %}
{% load staticfiles %}
{% block title %}{{ profile_user.userprofile.first_name }} {{ profile_user.userprofile.second_name }}{% endblock %}
{% block body_block %}
<h1>{{ profile_user.userprofile.first_name }}'s profile page</h1>
<img src="{{ profile_user.userprofile.profile_picture.url }}" width = "150" height = "150" />
<h2>{{ profile_user.userprofile.first_name }} {{ profile_user.userprofile.second_name }}</h2>
<h2>{{ profile_user.userprofile.user_country }}</h2>
{% if projects %}
<ul>
{% for project in projects %}
<li>{{ project.title }}</li>
{% endfor %}
</ul>
{% else %}
<strong>There are no projects present.</strong>
{% endif %}
{% if user.is_authenticated %}
{% if profile_user.username == user.username %}
<p>Edit profile</p>
<p>Create new project</p>
{% endif %}
{% endif %}
{% endblock %}
The problem is in you url ordering.
url(r'^(?P<username>\w+)/$', views.profile_page, name='user_profile'),
url(r'^(?P<slug>[-\w]+)/$', views.project_page, name='user_project'),
There is no big difference for Django in these urls. Django will go from up to down and find first match. If there is a - in your slug it will map to
url(r'^(?P<slug>[-\w]+)/$', views.project_page, name='user_project')
as it is the only url that matches -. But if your slug is example1 link will match
url(r'^(?P<username>\w+)/$', views.profile_page, name='user_profile'),
url as it is closer to the top. What you need to do is to add another 'level' to the urls. For example:
url(r'^users/(?P<username>\w+)/$', views.profile_page, name='user_profile'),
url(r'^projects/(?P<slug>[-\w]+)/$', views.project_page, name='user_project'),
Then everything will work fine.
P. S.
Your url doesn't deppend on user so actually any user can see all projects, I think that's not what you need.Think about this for a little bit and ask me if you need any help.
Related
I am building simple blog with posts and posts categories.
I would like to add links to posts categories to header and footer, so they appear on every page, not just home page (as routable pages).
How do I go about it?
Category class as below:
class BlogCategory(models.Model):
title = models.CharField( # field name has to be 'title'
verbose_name='Name', max_length=30, unique=True)
slug = AutoSlugField( populate_from='title', editable=True)
panels = [
MultiFieldPanel([
FieldPanel("title"),
FieldPanel("slug"),
], heading="New Category"),]
def __str__(self):
return self.title
Code for routable page:
class BlogIndexPage(RoutablePageMixin, Page):
class Meta:
verbose_name = "Blog Index Page"
template = "blog/blog_index_page.html"
parent_page_types = ["wagtailcore.Page"]
subpage_types = ["blog.PostArticlePage"]
max_count = 1
# context ------------------------------
def get_context(self, request, *args, **kwargs):
context = super().get_context(request, *args, **kwargs)
all_posts = (
BlogDetailPage.objects.live().public().order_by("-first_published_at")
)
context["posts"] = all_posts
#route(r"^category/(?P<cat_slug>[-\w]*)/$", name="category_view")
def category_view(self, request, cat_slug):
context = self.get_context(request)
try:
category = BlogCategory.objects.get(slug=cat_slug)
except Exception:
return redirect(self.url)
if category is None:
return redirect('/')
context["posts"] = (BlogDetailPage.objects.live().public().filter(categories__in=[category]))
return render(request, "blog/blog_view_page.html", context)
Try this from here :
{% regroup object_list by category as post_list %}
<ul>
{% for post_category in post_list %}
<li>{{ post_category.grouper }}
<ul>
{% for post in post_category.list %}
<li>{{ post.title }}</li>
{% endfor %}
</ul>
</li>
{% endfor %}
You may have to modify it a bit but the principal is the same.
The regroup tag is well explained in the Django docs and Wagtail docs clearly mention they support Django tags.
To add blog categories to header and footer:
First create a simple template tag
register = template.Library()
#register.simple_tag()
def get_categories():
return BlogCategory.objects.all()
Next add following code to header and footer
{% load blog_tags %}
{% get_categories as categories %}
<nav>
<ul>
{% for cat in categories %}
<li>{{ cat.title }}</li>
{% endfor %}
</ul>
</nav>
Finally, reload the server.
Why is the likes system not working? Аfter clicking on the "like" button I get an error.
class ImageDetail(DetailView):
model=Image
template_name='images/image/detail.html'
context_object_name='image'
def get_queryset(self):
return Image.objects.filter(id=self.kwargs.get('id'),slug=self.kwargs['slug'])
def get_context_data(self, **kwargs):
data = super().get_context_data(**kwargs)
likes_connected=get_object_or_404(Image, id=self.kwargs['id'],slug=self.kwargs['slug'])
liked=False
if likes_connected.users_like.filter(id=self.request.user.id).exists():
liked=True
data['number_of_likes']=likes_connected.number_of_likes()
data['post_is_liked']=liked
return data
def ImagePostLike(request,id,slug):
image=get_object_or_404(Image, id=request.POST.get('image_id'), slug=request.POST.get('image_slug'))
if image.users_like.filter(id=request.user.id).exists():
image.users_like.remove(request.user)
else:
image.users_like.add(request.user)
return HttpResponseRedirect(reverse('image_detail', args=[self.id, self.slug]))
Why is the likes system not working? Аfter clicking on the "like" button I get an error.
urls.py
from django.urls import path,include
from . import views
app_name = 'images'
urlpatterns = [
path('create/', views.image_create, name='create'),
path('detail/<int:id>/<slug:slug>/', views.ImageDetail.as_view(), name='image_detail'),
path('image_like/<int:id>/<slug:slug>/', views.ImagePostLike, name='image_like'),
]
Why is the likes system not working? Аfter clicking on the "like" button I get an error.
detail.html
{% extends 'base.html' %}
{% load thumbnail %}
{% block title %}{{image.title}}{% endblock title %}
{% block content %}
<h1>{{ image.title }}</h1>
<img src="{{ image.url }}" class="image-detail">
{% if user.is_authenticated %}
<form action="{% url 'images:image_like' image.id image.slug%}">
{% csrf_token %}
{% if post_is_liked %}
<button type="submit" name="image_id" value="{{image.id}}" class="btn btn-info">Unlike</button>
{% else %}
<button type="submit" name="image_id" value="{{image.id}}" class="btn btn-info">Like</button>
{% endif %}
</form>
{% else %}
<a class="btn btn-outline-info" href="{% url 'login' %}?next={{request.path}}">>Log in to like this article!</a><br>
{% endif %}
<strong class="text-secondary">{{ number_of_likes }} Like</strong>
{% endblock content %}
models.py
# Create your models here.
class Image(models.Model):
user=models.ForeignKey(settings.AUTH_USER_MODEL,
related_name='images_created', on_delete=models.CASCADE)
title=models.CharField(max_length=50)
slug=models.SlugField(max_length=200, blank=True)
url=models.URLField()
image=models.ImageField(upload_to='images/%Y/%m/%d/')
description = models.TextField(blank=True)
created = models.DateField(auto_now_add=True,
db_index=True)
users_like=models.ManyToManyField(User,
related_name='image_like')
def __str__(self):
return self.title
def save(self, *args, **kwargs):
if not self.slug:
self.slug = slugify(self.title)
super().save(*args, **kwargs)
def get_absolute_url(self):
return reverse('images:detail', args=[self.id, self.slug])
def number_of_likes(self):
return self.users_like.count()
As I understand it, the problem lies in the slug.
I am doing a training project and have encountered a problem. I try to display the "events" block and the "news" block on the main page, but when I run the loop cycle, only one block is displayed, and the second is not displayed. Explain who knows what I'm doing wrong. I have been solving this problem for three days now. Thanks in advance who will respond to help
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{% if post %}
{% for post in post %}
{{ post.title }}
{% endfor %}
{% else %}
<p>У вас нет материала</p>
{% endif %}
{% if event %}
{% for event in event %}
{{ event.name }}
{% endfor %}
{% else %}
<p>У вас нет материала</p>
{% endif %}
</body>
</html>
Views:
from django.shortcuts import get_object_or_404, render
from django.views.generic.base import View
from .models import Blog, Event
# Create your views here.
class EventView(View):
def get(self, request):
event = Event.objects.all()
return render(request, "home/home_list.html", {"event": event})
class BlogView(View):
def get(self, request):
post = Blog.objects.all()
return render(request, "home/home_list.html", {"post": post})
Urls:
from django.urls import path
from . import views
urlpatterns = [
path("", views.EventView.as_view()),
path("", views.BlogView.as_view())
]
Models:
from django.db import models
from datetime import date
# Create your models here.
class Blog(models.Model):
"""Новости"""
title = models.CharField("Заголовок", max_length=100)
description = models.TextField("Описание")
descriptionTwo = models.TextField("Описание (второй абзац)", blank=True, default="")
blockquote = models.TextField("Цитата", blank=True, default="")
short = models.TextField("Краткое описание", max_length=300)
poster = models.ImageField("Изображение", upload_to="post/")
prewiew = models.ImageField("Превью", upload_to="post/")
dataPost = models.DateField("Дата публикации", default=date.today)
url = models.SlugField(max_length=160, unique=True, blank=True)
draft = models.BooleanField("Черновик", default=False)
def __str__(self):
return self.title
class Meta:
verbose_name = "Новости"
verbose_name_plural = "Новости"
class Event(models.Model):
"""События"""
name = models.CharField("Заголовок", max_length=100)
adress = models.TextField("Адрес")
description = models.TextField("Описание")
short = models.TextField("Краткое описание")
phone = models.TextField("Контактный номер телефона")
email = models.EmailField()
image = models.ImageField("Изображение", upload_to="event/")
dataStart = models.DateField("Дата старта", default=date.today)
def __str__(self):
return self.name
class Meta:
verbose_name = "Событие"
verbose_name_plural = "События"
Admin:
from django.contrib import admin
from .models import Blog, Event
# Register your models here.
admin.site.register(Event)
admin.site.register(Blog)
Views
You need one view with a context containing both the events ant the posts
class EventView(View):
def get(self, request):
events = Event.objects.all()
posts = Blog.objects.all()
return render(request, "home/home_list.html", {"events": events, "posts":posts})
Template
In the template loop over both
{% if posts %}
{% for p in posts %}
{{ p.title }}
{% endfor %}
{% else %}
<p>У вас нет материала</p>
{% endif %}
{% if events %}
{% for e in events %}
{{ e.name }}
{% endfor %}
{% else %}
<p>У вас нет материала</p>
{% endif %}
In for each loop, use different name for the "loop Object" and the list/dictionary on which you are looping. LIKE THIS:
{% if post %}
{% for p in post %}
{{ p.title }}
{% endfor %}
{% else %}
<p>У вас нет материала</p>
{% endif %}
{% if event %}
{% for e in event %}
{{ e.name }}
{% endfor %}
{% else %}
<p>У вас нет материала</p>
{% endif %}
Did it solve your problem?
I am trying to find out why some data from my views.py are not showing up. Here's my code
views.py
def user(request, user_id):
profile = get_object_or_404(User, pk=user_id)
rnk = Ranks.objects.all()
context = {
'profile' : profile,
'rnk' : rnk,
}
return render(request, 'user/user.html', context)
I am trying to show, for example the rank_name from my model and I use {{rnk.rank_name}} in the HTML template but it's not showing up.
On the other hand, data from profile like {{profile.user_name}} are showing up.
Note that rnk and profile are from this model:
class Ranks(models.Model):
rank_name = models.CharField(max_length=300)
description = models.TextField(blank=True)
def __str__(self):
return self.br_rank_name
class User(models.Model):
b_rank = models.ForeignKey(Ranks, on_delete=models.DO_NOTHING)
name = models.CharField(max_length=20)
link = models.URLField(max_length=100)
weekly = models.BooleanField(default=False)
biweekly = models.BooleanField(default=False)
def __str__(self):
return self.name
Here's my template
{% extends 'base.html' %}
{% load static %}
{% block content %}
<h5>{{profile.user_name}}</h5><!--This shows up-->
<p>{{rnk.rank_name}}</p>
<p>{{profile.weekly}}</p>
<span class="icon-desc">{{rnk.rank_points}} points</span>
{% endblock %}
That's because the rnk passed to the template is a queryset and includes multiple objects. So you need to iterate rnk using for and try to show the details for each one in your template.
{% extends 'base.html' %}
{% load static %}
{% block content %}
<h5>{{ profile.user_name }}</h5>
<p>{{ profile.weekly }}</p>
{% for rank in rnk %}
<p>{{ rank.rank_name }}</p>
<span class="icon-desc">{{ rank.rank_points }} points</span>
<img src="{{ rank.br_photo.url }}" height="150" alt="">
{% endfor %}
{% endblock %}
I have customuser model name Profile and VideoFile models with relative fields to User. There are many users account and each of them can add a lot of video files. I need to show at templates.html user.nickname and all of him videofiles.
user.models.py
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, null=True)
nickname = models.CharField(max_length=30, blank=True, verbose_name="Никнэйм")
userpic = models.ImageField(upload_to='userpics/', blank=True, null=True)
videofile.models.py
class VideoFile(models.Model):
name = models.CharField(max_length=200,blank=True)
file = models.FileField(upload_to="vstories/%Y/%m/%d", validators=[validate_file_extension])
date_upload = models.DateTimeField(auto_now_add = True, auto_now = False, blank=True, null = True)
descriptions = models.TextField(max_length=200)
reports = models.BooleanField(default=False)
vstories = models.ForeignKey(Profile, blank = True, null = True)
views.py
def vstories (request):
profiles = Profile.objects.all()
return render(request, "vstories/vstories.html", {'profiles':profiles})
templates.html
{% extends "base.html" %}
{% block content %}
{% if users %}
{% for user in users %}
<p>{{ user.profile.nickname}}</p>
{% for vstorie in vstories %}
<p>{{ vstorie.vstories.url }}</p>
{% endfor %}
{% endfor %}
{% endif %}
{% endblock content %}
With the video, I'm confused. Or maybe I chose the wrong way to communicate models?
You can look for the foreign keys "backward". In this case, to access to all videos of a user (Profile), you need to have all Profiles:
def vstories (request):
profiles = Profile.objects.all()
return render(request, "vstories/vstories.html",{'profiles':profiles})
Then, in the template, you can access the relationship between Profile and VideoFile "backward".
{% for profile in profiles %}
{% for videofile in profile.videofile_set.all %}
<p>{{ videofile.file.url }}</p>
{% endfor %}
{% endfor %}
The trick is in the "_set" that allows you to follow the relationship backward.
Here is the documentation for this kind of queryset:
https://docs.djangoproject.com/en/2.0/topics/db/queries/#following-relationships-backward
This work for me
{% for profile in profiles %}
{{ profile.nickname }}
{% for videofile in profile.videofile_set.all %}
<video width="320" height="240" controls src="{{ videofile.file.url }}">
Your browser does not support the video tag.
</video>
{% endfor %}
{% endfor %}