1

I'm trying to create a basic django-rest-framework backend with mongoengine as a database. I have successfully made a basic list of entries which supports POST and behaves as needed with required fields.

However I encounter this bug with QuerySet not having attribute 'model'. Of what I've seen in the web - people get this kind of bug when putting a filtered collection in object. However in my case it is different(I believe). The error appears when I'm accessing /box/1 endpoint.

The source codes as below:

models.py:

from __future__ import unicode_literals

import datetime
from mongoengine import Document, connect, EmbeddedDocument, fields, DynamicDocument
from django.db import models

# Create your models here.
from mongoengine import signals

connect('yourdb', alias='default')

class GPS(EmbeddedDocument):
    lat = fields.FloatField(null=False, required=True)
    lon = fields.FloatField(null=False, required=True)


class PPM(EmbeddedDocument):
    time = fields.DateTimeField(default=datetime.datetime.now())
    value = fields.IntField(null=False, required=True)

    @classmethod
    def pre_save(cls, sender, document, **kwargs):
        document.time = datetime.datetime.now()


signals.pre_save.connect(PPM.pre_save, sender=PPM)

class BuyHistory(EmbeddedDocument):
    time = fields.DateTimeField(default=datetime.datetime.now())
    boxid = fields.StringField(max_length=128, null=False, required=True)
    username = fields.StringField(max_length=128, null=False, required=True)
    product = fields.StringField(max_length=128, null=False, required=True)
    amount = fields.IntField()

    @classmethod
    def pre_save(cls, sender, document, **kwargs):
        document.time = datetime.datetime.now()


signals.pre_save.connect(BuyHistory.pre_save, sender=BuyHistory)

class RecycleHistory(EmbeddedDocument):
    time = fields.DateTimeField(default=datetime.datetime.now())
    boxid = fields.StringField(max_length=128, null=False, required=True)
    username = fields.StringField(max_length=128, null=False, required=True)
    amount = fields.IntField()

    @classmethod
    def pre_save(cls, sender, document, **kwargs):
        document.time = datetime.datetime.now()


signals.pre_save.connect(RecycleHistory.pre_save, sender=RecycleHistory)

class Box(Document):
    boxid = fields.StringField(max_length=128, null=False, required=True)
    gps = fields.EmbeddedDocumentField(GPS, required=True)
    buy_history = fields.EmbeddedDocumentListField(BuyHistory, default='[]')
    recycle_history = fields.EmbeddedDocumentListField(RecycleHistory, default='[]')
    ppm_history = fields.EmbeddedDocumentListField(PPM, default='[]')

class User(Document):
    username = fields.StringField(max_length=128, null=False, required=True)
    rfid = fields.StringField(max_length=32, null=False, required=True)
    buy_history = fields.EmbeddedDocumentListField(BuyHistory)
    recycle_history = fields.EmbeddedDocumentListField(RecycleHistory)

serializers.py:

from rest_framework_mongoengine import serializers
from models import User, BuyHistory, Box, RecycleHistory, PPM

class UserSerializer(serializers.DocumentSerializer):
    class Meta:
        model = User
        fields = ('username', 'rfid', 'buy_history', 'recycle_history')


class PPMSerializer(serializers.DocumentSerializer):
    class Meta:
        model = PPM
        fields = ('time', 'value')


class BuyHistorySerializer(serializers.EmbeddedDocumentSerializer):
    class Meta:
        model = BuyHistory
        fields = ('time', 'boxid', 'username', 'product', 'amount')


class RecycleHistorySerializer(serializers.EmbeddedDocumentSerializer):
    class Meta:
        model = RecycleHistory
        fields = ('time', 'boxid', 'username', 'product', 'amount')


class BoxSerializer(serializers.DocumentSerializer):

    class Meta:
        model = Box
        fields = ('boxid', 'gps', 'buy_history', 'recycle_history', 'ppm_history')

views.py:

from models import User, Box
from serializers import UserSerializer, BoxSerializer
from rest_framework import generics
# Create your views here.


class BoxList(generics.ListCreateAPIView):
    queryset = Box.objects.all()
    serializer_class = BoxSerializer

class UserList(generics.ListCreateAPIView):
    queryset = User.objects.all()
    serializer_class = UserSerializer


