这里的第一个问题是,我对编程还比较陌生,而我却因遇到的错误而为Days烦恼:
目的是按照我想在django项目中实现的在线教程,使用Django Channels创建用户到用户的“消息传递”。我已经缩小了错误的范围,因为我使用的Auth模型与我如何对其进行查询,URL /路径语法错误或错字有关?经过如此多的研究,我迷失了。
当我在浏览器中键入localhost:8000 / messages / jarturoch时,出现以下错误:
/ messages / jarturoch /中的TypeError /
'NoneType'对象不可迭代
请求方法:GET
请求网址:http://localhost:8000/messages/jarturoch/
Django版本:2.0.2
异常类型:TypeError
异常值:
'NoneType'对象不可迭代
异常位置:get_object,第26行中的
/home/jarturoch/Desktop/pythondev/django_projects/quekieres-main/qkchat/views.py
Python可执行文件:
/ home / jarturoch / Desktop / pythondev / django_projects / myvenv / bin / python Python版本:3.6.3 Python路径:
['/ home / jarturoch / Desktop / pythondev / django_projects / quekieres-main', '/home/jarturoch/Desktop/pythondev/django_projects/myvenv/lib/python36.zip', '/home/jarturoch/Desktop/pythondev/django_projects/myvenv/lib/python3.6', '/home/jarturoch/Desktop/pythondev/django_projects/myvenv/lib/python3.6/lib-dynload', '/home/jarturoch/anaconda3/lib/python3.6', '/home/jarturoch/Desktop/pythondev/django_projects/myvenv/lib/python3.6/site-packages']
在回溯之前,控制台会向我显示此500 Internal Server Error:
在这种情况下,2018/07/19 14:08:20] HTTP GET / messages / jarturoch / 500 [0.16,127.0.0.1:53212] 内部服务器错误:/ messages / jarturoch /
jarturoch 是主要的登录用户。
如果我输入:localhost:8000 / messages / jones 琼斯是另一位注册用户。
我得到一个带有聊天功能的页面,如下所示:
chat page for other_username I assume as this is not the logged in user, which is functional
这里是django调试的回溯:
跟踪:
内部文件“ /home/jarturoch/Desktop/pythondev/django_projects/myvenv/lib/python3.6/site-packages/django/core/handlers/exception.py” 35. response = get_response(request)
_get_response中的文件“ /home/jarturoch/Desktop/pythondev/django_projects/myvenv/lib/python3.6/site-packages/django/core/handlers/base.py” 128. response = self.process_exception_by_middleware(e,request)
_get_response中的文件“ /home/jarturoch/Desktop/pythondev/django_projects/myvenv/lib/python3.6/site-packages/django/core/handlers/base.py” 126. response = wrapd_callback(request,* callback_args,** callback_kwargs)
视图中的文件“ /home/jarturoch/Desktop/pythondev/django_projects/myvenv/lib/python3.6/site-packages/django/views/generic/base.py” 69. return self.dispatch(request,* args,** kwargs)
文件“ /home/jarturoch/Desktop/pythondev/django_projects/myvenv/lib/python3.6/site-packages/django/contrib/auth/mixins.py”在分发中 52. return super()。dispatch(request,* args,** kwargs)
文件“ /home/jarturoch/Desktop/pythondev/django_projects/myvenv/lib/python3.6/site-packages/django/views/generic/base.py”已分发 89. return handler(request,* args,** kwargs)
获取文件“ /home/jarturoch/Desktop/pythondev/django_projects/myvenv/lib/python3.6/site-packages/django/views/generic/detail.py” 105. self.object = self.get_object()
文件“ /home/jarturoch/Desktop/pythondev/django_projects/quekieres-main/qkchat/views.py”,get_object中的第26行
obj,创建=> Thread.objects.get_or_new(self.request.user,other_username)异常类型:/ messages / jarturoch /中的TypeError 异常值:“ NoneType”对象不可迭代
Settings.py 文件包含以下片段:
#mainproject settings.py
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
# my apps
'products.apps.ProductsConfig',
'accounts.apps.AccountsConfig',
'ecommerce',
'qkchat',
# 3rd party apps
'social_django',
'channels',
]
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',
]
ROOT_URLCONF = 'quekieres.urls'
WSGI_APPLICATION = 'quekieres.wsgi.application'
# Channels app config - asgi
ASGI_APPLICATION = 'quekieres.routing.application'
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'quekieres/static/')
]
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
STATIC_URL = '/static/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'
try:
from .local_settings import *
except ImportError:
pass
AUTHENTICATION_BACKENDS = (
'social_core.backends.open_id.OpenIdAuth', # for Google authentication
'social_core.backends.google.GoogleOpenId', # for Google authentication
'social_core.backends.google.GoogleOAuth2', # for Google authentication
'social_core.backends.facebook.FacebookOAuth2', # for Facebook auth
'social_core.backends.twitter.TwitterOAuth', # for twitter auth
'django.contrib.auth.backends.ModelBackend', # ensures user can still login through django auth model backend
)
LOGIN_URL = 'login'
LOGIN_REDIRECT_URL = 'home'
SOCIAL_AUTH_GOOGLE_OAUTH2_KEY = ''
SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET = ''
SOCIAL_AUTH_FACEBOOK_KEY = ''
SOCIAL_AUTH_FACEBOOK_SECRET = ''
SOCIAL_AUTH_TWITTER_KEY = ''
SOCIAL_AUTH_TWITTER_SECRET = ''
CHANNEL_LAYERS = {
"default": {
"BACKEND": "channels_redis.core.RedisChannelLayer",
"CONFIG": {
"hosts": [("localhost", 6379)],
# "hosts": [(os.environ.get('REDIS_URL', 'redis://localhost:6379')] FOR PRODUCTION
},
},
}
routing.py -驻留在主项目应用程序(settings.py所在的位置)
from django.conf.urls import url
from channels.routing import ProtocolTypeRouter, URLRouter
from channels.auth import AuthMiddlewareStack
from channels.security.websocket import AllowedHostsOriginValidator, OriginValidator
from qkchat.consumers import ChatConsumer
application = ProtocolTypeRouter({
# Empty for now (http->django views is added by default)
'websocket': AllowedHostsOriginValidator(
AuthMiddlewareStack(
URLRouter([
url(r'^messages/(?P<username>[\w.@+-]+)/$', ChatConsumer),
])
)
)
})
urls.py -来自主应用程序
from django.contrib import admin
from django.urls import path, include, re_path
from django.conf import settings
from django.conf.urls.static import static
from products import views
# from products.views import ProductListView, ProductDetailView
urlpatterns = [
path('admin/', admin.site.urls),
path('', views.home, name='home'),
path('accounts/', include('accounts.urls')),
# path('products/', ProductListView.as_view()),
path('products/', include('products.urls')),
path('auth/', include('social_django.urls', namespace='social')), # social django url for oauth etc
path('about/', views.about, name='about'),
path('contact/', views.contact, name='contact'),
path('ecom_home', views.ecom_home, name='ecom_home'),
path('messages/', include('qkchat.urls')),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
聊天应用Views.py *注意-如果我访问localhost:8000 / messages /,则下面的InboxView没问题。
from django.contrib.auth.mixins import LoginRequiredMixin
from django.http import Http404, HttpResponseForbidden
from django.shortcuts import render
from django.urls import reverse
from django.views.generic.edit import FormMixin
from django.views.generic import DetailView, ListView
from .forms import ComposeForm
from .models import Thread, ChatMessage
class InboxView(LoginRequiredMixin, ListView):
template_name = 'qkchat/inbox.html'
def get_queryset(self):
return Thread.objects.by_user(self.request.user)
class ThreadView(LoginRequiredMixin, FormMixin, DetailView):
template_name = 'qkchat/thread.html'
form_class = ComposeForm
success_url = './'
def get_queryset(self):
return Thread.objects.by_user(self.request.user)
def get_object(self):
other_username = self.kwargs.get('username')
obj, created = Thread.objects.get_or_new(self.request.user, other_username)
if obj == None:
raise Http404
return obj
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['form'] = self.get_form()
return context
def post(self, request, *args, **kwargs):
if not request.user.is_authenticated:
return HttpResponseForbidden()
self.object = self.get_object()
form = self.get_form()
if form.is_valid():
return self.form_valid(form)
else:
return self.form_invalid(form)
def form_valid(self, form):
thread = self.get_object()
user = self.request.user
message = form.cleaned_data.get("message")
ChatMessage.objects.create(user=user, thread=thread, message=message)
return super().form_valid(form)
urls.py -通过聊天应用程序
from django.urls import path, re_path
# from qkchat import views
from .views import ThreadView, InboxView
app_name = 'qkchat'
urlpatterns = [
path('', InboxView.as_view()),
re_path(r'^(?P<username>[\w.@+-]+)/$', ThreadView.as_view()),
]
models.py -来自聊天应用程序
*注意-如果我删除if username == other_username:从下面的代码中返回None,则从上面的chap应用views.py中引发404错误。
from django.db import models
from django.conf import settings
from django.db.models import Q
class ThreadManager(models.Manager):
def by_user(self, user):
qlookup = Q(first=user) | Q(second=user)
qlookup2 = Q(first=user) & Q(second=user)
qs = self.get_queryset().filter(qlookup).exclude(qlookup2).distinct()
return qs
def get_or_new(self, user, other_username): # get_or_create
username = user.username
if username == other_username:
return None
qlookup1 = Q(first__username=username) & Q(second__username=other_username)
qlookup2 = Q(first__username=other_username) & Q(second__username=username)
qs = self.get_queryset().filter(qlookup1 | qlookup2).distinct()
if qs.count() == 1:
return qs.first(), False
elif qs.count() > 1:
return qs.order_by('timestamp').first(), False
else:
Klass = user.__class__
user2 = Klass.objects.get(username=other_username)
if user != user2:
obj = self.model(
first=user,
second=user2
)
obj.save()
return obj, True
return None, False
class Thread(models.Model):
first = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='chat_thread_first')
second = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='chat_thread_second')
updated = models.DateTimeField(auto_now=True)
timestamp = models.DateTimeField(auto_now_add=True)
objects = ThreadManager()
@property
def room_group_name(self):
return f'chat_{self.id}'
def broadcast(self, msg=None):
if msg is not None:
broadcast_msg_to_chat(msg, group_name=self.room_group_name, user='admin')
return True
return False
class ChatMessage(models.Model):
thread = models.ForeignKey(Thread, null=True, blank=True, on_delete=models.SET_NULL)
user = models.ForeignKey(settings.AUTH_USER_MODEL, verbose_name='sender', on_delete=models.CASCADE)
message = models.TextField()
timestamp = models.DateTimeField(auto_now_add=True)
forms.py -来自聊天应用程序
from django import forms
class ComposeForm(forms.Form):
message = forms.CharField(
widget=forms.TextInput(
attrs={"class": "form-control",
}
)
)
consumers.py -通过聊天应用程序
import json
import asyncio
from django.contrib.auth import get_user_model
# from django.contrib.auth.models import User
from channels.consumer import AsyncConsumer
from channels.db import database_sync_to_async
from .models import Thread, ChatMessage
class ChatConsumer(AsyncConsumer):
async def websocket_connect(self, event):
print("connected", event)
other_user = self.scope['url_route']['kwargs']['username']
me = self.scope['user']
# print(other_user, me)
thread_obj = await self.get_thread(me, other_user)
self.thread_obj = thread_obj
chat_room = f"thread_{thread_obj.id}"
self.chat_room = chat_room
# await asyncio.sleep(10)
await self.channel_layer.group_add(
chat_room,
self.channel_name,
)
await self.send({
"type": "websocket.accept",
})
async def websocket_receive(self, event):
# when a message is received from the websocket
print("receive", event)
front_text = event.get('text', None)
if front_text is not None:
loaded_dict_data = json.loads(front_text)
msg = loaded_dict_data.get('message')
print(msg)
user = self.scope['user']
username = 'default'
if user.is_authenticated:
username = user.username
myResponse = {
'message': msg,
'username': username,
}
await self.create_chat_message(user, msg)
# broadcasts the message event to be sent
await self.channel_layer.group_send(
self.chat_room,
{
"type": "chat_message",
"text": json.dumps(myResponse),
}
)
async def chat_message(self, event):
# sends the message
print('message', event)
await self.send({
"type": "websocket.send",
"text": event['text'],
})
async def websocket_disconnect(self, event):
print("disconnected", event)
@database_sync_to_async
def get_thread(self, user, other_username):
return Thread.objects.get_or_new(user, other_username)[0]
@database_sync_to_async
def create_chat_message(self, me, msg):
thread_obj = self.thread_obj
# me = self.scope['user']
return ChatMessage.objects.create(thread=thread_obj, user=me, message=msg)
thread.html -来自聊天应用程序模板
{% extends "base.html" %}
{% block content %}
<br />
<h5>Mensajes de: {% if user != object.first %}{{ object.first }}{% else %}{{ object.second }}{% endif %}</h5>
<hr>
<ul id='chat-items'>
{% for chat in object.chatmessage_set.all %}
<li>{{ chat.message }} via {{ chat.user }}</li>
{% endfor %}
</ul>
<form id='form' method='POST'>
{% csrf_token %}
<input type="hidden" id="myUsername" value="{{ user.username }}" />
{{ form.as_p }}
<input type='submit' class='btn btn-primary'/>
</form>
{% endblock %}
{% block script %}
<script src='https://cdnjs.cloudflare.com/ajax/libs/reconnecting-websocket/1.0.0/reconnecting-websocket.js'> </script>
<script>
// websocket scripts
// console.log(window.location)
var loc = window.location
var wsStart = 'ws://'
if (loc.protocol == 'https:'){
wsStart = 'wss://'
}
var endpoint = wsStart + loc.host + loc.pathname
var socket = new ReconnectingWebSocket(endpoint)
// Below is JQuery but could be anything like Angular/React etc
var formData = $("#form")
var msgInput = $("#id_message")
var chatHolder = $("#chat-items")
var me = $("#myUsername").val()
socket.onmessage = function(e){
console.log("message", e)
var chatDataMsg = JSON.parse(e.data)
chatHolder.append("<li>" + chatDataMsg.message + " via " + chatDataMsg.username + "</li>")
}
socket.onopen = function(e){
console.log("open", e)
formData.submit(function(event){
event.preventDefault()
var msgText = msgInput.val()
// chatHolder.append("<li>" + msgText + " via " + me + "</li>")
// var formDataSerialized = formData.serialize()
var finalData = {
'message': msgText
}
socket.send(JSON.stringify(finalData))
// msgInput.val('')
formData[0].reset()
})
}
socket.onerror = function(e){
console.log("error", e)
}
socket.onclose = function(e){
console.log("close", e)
}
</script>
{% endblock %}
我刚刚注意到这可能要花很多钱,也许我在没有必要知识的情况下过度开发,但是因此而学到了很多。
非常感谢您抽出宝贵的时间。
致谢
答案 0 :(得分:0)
登录用户尝试查看自己的消息时,您将返回NoneType对象。
如果您以管理员身份登录并创建一个名为weakling的用户并转到/ messages / weakling,您将拥有一个可与您的代码一起使用的对象。
答案 1 :(得分:0)
我知道您为什么收到此错误。您正在输入登录用户的用户名。您必须输入其他用户的用户名。
例如。我已经以#include <algorithm>
#include <iostream>
class Container
{
public:
// constructors
Container() = default() // no allocation!
Container(int len) : length(len) {
data = new double[len];
}
// destructor
~Container() {
releaseMemory_();
}
// Copy ctor
Container(const Container& other) : Container(other.length) {
if (data != nullptr) { std::copy(data, data + length, other.data); }
}
// Move ctor
Container(Container&& other) {
std::swap(length, other.length);
std::swap(data, other.data);
}
// Assignment operator
Container& operator=(const Container& other) {
releaseMemory_();
this->length = other.length;
if (other.data != nullptr) {
this->data = new double[length];
std::copy(this->data, this->data + length, other.data);
}
}
// Other stuff ...
private:
int length = 0;
double* data = nullptr;
void releaseMemory_() {
if (data != nullptr) {
delete[] data;
data = nullptr;
}
}
};
的身份登录,并且想与Ajay
聊天,所以我需要在URL中输入用户名作为Vishal
。因为它是用代码编写的,所以如果登录的\messages\Vishal\
和username
匹配,则返回None并引发Error。