create users before running tests DRF - django

i want to run django tests,
but i want to create some users before i run the test and the users' username will be attribute of the class and can be shared in all tests somthing like this:
class DoSomeTests(TestCase):
def setup_createusers(self):
self.usr1 = create_user1()
self.usr2 = create_user1()
self.usr3 = create_user1()
def test_number_one(self):
use self.user1/2/3
def test_number_two(self):
use self.user1/2/3
def test_number_three(self):
use self.user1/2/3
how can i do it becuase every time i tried the test dont recognize the self's attributes
ive tried use setupclass and setUp but nothing happend
cretae users before running tests

Generally (and personally) since setUpTestData was introduced I use this one but you can use setUp also based on your approach and what you need.
In order to use setUpTestData you need to put a class decorator and approach it with cls instead of self since you want to set up data for the whole TestCase, something like:
class TestViews(TestCase):
#classmethod
def setUpTestData(cls):
cls.user1 = User.objects.create_user(........)
cls.user2 = User.objects.create_user(........)
cls.user3 = User.objects.create_user(........)
Then in your tests, in order to access (and log in) each user you can use this:
def test_number_one(self):
test_user = self.user1
self.client.force_login(test_user)

Related

Django save a model instance when testing but can't find it in real database

I'am new to Django, when I was doing testing, I created a new test model record in setup() function for the following test, it succeeded, and I can access the record in the following code, but when I go to check the real database, the new record is not exist.
the setup code like this:
class UserTest(TestCase):
def setUp(self):
test_user = User.object.create(name='test')
when I set the breakpoint in the setUp() function, and after the 'test_user' is created, I can use 'User.object.get()' to obtain the created user, but when I go to real database and check the User table, I can't find this record. By the way, I use postgreSQL.
The test runner is using this:
class NoDBTestRunner(DiscoverRunner):
def setup_databases(self, **kwargs):
pass
def teardown_databases(self, old_config, **kwargs):
pass
I want to know where the created data record is stored?
Any suggestion will be very helpful
Django Unit Tests create a separate database for testing. The main database is not used to avoid errors that may result from testing.

How to pass Django mock instance to class method?

The Mock testing library is the one Django topic I just can't seem to wrap my head around. For example, in the following code, why don't the mock User instances that I create in my unit test appear in the User object that I query in the 'get_user_ids' method? If I halt the test in the 'get_user_ids' method via the debug call and do "User.objects.all()", there's nothing in the User queryset and the test fails. Am I not creating three mock User instances that will be queried the the UserProxy's static method?
I'm using Django 1.6 and Postgres 9.3 and running the test with the command "python manage.py test -s apps.profile.tests.model_tests:TestUserProxy".
Thanks!
# apps/profile/models.py
from django.contrib.auth.models import User
class UserProxy(User):
class Meta:
proxy = True
#staticmethod
def get_user_ids(usernames):
debug()
user_ids = []
for name in usernames:
try:
u = User.objects.get(username__exact=name)
user_ids.append(u.id)
except ObjectDoesNotExist:
logger.error("We were unable to find '%s' in a list of usernames." % name)
return user_ids
# apps/profile/tests/model_tests.py
from django.test import TestCase
from django.contrib.auth.models import User
from mock import Mock
from apps.profile.models import UserProxy
class TestUserProxy(TestCase):
def test_get_user_ids(self):
u1 = Mock(spec=User)
u1.id = 1
u1.username = 'user1'
u2 = Mock(spec=User)
u2.id = 2
u2.username = 'user2'
u3 = Mock(spec=User)
u3.id = 3
u3.username = 'user3'
usernames = [u1.username, u2.username, u3.username]
expected = [u1.id, u2.id, u3.id]
actual = UserProxy.get_user_ids(usernames)
self.assertEqual(expected, actual)
Mocking is awesome for testing, and can lead to very clean tests, however it suffers a little from (a) being a bit fiddly to get ones head around when starting out, and (b) does require some effort often to set up mock objects and have then injected/used in the correct places.
The mock objects you are creating for the users are objects that look like a Django User model object, but they are not actual model objects, and therefore do not get put into the database.
To get your test working, you have two options, depending on what kind of test you want to write.
Unit Test - Mock the data returned from the database
The first option is to get this working as a unit test, i.e. testing the get_user_ids method in isolation from the database layer. To do this, you would need to mock the call to User.objects.get(username__exact=name) so that it returns the three mock objects you created in your test. This would be the more correct approach (as it is better to test units of code in isolation), however it would involve more work to set up than the alternative below.
One way to achieve this would be to firstly separate out the user lookup into it's own function in apps/profile/models.py:
def get_users_by_name(name):
return User.objects.get(username__exact=name)
This would need to be called in your function, by replacing the call to Users.objects.get(username__exact=name) with get_users_by_name(name). You can then modify your test to patch the function like so:
from django.test import TestCase
from django.contrib.auth.models import User
from mock import Mock, patch
from apps.profile.models import UserProxy
class TestUserProxy(TestCase):
#patch('apps.profile.models.get_user_by_name')
def test_get_user_ids(self, mock_get_user_by_name):
u1 = Mock(spec=User)
u1.id = 1
u1.username = 'user1'
u2 = Mock(spec=User)
u2.id = 2
u2.username = 'user2'
u3 = Mock(spec=User)
u3.id = 3
u3.username = 'user3'
# Here is where we wire up the mocking - we take the patched method to return
# users and tell it that, when it is called, it must return the three mock
# users you just created.
mock_get_user_by_name.return_value = [u1, u2, u3]
usernames = [u1.username, u2.username, u3.username]
expected = [u1.id, u2.id, u3.id]
actual = UserProxy.get_user_ids(usernames)
self.assertEqual(expected, actual)
Integration Test - Create real user objects
The second approach is to modify this to be an integration test, i.e. one that tests both this unit of code and also the interaction with the database. This is a little less clean, in that you are now exposing your tests on the method to the chance of failing because of problems in a different unit of code (i.e. the Django code that interacts with the database). However, this does make the setup of the test a lot simpler, and pragmatically may be the right approach for you.
To do this, simply remove the mocks you have created and create actual users in the database as part of your test.

