FactoryBoy seem to always create the instances in the default database. But I have the following problem.
cpses = CanonPerson.objects.filter(persons__vpd=6,
persons__country="United States").using("global")
The code is pointing to the global database. I haven't found a way to specify the database within the factory:
class CanonPersonFactory(django_factory.DjangoModelFactory):
class Meta:
model = CanonPerson
django_get_or_create = ('name_first', 'p_id')
p_id = 1
name_first = factory.Sequence(lambda n: "name_first #%s" % n)
#factory.post_generation
def persons(self, create, extracted, **kwargs):
if not create:
# Simple build, do nothing.
return
if extracted:
# A list of groups were passed in, use them
for person in extracted:
self.persons.add(person)
Looks like Factory Boy does not provide this feature from box, but you can easily add it manually:
class CanonPersonFactory(django_factory.DjangoModelFactory):
class Meta:
model = CanonPerson
...
#classmethod
def _get_manager(cls, model_class):
manager = super(CanonPersonFactory, cls)._get_manager(model_class)
return manager.using('global')
...
This is now directly supported by adding the database attribute on Meta:
class CanonPersonFactory(django_factory.DjangoModelFactory):
class Meta:
model = CanonPerson
database = 'global'
...
Related
I want to create a base class that will be used by other classes. Only one field name will change depending on the child class.
class Person(serializers.Serializer):
name = serializers.CharField()
other_fields = ...
def validate(self, attrs):
# something to validate the name and other fields together
...
class John(Person):
john_name = Person.name # ?
All I want is to be able to receive a payload like this: {"john_name": "john"}, without the need to redo the Person validations for every child class of Person that the code needs.
How do I do this?
is this what you are looking for?
class John(Person):
john_name = serializer.charField(write_only=True)
def create(self,validated_data):
person_name = validated_data.pop('john_name')
validated_data["person_name"] = person_name
return Super().create(validated_data)
Here is my problem: I try to create layer under
models.Model
My Model -
class MainModel(models.Model):
#staticmethod
def getIf(condition):
results = __class__.objects.filter(condition)
if results.count() > 0:
return results.first()
else:
return None
And that's a model
class User(MainModel):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=256)
date_create = models.DateTimeField(auto_now_add=True)
date_last_login = models.DateTimeField(null=True)
But my project is crushed with error -
django.core.exceptions.FieldError: Local field 'id' in class 'User'
clashes with field of the same name from base class 'MainModel'.
What am I doing wrong?
UPD: if you want to do like this, you need to use subclass Meta in your layer
class MainModel(models.Model):
#staticmethod
def getIf(condition:dict):
results = __class__.objects.filter(condition)
if results.count() > 0:
return results.first()
else:
return None
class Meta:
abstract = True
Thanx, but I'm not trying to override fields, In my layer no one field is not defined. I found my answer, I just have to read documentation.
if you want to do like this, you need to use subclass Meta in your layer
class MainModel(models.Model):
#staticmethod
def getIf(condition:dict):
results = __class__.objects.filter(condition)
if results.count() > 0:
return results.first()
else:
return None
class Meta:
abstract = True
Django adds a field id to all Models, you have to remove it.
Ok I understand your question better now, your answer is there:
In Django - Model Inheritance - Does it allow you to override a parent model's attribute?
Django already adds a field id to your parent model.
I am creating a reference lexicon in django. The lexicon is a translator for certain fields from one language to another.
The lexicon goes like this: 'id','lng1','lng2','lng3'
I have a model that uses the lexicon in one of the fields.
class lexicon(models.Model):
lng1 = model.Charfield(max_length=255)
lng2 = model.Charfield(max_length=255)
lng3 = model.Charfield(max_length=255)
lexicon_choices = (
(lng1=lng1),
(lng2=lng2),
(lng3=lng3)
)
class model(models:Model):
model_name = model.Charfield(max_length=255, unique)
field1 = model.Charfield(max_length=3,CHOICES=lexicon_choices)
This works ok, but I want to know, is there a way to glean out the column names from class lexicon and port them as the choices for class model? I am using Django Rest Framework for the first time, and I want to make sure the right lng is there.
Thanks
You can use a ForeignKey on the lexicon class to your main model. This will ensure a One to Many relationship. And you can store the values in database.
yes, possible. but in admin.py
class CustomForm(forms.ModelForm):
class Meta:
model = YourModel
def __init__(self, *args, **kwargs):
super(CustomForm, self).__init__(*args, **kwargs)
choices = [(x.id, x.name) for x in Lexicon.objects.all()]
self.fields['field1'].choices = choices
class YourModelAdmin(admin.ModelAdmin):
form = CustomForm
and your original model looks like:
class YourModel(models:Model):
model_name = model.Charfield(max_length=255, unique)
field1 = models.CharField(max_length=10, choices=(('--', '--'),))
IMPORTANT: do not name your class names with lower case. ;)
I'm trying to access fields on the through table of my ManyToMany link to serialize into a JSON via Django Rest Frameworks.
My models involved in the many to many are:
class Mage(models.Model):
arcana = models.ManyToManyField('ArcanumAbility', through='CharacterArcanumLink', related_name='mage_by_arcana')
class ArcanumAbility(models.Model):
class Arcana(AutoNumber):
FATE = ()
MIND = ()
SPIRIT = ()
DEATH = ()
FORCES = ()
TIME = ()
SPACE = ()
LIFE = ()
MATTER = ()
PRIME = ()
arcanum = EnumField(Arcana)
class Meta:
verbose_name_plural = "Arcana Abilities"
def __str__(self):
return self.arcanum.label
class CharacterArcanumLink(Trait):
PRIORITY_CHOICES = (
(0, 'Unassigned'), (1, 'Ruling'), (2, 'Common'), (3, 'Inferior')
)
priority = models.PositiveSmallIntegerField(
choices=PRIORITY_CHOICES, default=0)
mage = models.ForeignKey('Mage')
arcana = models.ForeignKey('ArcanumAbility')
class Meta:
unique_together = ('mage', 'arcana')
def __str__(self):
return self.arcana.arcanum.label
Where the Trait mixin provides a current_value
To serialize the above relation into my JSON, I have tried these two patters on my serializer:
class CharacterArcanumLinkSerializer(serializers.ModelSerializer):
class Meta:
model = CharacterArcanumLink
fields = ('current_value', 'arcana')
class MageSerializer(serializers.ModelSerializer):
arcana = CharacterArcanumLinkSerializer()
....
class Meta:
model = Mage
fields = (...., 'arcana', ....)
depth = 1
But that gives me this error:
AttributeError at /mages
'ManyRelatedManager' object has no attribute 'arcana'
Which is from (ultimately):
C:\Python34\lib\site-packages\rest_framework\fields.py in get_attribute
if instance is None:
# Break out early if we get `None` at any point in a nested lookup.
return None
try:
if isinstance(instance, collections.Mapping):
instance = instance[attr]
else:
instance = getattr(instance, attr) ...
except ObjectDoesNotExist:
return None
if is_simple_callable(instance):
instance = instance()
return instance
▼ Local vars
Variable: Value
instance: <django.db.models.fields.related.create_many_related_manager.<locals>.ManyRelatedManager object at 0x0000000004E4D4A8>
attr: 'arcana'
attrs: ['arcana']
(Question: What trick to I need to go from my ManyRelatedManager to it's fields?)
And I've also tried not specifying a special serializer, and just having 'arcana' in my fields, and pull it from my model. That leads to this error:
TypeError at /mages
<Arcana.FATE: 1> is not JSON serializable
Where the 1 is from the PK on the ArcanumAbility not the value on the through table. The issue here is that the Mage class has a M2M field that points to the 'ArcanumAbility' model, so all that DRF tries to do is serialize the Enum on it.
So what method should I use if I want a JSON dictionary of all the relationships from Mage to ArcanumAbility with data from the through table?
Responding to Mark R., I'd like it looks like so:
....
"arcanum": {
"Fate": 2,
"Spirit": 0,
"Mind": 3,
....
}
Hopefully that's a clear enough sample.
As discussed, if you add a related_name="linked_arcana" to the mage field in the CharacterArcanumLink class, you should be able to do something like this:
class MageSerializer(serializers.ModelSerializer):
arcana = serializers.SerializerMethodField()
def get_arcana(self, obj):
if obj:
return {str(x): x.current_value for x in obj.linked_arcana.all()}
I have gotten this working like so:
arcana = serializers.SerializerMethodField()
def get_arcana(self, obj):
if obj:
return {str(link): link.current_value
for link in CharacterArcanumLink.objects.filter(mage=obj)}
Heavily inspired by this answer.
I have an "abstract" model class MyField:
class MyField(models.Model):
name = models.CharField(db_index = True, max_length=100)
user = models.ForeignKey("AppUser", null=False)
I have a few other subclasses of MyField each defining a value of a specific type.
for example:
class MyBooleanField(MyField):
value = models.BooleanField(db_index = True, default=False)
In MyField I have a method get_value() that returns the value based on the specific subclass.
In django rest I want to fetch all the fields of a user
class AppUserSerializer(serializers.ModelSerializer):
appuserfield_set = MyFieldSerializer(many=True)
class Meta:
model = AppUser
fields = ('appuser_id', 'appuserfield_set')
On the client side I want the user to be able to add new fields and set values to them and then on the server I want to be able to create the correct field based on the value.
What is the correct way to achieve this behavior?
After some digging, here is what I ended up doing. Aside from the code below I had to implement get_or_create and create the relevant subclass of MyField based on the passed value.
class ValueField(serializers.WritableField):
#called when serializing a field to a string. (for example when calling seralizer.data)
def to_native(self, obj):
return obj;
"""
Called when deserializing a field from a string
(for example when calling is_valid which calles restore_object)
"""
def from_native(self, data):
return data
class MyFieldSerializer(serializers.ModelSerializer):
value = ValueField(source='get_value', required=False)
def restore_object(self, attrs, instance=None):
"""
Called by is_valid (before calling save)
Create or update a new instance, given a dictionary
of deserialized field values.
Note that if we don't define this method, then deserializing
data will simply return a dictionary of items.
"""
if instance:
# Update existing instance
instance.user = attrs.get('user', instance.user)
instance.name = attrs.get('name', instance.name)
else:
# Create new instance
instance = MyField.get_or_create(end_user=attrs['user'],
name=attrs['name'],
value=attrs['get_value'])[0]
instance.value = attrs['get_value']
return instance
def save_object(self, obj, **kwargs):
#called when saving the instance to the DB
instance = MyField.get_or_create(end_user=obj.user,
name=obj.name,
value=obj.value)[0]
class Meta:
model = MyField
fields = ('id', 'user', 'name', 'value')