Model constraints are not working with Faker ( Django ) - 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.

Related

Save django CreateView in Python Shell

I'm trying to write a test for my CreateView view in django. As part fo the test, I want to create a new object through a CreateView class, though I'm unsure how to save the object through tests.py.
models.py
class MyModel(models.Model):
name = models.CharField(
max_length = 50,
)
views.py
class MyCreateView(CreateView):
model = MyModel
tests.py
from myapp.views import MyCreateView
m = MyCreateView()
m.name = 'John Doe'
# save object here
Neither m.save() nor m.submit() will work. Any suggestions?
Please refer to Django docs: https://docs.djangoproject.com/en/4.0/topics/testing/
It is well documented and shows how to test views and models.

Django raise ValidationException on id field when testing abstract model

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

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)

Django app to retrieve data from other apps models?

I have an app name sync which has a form created from a model that saves itself. I want to create another app called activity that retrieves the data from the sync models and other future apps. How can I do that in the activity views app?
This is my sync models.py
from django.db import models
from django.contrib.auth.models import User
from django.forms import ModelForm
FS_CHOICES = (
('/path1/', 'P1'),
('/path2/', 'P2'),
('/path3/', 'P3'),
)
OPTIONS = (
('-n', 'TRY'),
)
class SyncJob(models.Model):
date = models.DateTimeField()
user = models.ForeignKey(User, unique=False)
source = models.CharField(max_length=3, choices=FS_CHOICES)
destination = models.CharField(max_length=3, choices=FS_CHOICES)
options = models.CharField(max_length=10, choices=OPTIONS)
class SyncJobForm(ModelForm):
class Meta:
model = SyncJob
fields = ['source', 'destination', 'options']
Ok, in activity views.py I have this:
from toolbox.sync.models import SyncJob
from django.shortcuts import render_to_response
def Activity()
sync_job = SyncJob.objects.get(id=03)
return render_to_response('base.html', {'sync_job': sync_job})
UPDATE: When I try to view the page it displays the error:
'function' object is not iterable
Just import it like any other python class.
So in your activity app you'd do something like this:
from sync.models import SyncJob
sync_job = SyncJob.objects.get(id=99)