Django raise ValidationException on id field when testing abstract model - django

I have an abstract django model like this:
from django.db import models
class BaseModel(models.Model):
created_at = models.DateTimeField(auto_now_add=True)
class Meta:
abstract = True
When testing this class using following code:
from django.test import TestCase
from django.db import models
from core.models import BaseModel
class BaseModelTest(TestCase):
def test_1(self):
class SimpleClass(BaseModel):
name = models.CharField(max_length=10)
simple = SimpleClass(name="test")
simple.save()
simple.full_clean()
...
I get following error:
django.core.exceptions.ValidationError: {'id': ['ā€œ6072d8ce3c23022d0694ae8eā€ value must be an integer.']}
I'm using mongodb as my database. There is no such error when I delete abstract = True.

MongoDB isn't supported by Django: https://docs.djangoproject.com/en/3.2/ref/databases/
Also testing of the django internals aren't necessary. With the code provided you are not actually testing your class since you are creating a new one in the test method. I don't understand the calling of full_clean either.
You may check this out: https://django-mongodb-engine.readthedocs.io/en/latest/index.html

Related

Model constraints are not working with Faker ( Django )

I am just starting to use pytest and faker for testing
while trying to create text for a field in testing db the constraints are being ignored and i don't know how to fix it.
models.py
from django.db import models
# Create your models here.
class Note(models.Model):
body = models.TextField(null=True, blank=True, max_length=5)
updated = models.DateTimeField(auto_now=True)
created = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.body[0:50]
factories.py
import factory
from faker import Faker
fake = Faker()
from mynotes_api.models import Note
class NoteFactory(factory.django.DjangoModelFactory):
class Meta:
model = Note
body = fake.text()
conftest.py
import pytest
from django.contrib.auth.models import User
from pytest_factoryboy import register
from tests.factories import NoteFactory
register(NoteFactory)
#pytest.fixture
def new_user1(db, note_factory):
note = note_factory.create()
return note
test_ex1.py
import pytest
def test_product(new_user1):
note = new_user1
print(note.body)
assert True
test output
the problem as visible in output is that the length of the text generated and being stored in the testing db is more than 5.
kindly guide me in this regard.
Iain Shelvington's advice to use a CharField is the main issue here. It will enforce the database constraint.
Django offers more types of validation that cannot be enforced by the database. These will not be checked on a model.save call:
Note that validators will not be run automatically when you save a
model, but if you are using a ModelForm, it will run your validators
on any fields that are included in your form.
See How validators are run.

How to rename GraphQL type field autogenerated from Django model?

I've a model in Django with some fields. Let's say this exemplary one:
# <app>/models.py
from django.db import models
class Something(models.Model):
first_field = models.Charfield()
second_field = models.Charfield()
I use DjangoObjectType from graphene_django to map Django models to GraphQL types.
# <app>/schema.py
from graphene_django import DjangoObjectType
from .models import Something
class SomethingType(DjangoObjectType):
class Meta:
model = Something
Cause of auto camelcasing the model field second_field results in secondField in the GraphQL type. Now I'd like to rename the GraphQL type field from secondField to somethingFancy. How can I get this done easiest?
You can overwrite any field with DjangoObjectType. Your code may look like this.
class SomethingType(DjangoObjectType):
class Meta:
model = Something
something_fency = graphene.String()
def resolve_something_fency(self, info):
return self.second_field
For more details check out the docs

Serialize foreign key object that is AbstractUser

I am serializing a model using the Django REST framework successfully, but would like to add a field from a related model. I have seen other posts describe how to do this using nested serializers, however mine is different because the other model I am trying to access is an AbstractUser class.
I would like to serialize the UserDefinedEquipName field from CustomUser.
models (some fields removed for clarity):
accounts/models.py
from django.contrib.auth.models import AbstractUser
class CustomUser(AbstractUser):
UserDefinedEquipName = models.CharField(max_length=50, default = "Default equip",)
....
builds/models.py
from accounts.models import CustomUser
from django.contrib.auth import get_user_model
class Build(models.Model):
author = models.ForeignKey(get_user_model(),on_delete=models.CASCADE,)
machineName = models.OneToOneField(max_length=50,blank=True,)
....
So my thought is to pass the value into the serializer but can't seem to figure out how to access the value without getting error AttributeError: type object 'Build' has no attribute 'CustomUser'
I have tried:
My serializers.py:
from rest_framework import serializers
from .models import Data, Build, CustomUser
from django.contrib.auth.models import AbstractUser
class buildStatsAPI_serializer(serializers.ModelSerializer):
equipName = Build.CustomUser.UserDefinedEquipName
#also tried:
#equipName = Build.CustomUser__set.all()
class Meta:
fields = ('id','author','machineName','equipName',)
model = Build
Am I missing something small here? Or is there a much better way of doing this. It seems like if this wasn't an AbstractUser class it would be much easier.
EDIT - Added views.py
class buildStatsAPI(generics.ListCreateAPIView):#for build stats JSON
permission_classes = (permissions.IsAuthenticated,)
serializer_class = buildStatsAPI_serializer
def get_queryset(self):
machinesOwned =CustomUser.objects.filter(customerTag=self.request.user.customerTag).filter(isDevice=True)
machineList = []
for machine in machinesOwned:
machineList = machineList + [machine.id]
query = Build.objects.filter(deleted=0, author_id__in=machineList,).values().order_by('pk')
return query
I think you are defining the Serializer improperly. You can't directly reference Model in a serializer. You need to use any kind of fields. For example, if you use SerializerMethodField, you can try like this:
class buildStatsAPI_serializer(serializers.ModelSerializer):
equipName = serializers.SerializerMethodField()
class Meta:
fields = ('id','author','machineName','equipName',)
model = Build
def get_equipName(self, obj):
# here obj is a build model object
return obj.author.UserDefinedEquipName
Update
Please update your get_queryset method so that it returns a queryset like this(I have refactored it a bit):
def get_queryset(self):
query = Build.objects.filter(deleted=0, author__customerTag=self.request.user.customerTag, author__isDevice=True) # removed .values() because it will return a dictionary
return query

