第一次在 Heroku 上部署 django 应用程序,我面临 2 个问题,解决方案?
First time deploying a django app on Heroku and I'm facing 2 issues, solution?
我开发了我的社交应用程序并能够部署它,但我遇到了 2 个问题:
Link: https://network50web.herokuapp.com/
1/它自动将我定向到 https://network50web.herokuapp.com/accounts/login/?next=/,如果我在地址栏中手动编写路由(登录,注册)
,我只能看到该站点
2/当我尝试使用我现有的用户名登录时,它会抛出错误“/login
处出现编程错误
关系“auth_user”不存在
LINE 1: ...user"."is_active", "auth_user"."date_joined" FROM "auth_user..." 它突出显示了这一行 " user = User.objects.create_user(username, email, password)” 即使我尝试注册一个新帐户
我对数据库使用 SQL
观看次数:
from django.contrib.auth import authenticate, login, logout
from django.db import IntegrityError
from django.http import HttpResponse, HttpResponseRedirect, request
from django.http.response import JsonResponse
from django.shortcuts import render, redirect, resolve_url, get_object_or_404
from django.urls import reverse, reverse_lazy
from django.core import serializers
from django.core.paginator import Paginator
from django.contrib import messages
from django.contrib.auth.models import User
from django.db.models import Q
from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin
from itertools import chain
from .models import Relationship, Post, Profile, Like
from django.views.generic import TemplateView, View, UpdateView, DeleteView, ListView, DetailView
from .forms import ProfileModelForm, PostModelForm, CommentModelForm
def search_view(request):
if request.method == "POST":
searched = request.POST['searched']
profiles = Profile.objects.filter(slug__contains=searched)
return render(request, 'network/search.html',
{'searched':searched,
'profiles':profiles})
else:
return render(request, 'network/search.html',
{})
class ProfileDetailView(LoginRequiredMixin, DetailView):
model = Profile
template_name = 'network/profile.html'
success_url = reverse_lazy('profile-view')
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
user = User.objects.get(username__iexact=self.request.user)
profile = Profile.objects.get(user=user)
rel_r = Relationship.objects.filter(sender=profile)
rel_s = Relationship.objects.filter(receiver=profile)
rel_receiver = []
rel_sender = []
for item in rel_r:
rel_receiver.append(item.receiver.user)
for item in rel_s:
rel_sender.append(item.sender.user)
context["rel_receiver"] = rel_receiver
context["rel_sender"] = rel_sender
context["posts"] = self.get_object().get_all_authors_posts()
context["len_posts"] = True if len(self.get_object().get_all_authors_posts()) > 0 else False
return context
@login_required
def profile_view(request):
profile = Profile.objects.get(user=request.user)
form = ProfileModelForm(request.POST or None, request.FILES or None, instance=profile)
confirm = False
if request.method == 'POST':
if form.is_valid():
form.save()
confirm = True
context = {
'profile': profile,
'form': form,
'confirm': confirm,
}
return render(request, 'network/profile.html', context)
@login_required
def invites_received_view(request):
profile = Profile.objects.get(user=request.user)
qs = Relationship.objects.invitations_received(profile)
results = list(map(lambda x: x.sender, qs))
is_empty = False
if len(results) == 0:
is_empty = True
context = {
'qs':results,
'is_empty': is_empty,
}
return render(request, 'network/invites.html', context)
@login_required
def accept_invitation(request):
if request.method =='POST':
pk = request.POST.get('profile_pk')
sender = Profile.objects.get(pk=pk)
receiver = Profile.objects.get(user=request.user)
rel = get_object_or_404(Relationship, sender=sender, receiver=receiver)
if rel.status == 'send':
rel.status = 'accepted'
rel.save()
return redirect('invites-view')
@login_required
def reject_invitation(request):
if request.method=="POST":
pk = request.POST.get('profile_pk')
receiver = Profile.objects.get(user=request.user)
sender = Profile.objects.get(pk=pk)
rel = get_object_or_404(Relationship, sender=sender, receiver=receiver)
rel.delete()
return redirect('invites-view')
@login_required
def invite_profiles_list_view(request):
user = request.user
qs = Profile.objects.get_all_profiles_to_invite(user)
context = {'qs': qs}
return render(request, 'network/to_invite_list.html', context)
@login_required
def profiles_list_view(request):
user = request.user
qs = Profile.objects.get_all_profiles(user)
context = {'qs': qs}
return render(request, 'network/profile_list.html', context)
class ProfileListView(LoginRequiredMixin, ListView):
model = Profile
template_name = 'network/profile_list.html'
#context_object_name = 'qs'
def get_queryset(self):
qs = Profile.objects.get_all_profiles(self.request.user)
return qs
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
user = User.objects.get(username__iexact=self.request.user)
profile = Profile.objects.get(user=user)
rel_r = Relationship.objects.filter(sender=profile)
rel_s = Relationship.objects.filter(receiver=profile)
rel_receiver = []
rel_sender = []
for item in rel_r:
rel_receiver.append(item.receiver.user)
for item in rel_s:
rel_sender.append(item.sender.user)
context["rel_receiver"] = rel_receiver
context["rel_sender"] = rel_sender
context["is_empty"] = False
if len(self.get_queryset()) == 0:
context["is_empty"] = True
return context
@login_required
def send_invitation(request):
if request.method == 'POST':
pk = request.POST.get('profile_pk')
user = request.user
sender = Profile.objects.get(user=user)
receiver = Profile.objects.get(pk=pk)
rel = Relationship.objects.create(sender=sender, receiver=receiver, status='send')
return redirect(request.META.get('HTTP_REFERER'))
return redirect('profile')
@login_required
def remove_friends(request):
if request.method == 'POST':
pk = request.POST.get('profile_pk')
user = request.user
sender = Profile.objects.get(user=user)
receiver = Profile.objects.get(pk=pk)
rel = Relationship.objects.get(
(Q(sender=sender) & Q(receiver=receiver)) | (Q(sender=receiver) & Q(receiver=sender))
)
rel.delete()
return redirect(request.META.get('HTTP_REFERER'))
return redirect('profile')
@login_required
def like_unlike_post(request):
user = request.user
if request.method == 'POST':
post_id = request.POST.get('post_id')
post_obj = Post.objects.get(id=post_id)
profile = Profile.objects.get(user=user)
if profile in post_obj.liked.all():
post_obj.liked.remove(profile)
else:
post_obj.liked.add(profile)
like, created = Like.objects.get_or_create(user=profile, post_id=post_id)
if not created:
if like.value=='Like':
like.value='Unlike'
else:
like.value='Like'
else:
like.value='Unlike'
post_obj.save()
like.save()
data = {
'value': like.value,
'likes': post_obj.liked.all().count()
}
return JsonResponse(data, safe=False)
return redirect('posts')
@login_required
def post_comment_create_view(request):
qs = Post.objects.all()
profile = Profile.objects.get(user=request.user)
#Setting up pagination
p = Paginator(qs, 5)
page = request.GET.get('page')
post_list = p.get_page(page)
#Post form, comment form
p_form = PostModelForm()
c_form = CommentModelForm()
post_added = False
profile = Profile.objects.get(user=request.user)
if 'submit_pForm' in request.POST:
print(request.POST)
p_form = PostModelForm(request.POST, request.FILES)
if p_form.is_valid():
instance = p_form.save(commit=False)
instance.author = profile
instance.save()
p_form = PostModelForm()
post_added = True
if 'submit_cForm' in request.POST:
c_form = CommentModelForm(request.POST)
if c_form.is_valid():
instance = c_form.save(commit=False)
instance.user = profile
instance.post = Post.objects.get(id=request.POST.get('post_id'))
instance.save()
c_form = CommentModelForm()
context = {
'qs': qs,
'profile': profile,
'p_form': p_form,
'c_form': c_form,
'post_added': post_added,
'post_list': post_list,
}
return render(request, 'network/posts.html', context)
@login_required
def posts_of_following_profiles(request):
profile = Profile.objects.get(user=request.user)
users = [user for user in profile.following.all()]
posts = []
qs = None
for u in users:
p = Profile.objects.get(user=u)
p_posts = p.post_set.all()
posts.append(p_posts)
my_posts = profile.get_my_posts()
posts.append(my_posts)
if len(posts) > 0:
my_posts = sorted(chain(*posts), reverse=True, key=lambda obj: obj.created)
#Setting up pagination
p = Paginator(my_posts, 5)
page = request.GET.get('page')
post_list = p.get_page(page)
#Post form, comment form
p_form = PostModelForm()
c_form = CommentModelForm()
post_added = False
if 'submit_pForm' in request.POST:
print(request.POST)
p_form = PostModelForm(request.POST, request.FILES)
if p_form.is_valid():
instance = p_form.save(commit=False)
instance.author = profile
instance.save()
p_form = PostModelForm()
post_added = True
if 'submit_cForm' in request.POST:
c_form = CommentModelForm(request.POST)
if c_form.is_valid():
instance = c_form.save(commit=False)
instance.user = profile
instance.post = Post.objects.get(id=request.POST.get('post_id'))
instance.save()
c_form = CommentModelForm()
context = {
'posts': qs,
'profile': profile,
'p_form': p_form,
'c_form': c_form,
'post_added': post_added,
'post_list': post_list,
}
return render(request, 'network/followers_posts.html', context)
class PostDeleteView(LoginRequiredMixin, DeleteView):
model = Post
template_name = 'network/confirmDelete.html'
success_url = reverse_lazy('posts')
def get_object(self, *args, **kwargs):
pk = self.kwargs.get('pk')
obj = Post.objects.get(pk=pk)
if not obj.author.user == self.request.user:
messages.warning(self.request, 'You need to be the owner of the post in order to delete it!')
return obj
class PostUpdateView(LoginRequiredMixin, UpdateView):
form_class = PostModelForm
model = Post
template_name = 'network/update.html'
success_url = reverse_lazy('posts')
def form_valid(self, form):
profile = Profile.objects.get(user=self.request.user)
if form.instance.author == profile:
return super().form_valid(form)
else:
form.add_error(None, "You need to be the owner of the post in order to update it!")
return super().form_invalid(form)
def login_view(request):
if request.method == "POST":
# Attempt to sign user in
username = request.POST["username"]
password = request.POST["password"]
user = authenticate(request, username=username, password=password)
# Check if authentication successful
if user is not None:
login(request, user)
return HttpResponseRedirect(reverse("posts"))
else:
return render(request, "network/login.html", {
"message": "Invalid username and/or password."
})
else:
return render(request, "network/login.html")
def logout_view(request):
logout(request)
return HttpResponseRedirect(reverse("login"))
def register(request):
if request.method == "POST":
username = request.POST["username"]
email = request.POST["email"]
# Ensure password matches confirmation
password = request.POST["password"]
confirmation = request.POST["confirmation"]
if password != confirmation:
return render(request, "network/register.html", {
"message": "Passwords must match."
})
# Attempt to create new user
try:
user = User.objects.create_user(username, email, password)
user.save()
except IntegrityError:
return render(request, "network/register.html", {
"message": "Username already taken."
})
login(request, user)
return HttpResponseRedirect(reverse("all-profiles-view"))
else:
return render(request, "network/register.html")
网址:
from django.urls import path
from django.conf import settings
from django.conf.urls.static import static
from . import views
from .views import (
posts_of_following_profiles,
like_unlike_post,
invites_received_view,
invite_profiles_list_view,
send_invitation,
remove_friends,
accept_invitation,
reject_invitation,
search_view,
post_comment_create_view,
login_view,
logout_view,
register,
ProfileDetailView,
PostDeleteView,
PostUpdateView,
ProfileListView,
#EditProfileView,
)
urlpatterns = [
path("", ProfileListView.as_view(), name="all-profiles-view"),
path("posts/", views.post_comment_create_view, name="posts"),
path("posts-follow/", posts_of_following_profiles, name="posts-follow"),
path("login", views.login_view, name="login"),
path("logout", views.logout_view, name="logout"),
path("register", views.register, name="register"),
path("liked/", like_unlike_post, name="like-post-view"),
path("<pk>/delete", PostDeleteView.as_view(), name="post-delete"),
path("<pk>/update", PostUpdateView.as_view(), name="post-update"),
path("invites/", invites_received_view, name="invites-view"),
path("send-invite/", send_invitation, name="send-invite"),
path("remove-friend/", remove_friends, name="remove-friend"),
path("invites/accept/", accept_invitation, name="accept-invite"),
path("invites/reject/", reject_invitation, name="reject-invite"),
path("to-invite/", invite_profiles_list_view, name='invite-profiles-view'),
path("search/", views.search_view, name='search-view'),
path("<slug>", ProfileDetailView.as_view(), name="profile-view"),
]
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
型号:
from django.contrib.auth.models import User
from django.core import validators
from django.db import models
from itertools import chain
import random
from django.db.models.aggregates import Max
from django.shortcuts import reverse
from django.db.models.deletion import CASCADE
from .utils import get_random_code
from django.template.defaultfilters import slugify
from django.core.validators import FileExtensionValidator
from django.db.models import Q
class ProfileManager(models.Manager):
def get_all_profiles_to_invite(self, sender):
profiles = Profile.objects.all().exclude(user=sender)
profile = Profile.objects.get(user=sender)
qs = Relationship.objects.filter(Q(sender=profile) | Q(receiver=profile))
accepted = set([])
for rel in qs:
if rel.status == 'accepted':
accepted.add(rel.receiver)
accepted.add(rel.sender)
print(accepted)
available = [profile for profile in profiles if profile not in accepted]
return available
def get_all_profiles(self, me):
profiles = Profile.objects.all().exclude(user=me)
return profiles
class Profile(models.Model):
first_name = models.CharField(max_length=64, blank=True)
last_name = models.CharField(max_length=64, blank=True)
user = models.OneToOneField(User, on_delete=models.CASCADE)
country = models.CharField(max_length=64, blank=True)
avatar = models.ImageField(upload_to='avatars', default='avatar.png')
background = models.ImageField(upload_to='backgrounds', default='background.png')
following = models.ManyToManyField(User, related_name='following', blank=True)
bio = models.TextField(default="No Bio..")
updated = models.DateTimeField(auto_now=True)
created = models.DateTimeField(auto_now_add=True)
slug = models.SlugField(unique=True, blank=True)
objects = ProfileManager()
def __str__(self):
return f"{self.user.username}"
def get_absolute_url(self):
return reverse("profile-view", kwargs={"slug": self.slug})
__initial_first_name = None
__initial_last_name = None
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.__initial_first_name = self.first_name
self.__initial_last_name = self.last_name
def save(self, *args, **kwargs):
ex = False
to_slug = self.slug
if self.first_name != self.__initial_first_name or self.last_name != self.__initial_last_name or self.slug=="":
if self.first_name and self.last_name:
to_slug = slugify(str(self.first_name) + " " + str(self.last_name))
ex = Profile.objects.filter(slug=to_slug).exists()
while ex:
to_slug = slugify(to_slug + " " + str(get_random_code()))
ex = Profile.objects.filter(slug=to_slug).exists()
else:
to_slug = str(self.user)
self.slug = to_slug
super().save(*args, **kwargs)
def get_followers(self):
return self.following.all()
def get_followers_num(self):
return self.following.all().count()
def get_my_posts(self):
return self.post_set.all()
def get_country(self):
return self.post_set.all()
def get_following_users(self):
following_list = [p for p in self.get_following()]
return following_list
def get_followers_users(self):
following_list = [p for p in self.get_followers()]
return following_list
def get_all_posts(self):
users = [user for user in self.get_following()]
posts = []
qs = None
for u in users:
p = Profile.objects.get(user=u)
p_posts = p.post_set.all()
posts.append(p_posts)
my_posts = self.post_set.all()
posts.append(my_posts)
if len(posts) > 0:
qs = sorted(chain(*posts), reverse=True, key=lambda obj: obj.created)
return qs
def get_posts_num(self):
return self.post_set.all().count()
def get_all_authors_posts(self):
return self.post_set.all()
def get_likes_given_num(self):
likes = self.like_set.all()
total_liked = 0
for item in likes:
if item.value == 'Like':
total_liked += 1
return total_liked
def get_likes_received_num(self):
posts = self.post_set.all()
total_liked = 0
for item in posts:
total_liked += item.all().count()
return total_liked
def get_proposals_for_following(self):
profiles = Profile.objects.all().exclude(user=self.user)
followers_list = [p for p in self.get_following()]
available = [p.user for p in profiles if p.user not in followers_list]
random.shuffle(available)
return available[:3]
STATUS_CHOICES = (
('send', 'send'),
('accepted', 'accepted')
)
class RelationshipManager(models.Manager):
def invitations_received(self, receiver):
qs = Relationship.objects.filter(receiver=receiver, status='send')
return qs
class Relationship(models.Model):
sender = models.ForeignKey(Profile, on_delete=models.CASCADE, related_name='sender')
receiver = models.ForeignKey(Profile, on_delete=models.CASCADE, related_name='receiver')
status = models.CharField(max_length=8, choices=STATUS_CHOICES)
updated = models.DateTimeField(auto_now=True)
created = models.DateTimeField(auto_now_add=True)
objects = RelationshipManager()
def __str__(self):
return f"{self.sender}-{self.receiver}-{self.status}"
class Post(models.Model):
# id is created automatically by Django
picture = models.ImageField(upload_to='images', blank=True, validators=[FileExtensionValidator(['png', 'jpg', 'jpeg'])])
content = models.TextField()
liked = models.ManyToManyField(Profile, blank=True, related_name="likes")
author = models.ForeignKey(Profile, on_delete=models.CASCADE, null=True)
updated = models.DateTimeField(auto_now=True)
created = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ('-created',)
def __str__ (self):
return str(self.content[:20])
def num_likes(self):
return self.liked.all().count()
@property
def like_count(self):
return self.liked.all().count()
def get_user_liked(self, user):
pass
# Number of comments
def num_comments(self):
return self.comment_set.all.count()
class Comment(models.Model):
user = models.ForeignKey(Profile, on_delete=models.CASCADE)
post = models.ForeignKey(Post, on_delete=models.CASCADE)
body = models.TextField(max_length=250)
updated = models.DateTimeField(auto_now=True)
created = models.DateTimeField(auto_now_add=True)
def __str__(self):
return str(self.pk)
LIKE_CHOICES = (
('Like', 'Like'),
('Unlike', 'Unlike'),
)
class Like(models.Model):
user = models.ForeignKey(Profile, on_delete=models.CASCADE)
post = models.ForeignKey(Post, on_delete=models.CASCADE)
value = models.CharField(choices=LIKE_CHOICES, max_length=8)
updated = models.DateTimeField(auto_now=True)
created = models.DateTimeField(auto_now_add=True)
def __str__(self):
return f"{self.user}-{self.post}-{self.value}"
def like_numb(self):
return self.like.all().count()
设置:
import os
import django_heroku
import dj_database_url
from decouple import config
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/3.0/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = secretkey
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = []
# Application definition
INSTALLED_APPS = [
'crispy_forms',
'network',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'django.contrib.humanize',
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'whitenoise.middleware.WhiteNoiseMiddleware',
]
ROOT_URLCONF = 'project4.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': (BASE_DIR, 'network/templates'),
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
WSGI_APPLICATION = 'project4.wsgi.application'
# Database
# https://docs.djangoproject.com/en/3.0/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3')
}
}
# Password validation
# https://docs.djangoproject.com/en/3.0/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
# Internationalization
# https://docs.djangoproject.com/en/3.0/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.0/howto/static-files/
STATIC_URL = 'network/static/'
STATICFILES_DIRS = (BASE_DIR, 'network/static')
STATICFILES_STORAGE = 'whitenoise.storage.CompressManifestStaticFilesStorage'
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR,'media')
DEFAULT_AUTO_FIELD = 'django.db.models.AutoField'
django_heroku.settings(locals())
首先,您必须设置 LOGIN_URL
和 LOGIN_REDIRECT_URL
在你的 settings.py 文件中,像这样
LOGIN_URL = '/login'
LOGIN_REDIRECT_URL = '/'
第二次登录到您的 heroku cli 并运行此命令
$ heroku run bash
这将为您打开一个 bash,您可以从那里访问您的项目文件
你必须导航到你的项目根目录 (manage.py 所在的位置) 然后 运行 这两个命令
$ python manage.py makemigrations network
$ python manage.py migrate
$ python manage.py createsuperuser
我开发了我的社交应用程序并能够部署它,但我遇到了 2 个问题: Link: https://network50web.herokuapp.com/ 1/它自动将我定向到 https://network50web.herokuapp.com/accounts/login/?next=/,如果我在地址栏中手动编写路由(登录,注册)
,我只能看到该站点2/当我尝试使用我现有的用户名登录时,它会抛出错误“/login
处出现编程错误关系“auth_user”不存在 LINE 1: ...user"."is_active", "auth_user"."date_joined" FROM "auth_user..." 它突出显示了这一行 " user = User.objects.create_user(username, email, password)” 即使我尝试注册一个新帐户 我对数据库使用 SQL 观看次数:
from django.contrib.auth import authenticate, login, logout
from django.db import IntegrityError
from django.http import HttpResponse, HttpResponseRedirect, request
from django.http.response import JsonResponse
from django.shortcuts import render, redirect, resolve_url, get_object_or_404
from django.urls import reverse, reverse_lazy
from django.core import serializers
from django.core.paginator import Paginator
from django.contrib import messages
from django.contrib.auth.models import User
from django.db.models import Q
from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin
from itertools import chain
from .models import Relationship, Post, Profile, Like
from django.views.generic import TemplateView, View, UpdateView, DeleteView, ListView, DetailView
from .forms import ProfileModelForm, PostModelForm, CommentModelForm
def search_view(request):
if request.method == "POST":
searched = request.POST['searched']
profiles = Profile.objects.filter(slug__contains=searched)
return render(request, 'network/search.html',
{'searched':searched,
'profiles':profiles})
else:
return render(request, 'network/search.html',
{})
class ProfileDetailView(LoginRequiredMixin, DetailView):
model = Profile
template_name = 'network/profile.html'
success_url = reverse_lazy('profile-view')
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
user = User.objects.get(username__iexact=self.request.user)
profile = Profile.objects.get(user=user)
rel_r = Relationship.objects.filter(sender=profile)
rel_s = Relationship.objects.filter(receiver=profile)
rel_receiver = []
rel_sender = []
for item in rel_r:
rel_receiver.append(item.receiver.user)
for item in rel_s:
rel_sender.append(item.sender.user)
context["rel_receiver"] = rel_receiver
context["rel_sender"] = rel_sender
context["posts"] = self.get_object().get_all_authors_posts()
context["len_posts"] = True if len(self.get_object().get_all_authors_posts()) > 0 else False
return context
@login_required
def profile_view(request):
profile = Profile.objects.get(user=request.user)
form = ProfileModelForm(request.POST or None, request.FILES or None, instance=profile)
confirm = False
if request.method == 'POST':
if form.is_valid():
form.save()
confirm = True
context = {
'profile': profile,
'form': form,
'confirm': confirm,
}
return render(request, 'network/profile.html', context)
@login_required
def invites_received_view(request):
profile = Profile.objects.get(user=request.user)
qs = Relationship.objects.invitations_received(profile)
results = list(map(lambda x: x.sender, qs))
is_empty = False
if len(results) == 0:
is_empty = True
context = {
'qs':results,
'is_empty': is_empty,
}
return render(request, 'network/invites.html', context)
@login_required
def accept_invitation(request):
if request.method =='POST':
pk = request.POST.get('profile_pk')
sender = Profile.objects.get(pk=pk)
receiver = Profile.objects.get(user=request.user)
rel = get_object_or_404(Relationship, sender=sender, receiver=receiver)
if rel.status == 'send':
rel.status = 'accepted'
rel.save()
return redirect('invites-view')
@login_required
def reject_invitation(request):
if request.method=="POST":
pk = request.POST.get('profile_pk')
receiver = Profile.objects.get(user=request.user)
sender = Profile.objects.get(pk=pk)
rel = get_object_or_404(Relationship, sender=sender, receiver=receiver)
rel.delete()
return redirect('invites-view')
@login_required
def invite_profiles_list_view(request):
user = request.user
qs = Profile.objects.get_all_profiles_to_invite(user)
context = {'qs': qs}
return render(request, 'network/to_invite_list.html', context)
@login_required
def profiles_list_view(request):
user = request.user
qs = Profile.objects.get_all_profiles(user)
context = {'qs': qs}
return render(request, 'network/profile_list.html', context)
class ProfileListView(LoginRequiredMixin, ListView):
model = Profile
template_name = 'network/profile_list.html'
#context_object_name = 'qs'
def get_queryset(self):
qs = Profile.objects.get_all_profiles(self.request.user)
return qs
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
user = User.objects.get(username__iexact=self.request.user)
profile = Profile.objects.get(user=user)
rel_r = Relationship.objects.filter(sender=profile)
rel_s = Relationship.objects.filter(receiver=profile)
rel_receiver = []
rel_sender = []
for item in rel_r:
rel_receiver.append(item.receiver.user)
for item in rel_s:
rel_sender.append(item.sender.user)
context["rel_receiver"] = rel_receiver
context["rel_sender"] = rel_sender
context["is_empty"] = False
if len(self.get_queryset()) == 0:
context["is_empty"] = True
return context
@login_required
def send_invitation(request):
if request.method == 'POST':
pk = request.POST.get('profile_pk')
user = request.user
sender = Profile.objects.get(user=user)
receiver = Profile.objects.get(pk=pk)
rel = Relationship.objects.create(sender=sender, receiver=receiver, status='send')
return redirect(request.META.get('HTTP_REFERER'))
return redirect('profile')
@login_required
def remove_friends(request):
if request.method == 'POST':
pk = request.POST.get('profile_pk')
user = request.user
sender = Profile.objects.get(user=user)
receiver = Profile.objects.get(pk=pk)
rel = Relationship.objects.get(
(Q(sender=sender) & Q(receiver=receiver)) | (Q(sender=receiver) & Q(receiver=sender))
)
rel.delete()
return redirect(request.META.get('HTTP_REFERER'))
return redirect('profile')
@login_required
def like_unlike_post(request):
user = request.user
if request.method == 'POST':
post_id = request.POST.get('post_id')
post_obj = Post.objects.get(id=post_id)
profile = Profile.objects.get(user=user)
if profile in post_obj.liked.all():
post_obj.liked.remove(profile)
else:
post_obj.liked.add(profile)
like, created = Like.objects.get_or_create(user=profile, post_id=post_id)
if not created:
if like.value=='Like':
like.value='Unlike'
else:
like.value='Like'
else:
like.value='Unlike'
post_obj.save()
like.save()
data = {
'value': like.value,
'likes': post_obj.liked.all().count()
}
return JsonResponse(data, safe=False)
return redirect('posts')
@login_required
def post_comment_create_view(request):
qs = Post.objects.all()
profile = Profile.objects.get(user=request.user)
#Setting up pagination
p = Paginator(qs, 5)
page = request.GET.get('page')
post_list = p.get_page(page)
#Post form, comment form
p_form = PostModelForm()
c_form = CommentModelForm()
post_added = False
profile = Profile.objects.get(user=request.user)
if 'submit_pForm' in request.POST:
print(request.POST)
p_form = PostModelForm(request.POST, request.FILES)
if p_form.is_valid():
instance = p_form.save(commit=False)
instance.author = profile
instance.save()
p_form = PostModelForm()
post_added = True
if 'submit_cForm' in request.POST:
c_form = CommentModelForm(request.POST)
if c_form.is_valid():
instance = c_form.save(commit=False)
instance.user = profile
instance.post = Post.objects.get(id=request.POST.get('post_id'))
instance.save()
c_form = CommentModelForm()
context = {
'qs': qs,
'profile': profile,
'p_form': p_form,
'c_form': c_form,
'post_added': post_added,
'post_list': post_list,
}
return render(request, 'network/posts.html', context)
@login_required
def posts_of_following_profiles(request):
profile = Profile.objects.get(user=request.user)
users = [user for user in profile.following.all()]
posts = []
qs = None
for u in users:
p = Profile.objects.get(user=u)
p_posts = p.post_set.all()
posts.append(p_posts)
my_posts = profile.get_my_posts()
posts.append(my_posts)
if len(posts) > 0:
my_posts = sorted(chain(*posts), reverse=True, key=lambda obj: obj.created)
#Setting up pagination
p = Paginator(my_posts, 5)
page = request.GET.get('page')
post_list = p.get_page(page)
#Post form, comment form
p_form = PostModelForm()
c_form = CommentModelForm()
post_added = False
if 'submit_pForm' in request.POST:
print(request.POST)
p_form = PostModelForm(request.POST, request.FILES)
if p_form.is_valid():
instance = p_form.save(commit=False)
instance.author = profile
instance.save()
p_form = PostModelForm()
post_added = True
if 'submit_cForm' in request.POST:
c_form = CommentModelForm(request.POST)
if c_form.is_valid():
instance = c_form.save(commit=False)
instance.user = profile
instance.post = Post.objects.get(id=request.POST.get('post_id'))
instance.save()
c_form = CommentModelForm()
context = {
'posts': qs,
'profile': profile,
'p_form': p_form,
'c_form': c_form,
'post_added': post_added,
'post_list': post_list,
}
return render(request, 'network/followers_posts.html', context)
class PostDeleteView(LoginRequiredMixin, DeleteView):
model = Post
template_name = 'network/confirmDelete.html'
success_url = reverse_lazy('posts')
def get_object(self, *args, **kwargs):
pk = self.kwargs.get('pk')
obj = Post.objects.get(pk=pk)
if not obj.author.user == self.request.user:
messages.warning(self.request, 'You need to be the owner of the post in order to delete it!')
return obj
class PostUpdateView(LoginRequiredMixin, UpdateView):
form_class = PostModelForm
model = Post
template_name = 'network/update.html'
success_url = reverse_lazy('posts')
def form_valid(self, form):
profile = Profile.objects.get(user=self.request.user)
if form.instance.author == profile:
return super().form_valid(form)
else:
form.add_error(None, "You need to be the owner of the post in order to update it!")
return super().form_invalid(form)
def login_view(request):
if request.method == "POST":
# Attempt to sign user in
username = request.POST["username"]
password = request.POST["password"]
user = authenticate(request, username=username, password=password)
# Check if authentication successful
if user is not None:
login(request, user)
return HttpResponseRedirect(reverse("posts"))
else:
return render(request, "network/login.html", {
"message": "Invalid username and/or password."
})
else:
return render(request, "network/login.html")
def logout_view(request):
logout(request)
return HttpResponseRedirect(reverse("login"))
def register(request):
if request.method == "POST":
username = request.POST["username"]
email = request.POST["email"]
# Ensure password matches confirmation
password = request.POST["password"]
confirmation = request.POST["confirmation"]
if password != confirmation:
return render(request, "network/register.html", {
"message": "Passwords must match."
})
# Attempt to create new user
try:
user = User.objects.create_user(username, email, password)
user.save()
except IntegrityError:
return render(request, "network/register.html", {
"message": "Username already taken."
})
login(request, user)
return HttpResponseRedirect(reverse("all-profiles-view"))
else:
return render(request, "network/register.html")
网址:
from django.urls import path
from django.conf import settings
from django.conf.urls.static import static
from . import views
from .views import (
posts_of_following_profiles,
like_unlike_post,
invites_received_view,
invite_profiles_list_view,
send_invitation,
remove_friends,
accept_invitation,
reject_invitation,
search_view,
post_comment_create_view,
login_view,
logout_view,
register,
ProfileDetailView,
PostDeleteView,
PostUpdateView,
ProfileListView,
#EditProfileView,
)
urlpatterns = [
path("", ProfileListView.as_view(), name="all-profiles-view"),
path("posts/", views.post_comment_create_view, name="posts"),
path("posts-follow/", posts_of_following_profiles, name="posts-follow"),
path("login", views.login_view, name="login"),
path("logout", views.logout_view, name="logout"),
path("register", views.register, name="register"),
path("liked/", like_unlike_post, name="like-post-view"),
path("<pk>/delete", PostDeleteView.as_view(), name="post-delete"),
path("<pk>/update", PostUpdateView.as_view(), name="post-update"),
path("invites/", invites_received_view, name="invites-view"),
path("send-invite/", send_invitation, name="send-invite"),
path("remove-friend/", remove_friends, name="remove-friend"),
path("invites/accept/", accept_invitation, name="accept-invite"),
path("invites/reject/", reject_invitation, name="reject-invite"),
path("to-invite/", invite_profiles_list_view, name='invite-profiles-view'),
path("search/", views.search_view, name='search-view'),
path("<slug>", ProfileDetailView.as_view(), name="profile-view"),
]
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
型号:
from django.contrib.auth.models import User
from django.core import validators
from django.db import models
from itertools import chain
import random
from django.db.models.aggregates import Max
from django.shortcuts import reverse
from django.db.models.deletion import CASCADE
from .utils import get_random_code
from django.template.defaultfilters import slugify
from django.core.validators import FileExtensionValidator
from django.db.models import Q
class ProfileManager(models.Manager):
def get_all_profiles_to_invite(self, sender):
profiles = Profile.objects.all().exclude(user=sender)
profile = Profile.objects.get(user=sender)
qs = Relationship.objects.filter(Q(sender=profile) | Q(receiver=profile))
accepted = set([])
for rel in qs:
if rel.status == 'accepted':
accepted.add(rel.receiver)
accepted.add(rel.sender)
print(accepted)
available = [profile for profile in profiles if profile not in accepted]
return available
def get_all_profiles(self, me):
profiles = Profile.objects.all().exclude(user=me)
return profiles
class Profile(models.Model):
first_name = models.CharField(max_length=64, blank=True)
last_name = models.CharField(max_length=64, blank=True)
user = models.OneToOneField(User, on_delete=models.CASCADE)
country = models.CharField(max_length=64, blank=True)
avatar = models.ImageField(upload_to='avatars', default='avatar.png')
background = models.ImageField(upload_to='backgrounds', default='background.png')
following = models.ManyToManyField(User, related_name='following', blank=True)
bio = models.TextField(default="No Bio..")
updated = models.DateTimeField(auto_now=True)
created = models.DateTimeField(auto_now_add=True)
slug = models.SlugField(unique=True, blank=True)
objects = ProfileManager()
def __str__(self):
return f"{self.user.username}"
def get_absolute_url(self):
return reverse("profile-view", kwargs={"slug": self.slug})
__initial_first_name = None
__initial_last_name = None
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.__initial_first_name = self.first_name
self.__initial_last_name = self.last_name
def save(self, *args, **kwargs):
ex = False
to_slug = self.slug
if self.first_name != self.__initial_first_name or self.last_name != self.__initial_last_name or self.slug=="":
if self.first_name and self.last_name:
to_slug = slugify(str(self.first_name) + " " + str(self.last_name))
ex = Profile.objects.filter(slug=to_slug).exists()
while ex:
to_slug = slugify(to_slug + " " + str(get_random_code()))
ex = Profile.objects.filter(slug=to_slug).exists()
else:
to_slug = str(self.user)
self.slug = to_slug
super().save(*args, **kwargs)
def get_followers(self):
return self.following.all()
def get_followers_num(self):
return self.following.all().count()
def get_my_posts(self):
return self.post_set.all()
def get_country(self):
return self.post_set.all()
def get_following_users(self):
following_list = [p for p in self.get_following()]
return following_list
def get_followers_users(self):
following_list = [p for p in self.get_followers()]
return following_list
def get_all_posts(self):
users = [user for user in self.get_following()]
posts = []
qs = None
for u in users:
p = Profile.objects.get(user=u)
p_posts = p.post_set.all()
posts.append(p_posts)
my_posts = self.post_set.all()
posts.append(my_posts)
if len(posts) > 0:
qs = sorted(chain(*posts), reverse=True, key=lambda obj: obj.created)
return qs
def get_posts_num(self):
return self.post_set.all().count()
def get_all_authors_posts(self):
return self.post_set.all()
def get_likes_given_num(self):
likes = self.like_set.all()
total_liked = 0
for item in likes:
if item.value == 'Like':
total_liked += 1
return total_liked
def get_likes_received_num(self):
posts = self.post_set.all()
total_liked = 0
for item in posts:
total_liked += item.all().count()
return total_liked
def get_proposals_for_following(self):
profiles = Profile.objects.all().exclude(user=self.user)
followers_list = [p for p in self.get_following()]
available = [p.user for p in profiles if p.user not in followers_list]
random.shuffle(available)
return available[:3]
STATUS_CHOICES = (
('send', 'send'),
('accepted', 'accepted')
)
class RelationshipManager(models.Manager):
def invitations_received(self, receiver):
qs = Relationship.objects.filter(receiver=receiver, status='send')
return qs
class Relationship(models.Model):
sender = models.ForeignKey(Profile, on_delete=models.CASCADE, related_name='sender')
receiver = models.ForeignKey(Profile, on_delete=models.CASCADE, related_name='receiver')
status = models.CharField(max_length=8, choices=STATUS_CHOICES)
updated = models.DateTimeField(auto_now=True)
created = models.DateTimeField(auto_now_add=True)
objects = RelationshipManager()
def __str__(self):
return f"{self.sender}-{self.receiver}-{self.status}"
class Post(models.Model):
# id is created automatically by Django
picture = models.ImageField(upload_to='images', blank=True, validators=[FileExtensionValidator(['png', 'jpg', 'jpeg'])])
content = models.TextField()
liked = models.ManyToManyField(Profile, blank=True, related_name="likes")
author = models.ForeignKey(Profile, on_delete=models.CASCADE, null=True)
updated = models.DateTimeField(auto_now=True)
created = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ('-created',)
def __str__ (self):
return str(self.content[:20])
def num_likes(self):
return self.liked.all().count()
@property
def like_count(self):
return self.liked.all().count()
def get_user_liked(self, user):
pass
# Number of comments
def num_comments(self):
return self.comment_set.all.count()
class Comment(models.Model):
user = models.ForeignKey(Profile, on_delete=models.CASCADE)
post = models.ForeignKey(Post, on_delete=models.CASCADE)
body = models.TextField(max_length=250)
updated = models.DateTimeField(auto_now=True)
created = models.DateTimeField(auto_now_add=True)
def __str__(self):
return str(self.pk)
LIKE_CHOICES = (
('Like', 'Like'),
('Unlike', 'Unlike'),
)
class Like(models.Model):
user = models.ForeignKey(Profile, on_delete=models.CASCADE)
post = models.ForeignKey(Post, on_delete=models.CASCADE)
value = models.CharField(choices=LIKE_CHOICES, max_length=8)
updated = models.DateTimeField(auto_now=True)
created = models.DateTimeField(auto_now_add=True)
def __str__(self):
return f"{self.user}-{self.post}-{self.value}"
def like_numb(self):
return self.like.all().count()
设置:
import os
import django_heroku
import dj_database_url
from decouple import config
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/3.0/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = secretkey
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = []
# Application definition
INSTALLED_APPS = [
'crispy_forms',
'network',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'django.contrib.humanize',
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'whitenoise.middleware.WhiteNoiseMiddleware',
]
ROOT_URLCONF = 'project4.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': (BASE_DIR, 'network/templates'),
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
WSGI_APPLICATION = 'project4.wsgi.application'
# Database
# https://docs.djangoproject.com/en/3.0/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3')
}
}
# Password validation
# https://docs.djangoproject.com/en/3.0/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
# Internationalization
# https://docs.djangoproject.com/en/3.0/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.0/howto/static-files/
STATIC_URL = 'network/static/'
STATICFILES_DIRS = (BASE_DIR, 'network/static')
STATICFILES_STORAGE = 'whitenoise.storage.CompressManifestStaticFilesStorage'
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR,'media')
DEFAULT_AUTO_FIELD = 'django.db.models.AutoField'
django_heroku.settings(locals())
首先,您必须设置 LOGIN_URL
和 LOGIN_REDIRECT_URL
在你的 settings.py 文件中,像这样
LOGIN_URL = '/login'
LOGIN_REDIRECT_URL = '/'
第二次登录到您的 heroku cli 并运行此命令
$ heroku run bash
这将为您打开一个 bash,您可以从那里访问您的项目文件 你必须导航到你的项目根目录 (manage.py 所在的位置) 然后 运行 这两个命令
$ python manage.py makemigrations network
$ python manage.py migrate
$ python manage.py createsuperuser