Getting random object of a model with django-rest-framework

In my Django project I need to provide a view to get random object from a model using django-rest-framework. I had this ListAPIView:
class RandomObject(generics.ListAPIView):
queryset = MyModel.objects.all().order_by('?')[:1]
serializer_class = MyModelSerializer
...
It worked fine but order_by('?') takes a lot of time when launched on big database. So I decided to use usual Python random.
import random
def pick_random_object():
return random.randrange(1, MyModel.objects.all().count() + 1)
class RandomObject(generics.ListAPIView):
queryset = MyModel.objects.all().filter(id = pick_random_object())
...
I found out a strange thing when tried to use this. I launched Django development server and sent some GET requests, but I got absolutely the same object for all of the requests. When dev server restarted and another set of requests sent I'm getting another object, but still absolutely the same one for all of requests - even if random.seed() was used first of all. Meanwhile, when I tried to get a random object not via REST but via python manage.py shell I got random objects for every time I called pick_random_object().
So everything looks good when using shell and the behavior is strange when using REST, and I have no clue of what's wrong.
Everything was executed on Django development server (python manage.py runserver).
As #CarltonGibson noticed, queryset is an attribute of RandomObject class. Hence it cached and cannot be changed any later. So if you want to make some changeable queryset (like getting random objects at every request) in some APIView, you must override a get_queryset() method. So instead of
class RandomObject(generics.ListAPIView):
queryset = MyModel.objects.all().filter(id = pick_random_object())
...
you should write something like this:
class RandomObject(generics.ListAPIView):
#queryset = MyModel.objects.all().filter(id = pick_random_object())
def get_queryset(self):
return MyModel.objects.all().filter(id = pick_random_object())
Here pick_random_object() is a method to get random id from the model.
Since it's an attribute of the class, your queryset is getting evaluated and cached when the class is loaded, i.e. when you start the dev server.
I'd try pulling a list of primary keys, using values_list() — the flat=True example does exactly what you need. Ideally cache that. Pick a primary key at random and then use that to get() the actual object when you need it.
So, how would that go?
I'd define a method on the view. If you forget the caching, the implementation might go like this:
# Lets use this...
from random import choice
def random_MyModel(self):
"""Method of RandomObject to pick random MyModel"""
pks = MyModel.objects.values_list('pk', flat=True).order_by('id')
random_pk = choice(pks)
return MyModel.objects.get(pk=random_pk)
You might then want to cache the first look up here. The caching docs linked above explain how to do that. If you do cache the result look into the db.models signals to know when to invalidate — I guess you'd post_save, checking the created flag, and post_delete.
I hope that helps.

Using Django filters inside model function

