Import cycle with Model, ModelManager and ModelSerializer - django

I am using Django with Django Rest Framework for serializers.
I have the following situation.
In file models.py:
from django.db.models import Manager, Model, CharField
from .serializers import MyModelSerializer
class MyModelManager(Manager):
serializer_class = MyModelSerializer
class MyModel(Model):
name = CharField(max_length=64)
objects = MyModelManager()
In file serializers.py:
from rest_framework.serializers import ModelSerializer
from models import MyModel
class MyModelSerializer(ModelSerializer):
class Meta:
model = MyModel
fields = ('name',)
However, this leads to an import cycle, since both files try to import each other. I could prevent this by making a local import:
class MyModelManager(Manager):
#property
def serializer_class(self):
from ow_articlecode.import_cycle_serializers import MyModelSerializer
return MyModelSerializer
However, this feels like a hack. What would be a proper solution to break this import cycle?

A Manager [Django-doc], has no serializer_class field. In fact a manager does not know anything about serialization. A manager is used to filter, create, etc. objects.
Your models.py thus should look like:
# app/models.py
from django.db.models import Manager, Model, CharField
class MyModelManager(Manager):
# no serializer_class
pass
class MyModel(Model):
name = CharField(max_length=64)
The idea of Models is that this defines your business logic, not the serialization, form, view, template logic.

Related

Fetch the Django Serializer Indirectly

I am having a circular dependency problem. In order to avoid that I am using
apps.get_model('ModelName')
Is there a way to fetch the serializer class in the same way?
project
app
models
views
serializers
tasks
app_urls
settings
urls
etc etc...
models.py:
from .tasks import taskA
class Bag():
...
sender=Bag
def bag_signal():
taskA()
views:
from .models import Bag
from .serializers import BagSerializer
class BagViewset(ModelViewSet):
model = Bag
serializer = BagSerializer
serializer:
from .models import Bag
class BagSerializer(ModelSerializer):
def meta:
model = Bag
def validate():
**validation stuff
tasks:
from django.apps import apps
def taskA():
model_name = apps.get('app', 'model_name')
model.objects.create(**data)
# wanna call serializer's validate and save it through serializer.save()

django ManyToManyField serializer

i'm new to django. The version i'm using is 1.11.2
I have a a schema like this.
There are many "designs" and each design can have any number of "patterns".
my design model is like below
from django.db import models
from products.models import Product
class Design(models.Model):
name = models.CharField(max_length=200)
product_id = models.ForeignKey(Product, on_delete=models.CASCADE)
price = models.CharField(max_length=200)
def __str__(self):
return self.name
My design serializer is like below
from rest_framework import serializers
from .models import Design
from rest_framework import serializers
from patterns.models import Pattern
class DesignsSerializer(serializers.ModelSerializer):
patterns = DesignPatternSerializer(read_only=True, many=True)
class Meta:
depth = 1
model = Design
fields = ('id','name','patterns')
read_only_fields = ('id','name','patterns')
The view for designs is as below
from django.shortcuts import render
from .models import Design
from .serializers import DesignsSerializer
from rest_framework import generics, filters
# Create your views here.
class ListDesignsByProducId(generics.ListCreateAPIView):
serializer_class = DesignsSerializer
def get_queryset(self):
return Design.objects.filter(product_id__exact = self.kwargs.get('product_id'))
My pattern model is like below.
from django.db import models
from datetime import date
from designs.models import Design
class Pattern(models.Model):
design_id = models.ManyToManyField(Design)
name = models.CharField(max_length=200)
def __str__(self):
return self.name
My pattern serializer is as below
from rest_framework import serializers
from .models import Pattern
class PatternSerializer(serializers.ModelSerializer):
class Meta:
depth = 1
model = Pattern
fields = ('id','design_id','name')
read_only_fields =('id','design_id','name')
Right now the api would return the details of the designs and it's associated products.
I would also like to get an array of patterns associated with the design.
In your DesignsSerializer you referred to the patterns by the name patterns without defining it in your models.
From the Django REST Framework documentation:
You'll normally want to ensure that you've set an appropriate
related_name argument on the relationship, that you can use as the
field name.
In your Pattern model:
class Pattern(models.Model):
design_id = models.ManyToManyField(Design, related_name='patterns')
...

How can we append extra fields dynamically in serializer.py using request object

http://127.0.0.1:8000/?words=anger
and I want to add 'anger' to the field serializer dynamically.
from .models import Synonym
from rest_framework import serializers
class SynonymSerializer(serializers.ModelSerializer):
class Meta:
model = Synonym
fields = ('word',)

Removing fields from django-rest-framework view

is there any way to show only a list of fields or excluding some of them when using django-rest-framework?
Here's my app/views.py:
from rest_framework.generics import ListAPIView
from .models import PhpbbUsers
class UsersReadView(ListAPIView):
model = PhpbbUsers
Obiously there are some user information that I don't want to show to everyone. How could I do?
Solution code
from rest_framework import generics, serializers
from .models import PhpbbUsers
class UsersSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = PhpbbUsers
fields = ('user_id', 'username', 'user_avatar')
class UsersReadView(generics.ListAPIView):
model = PhpbbUsers
serializer_class = UsersSerializer
Set the serializer_class attribute on the view.
See the quickstart for a good example: http://django-rest-framework.org/tutorial/quickstart.html

Django - Dynamically importing a models form

I want to create a view that is able to show a ModelForm for various different models. It does this by obtaining the content type of the model and then dynamically instantiating the model form associated with that particular model. Here is my model:
from django.db import models
class SomeModel(models.Model):
name = models.CharField(max_length=150)
def __unicode__(self):
return self.name
And inside the same app there is a forms.py with the following form:
from django.forms import ModelForm
from someapp.models import SomeModel
class SomeModelForm(ModelForm):
class Meta:
model = SomeModel
fields = ('name',)
So what I want to do inside of my view file is return the correct form for each model dynamically. I tried the following:
from django.db import models
from someapp.forms import SomeModelForm
class SomeModel(models.Model):
name = models.CharField(max_length=150)
form = SomeModelForm
def __unicode__(self):
return self.name
But it doesn't work because of the obvious circular import. Does anyone have any idea how I might go about achieving this? I tried toying with modelform_factory, but it seems to ignore any of my custom model forms in forms.py.
EDIT: I should of mentioned that I won't have an instance of the model, just the model class itself, so having a method that inside of the model doesn't work (it does, however, work if you are calling it on an instance of the model)
You could get around the circular import by importing your model form inside a method.
class SomeModel(models.Model):
name = models.CharField(max_length=150)
#staticmethod
def get_form_class():
from someapp.forms import SomeModelForm
return SomeModelForm
# in your view:
SomeModel.get_form_class()
Putting the import within a method on the model should be enough to get you around the circular import, so instead of what you have, you'd use:
class SomeModel(models.Model):
...
def get_form(self):
from someapp.forms import SomeModelForm
return SomeModelForm
You can even make it a property if you want with:
form = property(get_form)
There is a built-in func get_model for lazy importing models.
from django.db.models import get_model
SomeModel = get_model('your_app_name', 'SomeModel')
Using __import__ and getattr.
# models.py
class SomeModel(models.Model):
...
#classmethod
def get_form(cls):
try:
app = __import__(cls._meta.app_label)
forms = getattr(app, "forms")
return getattr(forms, "%sForm" % cls.__name__)
except:
return None
# forms.py
class SomeModelForm(forms.Form):
...
in a view you can get the form associate to a models like this:
# views.p
from models import SomeModel
...
def myview(request):
form = SomeModel.getform()