Meta.filter_overrides for IntegerRangeField in django filter view

Using the example in the Django documentation for utilizing IntergerRangeField with Postgres backend to create ranges in "ages" with the following model:
from django.contrib.postgres.fields import IntegerRangeField
from psycopg2.extras import NumericRange
from django.db import models
class Event(models.Model):
name = models.CharField(max_length=200)
ages = IntegerRangeField()
def __str__(self):
return self.name
This works perfectly however when using Django Rest Frameworks and using filter view with the following filter:
import django_filters
from django_filters import rest_framework as filters
from app import Event
class EventFilter(django_filters.FilterSet):
ages = django_filters.NumericRangeFilter(queryset=Event.objects.all())
class Meta:
model = Event
fields = ['name','ages']
the view generates an AssertionError at /api/event_filter/ and suggests adding an override to Meta.filters_override.
What I would really appreciate is an example based on the example model for this override, the example in django-filters documentation http://django-filter.readthedocs.io/en/latest/ref/filterset.html#filter-overrides, isn't helping me understand how to get this to render. I would appreciate any help with this so I can understand with this example to utilize this in the future.
Based on the documentation, overriding custom option seems to be done inside the Meta class and not the way you have done it.
ages = django_filters.NumericRangeFilter(queryset=Event.objects.all())
There are a few potential issues here:
The declaration itself does not seem supported
The overrides appear to be supported from within the Meta class
queryset is not a valid option for NumericRangeFilter AFAIk
Can you try the following:
from django.contrib.postgres.fields import IntegerRangeField
class EventFilter(django_filters.FilterSet):
class Meta:
model = Event
fields = ['name','ages']
filter_overrides = {
IntegerRangeField: {
'filter_class': django_filters.NumericRangeFilter,
}
}
Working on a similar thing.
from django.contrib.postgres.fields import ArrayField
import django_filters
class SkillFilter(django_filters.Filters):
class Meta:
model = Skill
filter_overrides = {
ArrayField: {
'filter_class': django_filters.CharFilter,
'extra': lambda f: {
'lookup_expr': 'icontains',
},
},
}
class SkillType(DjangoObjectType):
class Meta:
model = Skill
filterset_class = SkillFilter
interfaces = (relay.Node, )
Then my model
from django.contrib.postgres.fields import ArrayField
from django.db import models
class Skill(models.Model):
name = models.CharField(max_length=50)
skills = ArrayField(models.CharField(max_length=200), blank=True)
Doing this solves the problem, hopefully you can leverage on this to get a solution
Note: I think django_filters does not have support for an array filter that is why I used the CharFilter and this works for me

ModelForm is_valid() always return false during unit testing

I have a simple Django code.
there is my model and form in models.py file:
from django.db import models
from django.forms import ModelForm
class Supplier(models.Model):
name = models.CharField(max_length=55)
comment = models.TextField(blank=True)
class SupplierForm(ModelForm):
class Meta:
model = Supplier
and there is my test.py:
from django.test import TestCase
from mysite.myapp.models import Supplier, SupplierForm
class SupplierTest(TestCase):
def test_supplier(self):
supplier = Supplier(name="SomeSupplier")
supplier_form = SupplierForm(instance = supplier)
self.assertEquals(supplier_form.is_valid(), True)
When I start test through manage.py, is_valid() always returns False, but I expect True.
What the reasons for fail is_valid() in this case ?
I use Django 1.3.
All forms constructed without data are "invalid" because they have nothing to validate :-) You need to supply valid input to form's constuctor:
supplier_form = SupplierForm({'name': 'NewSupplier'}, instance=supplier)