The main purpose of a model is to contain business logic, so I want most of my code inside Django model in the form of methods. For example I want to write a method named get_tasks_by_user() inside task model. So that I can access it as
Tasks.get_tasks_by_user(user_id)
Following is my model code:
class Tasks(models.Model):
slug=models.URLField()
user=models.ForeignKey(User)
title=models.CharField(max_length=100)
objects=SearchManager()
def __unicode__(self):
return self.title
days_passed = property(getDaysPassed)
def get_tasks_by_user(self,userid):
return self.filters(user_id=userid)
But this doesn't seems to work, I have used it in view as:
tasks = Tasks.objects.get_tasks_by_user(user_id)
But it gives following error:
'SearchManager' object has no attribute 'get_tasks_by_user'
If I remove objects=SearchManager, then just name of manager in error will change so I think that is not issue. Seems like I am doing some very basic level mistake, how can I do what I am trying to do? I know I can do same thing via :Tasks.objects.filters(user_id=userid) but I want to keep all such logic in model. What is the correct way to do so?
An easy way to do this is by using classmethod decorator to make it a class method. Inside class Tasks:
#classmethod
def get_tasks_by_user(cls, userid):
return cls.objects.filters(user_id=userid)
This way you can simply call:
tasks = Tasks.get_tasks_by_user(user_id)
Alternatively, you can use managers per Tom's answer.
To decided on which one to choose in your specific case, you can refer James Bennett's (the release manager of Django) blog post on when to use managers/classmethod.
Any methods on a model class will only be available to instances of that model, i.e. individual objects.
For your get_tasks_by_user function to be available as you want it (on the collection), it needs to be implemented on the model manager.
class TaskManager(models.Manager):
def get_tasks_by_user(self, user_id):
return super(TaskManager, self).get_query_set().filter(user=user_id)
class Task(models.Model):
# ...
objects = TaskManager()

Django custom managers - how do I return only objects created by the logged-in user?

I want to overwrite the custom objects model manager to only return objects a specific user created. Admin users should still return all objects using the objects model manager.
Now I have found an approach that could work. They propose to create your own middleware looking like this:
#### myproject/middleware/threadlocals.py
try:
from threading import local
except ImportError:
# Python 2.3 compatibility
from django.utils._threading_local import local
_thread_locals = local()
def get_current_user():
return getattr(_thread_locals, 'user', None)
class ThreadLocals(object):
"""Middleware that gets various objects from the
request object and saves them in thread local storage."""
def process_request(self, request):
_thread_locals.user = getattr(request, 'user', None)
#### end
And in the Custom manager you could call the get_current_user() method to return only objects a specific user created.
class UserContactManager(models.Manager):
def get_query_set(self):
return super(UserContactManager, self).get_query_set().filter(creator=get_current_user())
Is this a good approach to this use-case? Will this work? Or is this like "using a sledgehammer to crack a nut" ? ;-)
Just using:
Contact.objects.filter(created_by= user)
in each view doesn`t look very neat to me.
EDIT Do not use this middleware approach !!!
use the approach stated by Jack M. below
After a while of testing this approach behaved pretty strange and with this approach you mix up a global-state with a current request.
Use the approach presented below. It is really easy and no need to hack around with the middleware.
create a custom manager in your model with a function that expects the current user or any other user as an input.
#in your models.py
class HourRecordManager(models.Manager):
def for_user(self, user):
return self.get_query_set().filter(created_by=user)
class HourRecord(models.Model):
#Managers
objects = HourRecordManager()
#in vour view you can call the manager like this and get returned only the objects from the currently logged-in user.
hr_set = HourRecord.objects.for_user(request.user)
See also this discussion about the middelware approach.
One way to handle this would be to create a new method instead of redefining get_query_set. Something along the lines of:
class UserContactManager(models.Manager):
def for_user(self, user):
return super(UserContactManager, self).get_query_set().filter(creator=user)
class UserContact(models.Model):
[...]
objects = UserContactManager()
This allows your view to look like this:
contacts = Contact.objects.for_user(request.user)
This should help keep your view simple, and because you would be using Django's built in features, it isn't likely to break in the future.
It seems necessary to use the middleware to store the user information.
However, I'd rather not modify the default ModelManager objects, but hook it upto a different manager, that I will use in the code, say in your case user_objects instead of objects.
Since you will use this only within views that are #login_required you dont need all the complex error handling in the Middleware.
Just my 2¢.
Or even simpler and use foreign key to retrieve queryset.
If you have model like that
class HourRecord(models.Model):
created_by = ForeignKey(get_user_model(), related_name='hour_records')
You can query HourRecords in a view by user with simply:
request.user.hour_records.all()