Use managers in Factory-Boy for models - python

Use Factory-boy for retrieve operation without use the DB for testing case.
I have this simple model:
class Student(models.Model):
name = models.CharField(max_length=20) `
To get all: Student.objects.all()
With Factory-boy:
class StudentFactory(factory.django.DjangoModelFactory):
class Meta:
model = Student
Is there a way to make StudentFactory.objects.all() ?
When I call the method all() in my factory, I would like to return a list of QuerySet created by me. Example: [QuerySet_1, QuerySet_2] # Not Database.
With that, I can change my data from DB to memory in my test.

You may be looking for the methods create_batch and build_batch, depending on whether you want to save the newly generated instances in the test database or not.
Here's an example which I copy-pasted and adapted from factory-boy documentation:
# --- models.py
class StudentFactory(factory.django.DjangoModelFactory):
class Meta:
model = Student
# --- test_student_factory.py
from . import factories
def make_objects():
factories.StudentFactory.create_batch(size=50)

Related

Access related set from a Custom QuerySet in Django?

I want to annotate additional field to my model via custom queryset and access it with a function, here is a simplified code:
class CustomQuerySet(models.QuerySet):
def my_func(self):
return self.annotate(b_count=self.b_set.count()) # 'CustomQuerySet' object has no attribute 'b_set'
class A(models.Model):
objects = CustomQuerySet.as_manager()
class B(models.Model):
a = models.ForeignKey(A)
I want to access it like this models.A.objects.my_func().all(), so an extra field would be added to my model when I want to get it.
But I can't access b_set from a CustomQuerySet.
Previously I was using a #property in model A, but it makes an additional DB request every time.
How could I access a set of related model from a Custom QuerySet?
Probably, you should take a look at the Manager example that does exactly what you want: https://docs.djangoproject.com/en/3.2/topics/db/managers/#adding-extra-manager-methods
from django.db import models
from django.db.models.functions import Coalesce
class PollManager(models.Manager):
def with_counts(self):
return self.annotate(
num_responses=Coalesce(models.Count("response"), 0)
)
class OpinionPoll(models.Model):
question = models.CharField(max_length=200)
objects = PollManager()
class Response(models.Model):
poll = models.ForeignKey(OpinionPoll, on_delete=models.CASCADE)
# ...
In your example, I think you can't access b_set because this attribute belongs to a model instance, not to the queryset itself.

Django model instance with nested field filter

I have these two models:
class Task(models.Model):
pass
class Result(models.Model)
task = models.ForeignKey('tasks.Task', related_name='results')
enabled = models.BooleanField('enabled', default=False)
And I want to get task with filtered results for my temporary calculations:
task = Task.objects.first()
results = task.results.filter(enabled=True)
task.results.set(results)
This is the working code, but task results will be rewritten after the first usage. How to get the new task with filtered results without task.results rewriting? I need to keep the changed task instance in memory only.
My final point is to pass the task to the serializer. But it seems to me the serializer must serialize and not to filter something. Because the context of filtering may be different in other submodules.
class ResultSerializer(DynamicFieldsMixin, ModelSerializer):
class Meta:
model = Result
class TaskResultsSerializer(ModelSerializer):
results = ResultSerializer(many=True, read_only=True)
class Meta:
model = Task
Set is used for replacing related objects. You getting results and then reset them. I'm not sure why? Maybe you are trying to do the update?
https://docs.djangoproject.com/en/2.2/ref/models/querysets/#django.db.models.query.QuerySet.update
It looks from your choice of serializer class like you're using the Django REST framework for serialization. If that's correct, I would handle this by declaring a callable on the Task model that returns the results you want to include, and then explicitly specifying a serializer field for that callable. EG:
class Task(models.Model):
def enabled_results(self):
return self.results.filter(enabled=True)
class TaskResultsSerializer(ModelSerializer):
results = ResultSerializer(source='enabled_results', many=True, read_only=True)
class Meta:
model = Task
This is untested, but it looks like it should work.

In Django, how can I easily inherit a field and create a new class with this field preconfigured parameters?

I am currently using UUID in my PostgreSQL database, therefore I am also using PrimaryKeyRelatedField() with some parameters in order to avoid problems when encoding to JSON the UUID field.
My serializer field looks like:
id = serializers.PrimaryKeyRelatedField(read_only=True,
allow_null=False,
pk_field=serializers.UUIDField(format='hex_verbose'))
And in every serializer that uses UUID I am having to use that.
My question is, how can I create a new class based on PrimaryKeyRelatedField so that I don't have to write all those parameters (read_only, allow_null...) ?
I am looking for something like:
id = BaseUUIDField()
Thanks
You can make an abstract class using the id which is a uuid field. Then inheret that model in your derived models.
import uuid
from django.db import models
//Abstract Model
class AbstractModel(models.Model):
id = models.UUIDField(primary_key=True,default=uuid.uuid4, editable=False)
class Meta:
Abstract =True
//Derived Model
class YourDerivedModel(Abstract.Model):
//fields here
Hope this helps your query

Expose multiple similar database fields as enumerable collection

I have a Django (1.8) Model for an underlying database table that has multiple columns that are logically a fixed-size array. For example:
from django.db import models
class Widget(models.Model):
# ...
description_1 = models.CharField(max_length=255)
description_2 = models.CharField(max_length=255)
description_3 = models.CharField(max_length=255)
# ...
I would like to be able to access these columns as if they were a collection on the model instance, e.g.:
instance = Widget.objects.get(...)
for description in instance.descriptions:
# do something with each description
My primary motivation is that I am exposing this model via Django Rest Framework (DRF), and would like the API clients to be able to easily enumerate the descriptions associated with the model. As it stands, the clients have to reference each logical 'index' manually, which makes the code repetitive.
My DRF serializer code is currently like this:
class WidgetSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Widget
There are a fixed number of descriptions for each Widget, and their ordering is important.
Is there a clean way to expose these fields as a collection on the Model object?
It really was as easy as adding a method to the Model class that returns the fields as a sequence, and then (for API clients), manually specifying that new method as a field to serialize.
So the Model definition becomes:
from django.db import models
class Widget(models.Model):
description_1 = models.CharField(max_length=255)
description_2 = models.CharField(max_length=255)
description_3 = models.CharField(max_length=255)
def descriptions(self):
return self.description_1, self.description_2, self.description_3
And the DRF serializer is updated like:
class WidgetSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Widget
fields = ('url', 'descriptions',)
This causes the API to return a JSON array for descriptions and omit all of the individual description_x fields.

Can Django-Rest-Framework create an API that returns a single attribute of an Object Model instance?

In my Django app, I have the following Models:
class MyModelA(models.Model):
myAttributeA = models.CharField(max_length=255)
class MyModelB(models.Model):
myParent = models.OneToOneField(myModelA)
myAttributeB = models.CharField(max_length=255)
My settings.py has the following Rest Permission settings:
'DEFAULT_PERMISSION_CLASSES': ('rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly',),
I also have the following Serializers:
class MyModelASerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = MyModelA
fields = ('myAttributeA',)
class MyModelBSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = MyModelB
fields = ('myParent', 'myAttributeB',)
Now I want to write a simple Django-Rest-Framework API that will allow any user (weather authenticated or not) to retrieve the value of myParent on any instance of MyModelB assuming they have the Primary Key of the MyModelB instance. This should be rather simple. I'm not trying to update, create, or delete anything. I just want to retrieve the value of one attribute of the instance. But I also want my urls.py to match this endpoint to the API:
url(r'^api/AttrMyModelA/(?P<myModelAID>\d+)/?$', SOMETHING HERE. NOT SURE WHAT)
However, I cannot figure out which pattern to use from the tutorial to make this work. Should I use function based or class based views? Should I use Generic API views? Do I need a decorator or no? Mixins? Can someone please show me what my view should look like and what the urls.py endpoint should look like?
Thanks
You require a RetrieveAPIView-derived class to tie things together:
class MyModelAView(RetrieveAPIView):
model = MyModelA
serializer_class = MyModelASerializer
The route mentioned by you would then look like this:
url(r'^api/AttrMyModelA/(?P<pk>\d+)/?$', MyModelAView.as_view())
Note that pk is the default look-up field used by APIView-derived classes when performing single object queries.
You have defined a default permission class (in settings.py), so unless you want to override that you don't need to specify a permission_classes value in your view class.

Categories

Resources