class BoxDetail(generics.RetrieveUpdateDestroyAPIView):
    queryset = Box.objects.all()
    serializer_class = BoxSerializer(partial=True)


class UserDetail(generics.RetrieveUpdateDestroyAPIView):
    queryset = User.objects.all()
    serializer_class = UserSerializer(partial=True)

urls.py:

from django.conf.urls import url
from django.contrib import admin
from server_api import views

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^box/$', views.BoxList.as_view()),
    url(r'^box/(?P<pk>[0-9]+)$', views.BoxDetail.as_view()),
    url(r'^user/$', views.UserList.as_view()),
]

settings.py:

import os

# 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/1.10/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = '08v0)(rn8ae8%v9li=he7n9)50q5^wre8srx*m#0_idvcu=jew'

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

ALLOWED_HOSTS = []


# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'rest_framework',
    'server_api.apps.ServerApiConfig'
]

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 = 'pmi_pos_server_django.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [],
        '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 = 'pmi_pos_server_django.wsgi.application'


# Database
# https://docs.djangoproject.com/en/1.10/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/1.10/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/1.10/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/1.10/howto/static-files/

STATIC_URL = '/static/'

Versions: enter image description here

Also, I would really appreciate if someone could suggest a very detailed tutorial about Django, I have read Django-Rest-Framework classic tutorial, quickstart and API-reference, however I still feel that information is not enough for me - if there's any good in-depth tutorial to be suggested - please do it.

EDIT 1:

Tracelog:

Traceback (most recent call last):
  File "/usr/local/lib/python2.7/site-packages/django/core/handlers/exception.py", line 39, in inner
    response = get_response(request)
  File "/usr/local/lib/python2.7/site-packages/django/core/handlers/base.py", line 187, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File "/usr/local/lib/python2.7/site-packages/django/core/handlers/base.py", line 185, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/usr/local/lib/python2.7/site-packages/django/views/decorators/csrf.py", line 58, in wrapped_view
    return view_func(*args, **kwargs)
  File "/usr/local/lib/python2.7/site-packages/django/views/generic/base.py", line 68, in view
    return self.dispatch(request, *args, **kwargs)
  File "/usr/local/lib/python2.7/site-packages/rest_framework/views.py", line 477, in dispatch
    response = self.handle_exception(exc)
  File "/usr/local/lib/python2.7/site-packages/rest_framework/views.py", line 437, in handle_exception
    self.raise_uncaught_exception(exc)
  File "/usr/local/lib/python2.7/site-packages/rest_framework/views.py", line 474, in dispatch
    response = handler(request, *args, **kwargs)
  File "/usr/local/lib/python2.7/site-packages/rest_framework/generics.py", line 283, in get
    return self.retrieve(request, *args, **kwargs)
  File "/usr/local/lib/python2.7/site-packages/rest_framework/mixins.py", line 56, in retrieve
    instance = self.get_object()
  File "/usr/local/lib/python2.7/site-packages/rest_framework/generics.py", line 97, in get_object
    obj = get_object_or_404(queryset, **filter_kwargs)
  File "/usr/local/lib/python2.7/site-packages/rest_framework/generics.py", line 20, in get_object_or_404
    return _get_object_or_404(queryset, *filter_args, **filter_kwargs)
  File "/usr/local/lib/python2.7/site-packages/django/shortcuts.py", line 92, in get_object_or_404
    except queryset.model.DoesNotExist:
AttributeError: 'QuerySet' object has no attribute 'model'
1
  • 1
    You should have provided your trace log Commented Nov 28, 2016 at 5:11

2 Answers 2

1

You are doing this

serializer_class = BoxSerializer(partial=True)

this is invalid code, because you are instantiating serializer here, so serializer instance will be stored in serializer_class variable not a class

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you for advice. I fixed it, however the bug still reproduces. However regarding serializer instantiation - then where do I need to declare partial=True? I want to do it in order to allow partial updates on nested lists because they are meant to accumulate data, and as I read with classic UPDATE I have to provide a new object to completely change the existing one.
@ConstantineSamoilenko there is get_serializer method You can set it there
1

Ok, I have found a problem - I changed the generics import - now I'm using from rest_framework_mongoengine import generics. I assume the conflict was that it couldn't find model parameter of queryset because it was not in default database from config.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.