Unable to create instance of Django model - python

I'm trying to create an instance of this Report model:
class Report(models.Model):
"""
A model for storing credit reports pulled from Equifax.
"""
user = models.ForeignKey(to=CustomUserModel, on_delete=models.CASCADE,
help_text='User report belongs to.')
timestamp = models.DateTimeField(default=timezone.now)
report = JSONField()
However, whenever I try I get this error:
Exception Type: TypeError at /internal/report
Exception Value: 'report' is an invalid keyword argument for this function
This happens whether I instantiate the instance using the Report().save() method, or the Report.object.create() method as follows:
report_obj = Report.objects.create(
user=user,
report=report
)
Does anyone have any clue what's going on? There is very clearly a "report" attribute for that class, so why the error?
Thanks!

Based on the the error and the comment:
(...) Looks like I imported the form field from DRF instead of the model field of the same name from Django (...)
You did not import a JSONField that is a model field, but something else (for example a form field, or here a DRF field). As a result, Django does not consider report to be a field of your Report module, it sees it as a "vanilla" Python attribute.
You thus should make sure that JSONField links to the model field class instead. Adding such field will probably result in another migration to add the field to the database table:
from django.contrib.postgres.fields import JSONField
class Report(models.Model):
"""
A model for storing credit reports pulled from Equifax.
"""
user = models.ForeignKey(to=CustomUserModel, on_delete=models.CASCADE,
help_text='User report belongs to.')
timestamp = models.DateTimeField(default=timezone.now)
report = JSONField()

Related

DRF AssertionError: Expected a `time`, but got a `datetime`

I have a model:
class Inspection(models.Model):
vendor = models.ForeignKey(Vendor, on_delete=models.CASCADE,
related_name='vendor_inspections')
inspection_date = models.DateField(default=date.today)
inspection_time = models.TimeField(default=timezone.now)
...
class Meta:
unique_together = (('vendor', 'inspection_date'),)
serializer:
class InspectionSerializer(serializers.ModelSerializer):
class Meta:
model = Inspection
fields = ['vendor', 'inspection_date', 'inspection_time']
and modelviewset:
class InspectionModelViewSet(viewsets.ModelViewSet):
serializer_class = InspectionSerializer
queryset = Inspection.objects.all()
I want to change data and time fields with PUT/PATCH requests or set their values manually on instance creating if it's needed, otherwise, current date & time should be saved.
When I send POST request with or without inspection_time in payload I get this error:
AssertionError: Expected a `time`, but got a `datetime`.
Refusing to coerce, as this may mean losing timezone information.
Use a custom read-only field and deal with timezone issues explicitly.
This error isn't raised if I remove inspection_time from fields in serializer Meta class. I've implemented serializer field validation method just to understand what's going on:
def validate_inspection_time(self, inspection_time):
raise Exception(inspection_time)
Aforementioned AssertionError is raised before validate_inspection_time.
Although the listed an inspection instance is saved in DB.
what the problem could be? Thank you.

Django Rest Framework: Get field name from model definition

Within the Django Rest framework documentation it is suggested to declare the "field" list explicitly to avoid providing the data of new columns just by adding them to the model which may contain sensitive information.
The field list is an array of strings, containing the field ids. To avoid declaring field ids, which actually do not exist in the model (e.g. typos or changed models) I tried to declare the list using object references - but always end up with "DeferredAttribute: object has no attribute ".
I have read something that meta information is not available in objects and that you could solve that by defininig your own Meta class using Object._meta.get_fields() and store it in the class, but I thought there might be a simpler/more elegant way (and I do now know, how, in detail ;-)).
Example:
class Samples(models.Model):
# Meta data, primarily used in AdminSite.
class Meta:
verbose_name = _('Samples')
verbose_name_plural = _('Samples')
samples_boolfield = models.BooleanField
samples_textfield = models.CharField(max_length=2000, blank=True)
views.py:
class SamplesView(viewsets.ModelViewSet):
serializer_class = SamplesSerializer
queryset = Samples.objects.all()
serializers.py:
Version 1, which does not show any errors in pyCharm or makemigrations, but calling the API reults in "TypeError at /api/samples/: argument of type 'DeferredAttribute' is not iterable":
class SamplesSerializer(serializers.ModelSerializer):
class Meta:
model = Samples
fields = (
'id',
Samples.samples_boolfield,
Samples.samples_textfield,
)
Version 2, which does not show any errors in pyCharm, but makemigrations fails with "DeferredAttribute: object has no attribute name":
class SamplesSerializer(serializers.ModelSerializer):
class Meta:
model = Samples
fields = (
'id',
Samples.samples_boolfield.__name__,
Samples.samples_textfield.__name__,
)
Version 3, which does not show any errors in pyCharm, but makemigrations fails with "DeferredAttribute: object has no attribute get_attname":
class SamplesSerializer(serializers.ModelSerializer):
class Meta:
model = Samples
fields = (
'id',
Samples.samples_boolfield.get_attname(),
Samples.samples_textfield.get_attname(),
)
Is there a way to declare the field list using object references (so that it fails e.g. in pyCharm/during compilation)?
Thank you for your feedback.
Regards,
HerrB92

How to add a custom field in django model form?

I'm trying to add a readonly field in a form.
The model Folder is registered in admin site. The FolderAdminForm defines the custom field statistics. There isn't statistcs field in the Folder model, I just want to put some readonly data on the form. This data is defined in the template.
But I get a error whenever the user doesn't have edit permission. If the user only have the view permission,this error is raised:
AttributeError: Unable to lookup 'statistics' on Folder or FolderAdmin
Here is my code:
class CustomWidget(forms.Textarea):
template_name = 'widget.html'
class FolderAdminForm(forms.ModelForm):
class Meta:
model = Folder
fields = ('field1', 'field2', 'field3',)
statistics = forms.Field(
widget=CustomWidget,
label='Estatísticas',
help_text='Estatísticas da pasta',
)
According to the last part of this answer, you could try to override the forms __init__() method and assign the fields initial attribute.
This could look like:
def __init__(self, *args, **kwargs):
# only change attributes if an instance is passed
instance = kwargs.get('instance')
if instance:
self.base_fields['statistics'].initial = 'something'
super().__init__(*args, **kwargs)
Does this work for you?
The error only occurred whenever I tried to open a folder instance without edit permission (i.e. with read only permission). Therefore, django consider the statistics field as a read only field and then search for a label for this field. Django look for this label in Model, ModelAdmin. Since none of them has the 'statistics' attribute, the error is raised.
So, this worked for me:
class FolderAdminForm(forms.ModelForm):
class Meta:
model = Folder
fields = ('field1', 'field2', 'field3',)
labels = {'statistics': 'Estatísticas'}
statistics = forms.Field(
widget=CustomWidget,
label='Estatísticas',
help_text='Estatísticas da pasta',
)
Therefore, whenever django looks for a label for statistics, it finds this label and the error is not raised. I don't know why it doesn't recognize the label passed as a Field parameter.

How to rate objects programmatically in Django Star Rating

I am using this library : django-star-rating to rate model objects by scores given by users.
You can view the documentation here
Problem that I face:
How can I rate an object programmatically in view function rather than in the template.
Also how can I integrate it with Django Rest framework? It uses a generic relation in the model schema. So far, I have used the field as Serializer Method field but the problem with that is that it is read only and the client cannot make patch request to update rating.
Code so far:
from star_ratings.models import Rating
class ExampleModel(models.Model):
rating = GenericRelation(Rating, related_query_name='example')
from rest_framework import serializers
class ExampleSerializer(serializers.HyperlinkedModelSerializer):
rating_total = serializers.SerializerMethodField()
rating_count = serializers.SerializerMethodField()
class Meta:
model = ExampleModel
fields = '__all__'
def get_rating_total(self, obj):
if obj.rating.exists():
return obj.rating.first().total
else:
return 0
def get_rating_count(self, obj):
if obj.rating.exists():
return obj.rating.first().count
else:
return 0
From drf docs :
SerializerMethodField
This is a read-only field. It gets its value by calling a method on the
serializer class it is attached to. It can be used to add any sort of data to the serialized representation of your object.
Hence the field is read only and I can't rate it from API client side.
I know Custom field exists for Generic relation but the documentation example is not thoroughly explained.

Can't disable ForeignKey referential integrity check in Django 1.9

I have a model with two entities, Person and Code. Person is referenced by Code twice, a Person can be either the user of the code or the approver.
What I want to achieve is the following:
if the user provides an existing Person.cusman, no further action is needed.
if the user provides an unknown Person.cusman, a helper code looks up other attributes of the Person (from an external database), and creates a new Person entity.
I have implemented a function triggered by pre_save signal, which creates the missing Person on the fly. It works fine as long as I use python manage.py shell to create a Code with nonexistent Person.
However, when I try to add a new Code using the admin form or a CreateView descendant I always get the following validation error on the HTML form:
Select a valid choice. That choice is not one of the available choices.
Obviously there's a validation happening between clicking on the Save button and the Code.save() method, but I can't figure out which is it. Can you help me which method should I override to accept invalid foreign keys until pre_save creates the referenced entity?
models.py
class Person(models.Model):
cusman = models.CharField(
max_length=10,
primary_key=True)
name = models.CharField(max_length=30)
email = models.EmailField()
def __unicode__(self):
return u'{0} ({1})'.format(self.name, self.cusman)
class Code(models.Model):
user = models.ForeignKey(
Person,
on_delete=models.PROTECT,
db_constraint=False)
approver = models.ForeignKey(
Person,
on_delete=models.PROTECT,
related_name='approves',
db_constraint=False)
signals.py
#receiver(pre_save, sender=Code)
def create_referenced_person(sender, instance, **kwargs):
def create_person_if_doesnt_exist(cusman):
try:
Person = Person.objects.get(pk=cusman)
except Person.DoesNotExist:
Person = Person()
cr = CusmanResolver()
Person_details = cr.get_person_details(cusman)
Person.cusman = Person_details['cusman']
Person.name = Person_details['name']
Person.email = Person_details['email']
Person.save()
create_Person_if_doesnt_exist(instance.user_id)
create_Person_if_doesnt_exist(instance.approver_id)
views.py
class CodeAddForm(ModelForm):
class Meta:
model = Code
fields = [
'user',
'approver',
]
widgets = {
'user': TextInput,
'approver': TextInput
}
class CodeAddView(generic.CreateView):
template_name = 'teladm/code_add.html'
form_class = CodeAddForm
You misunderstood one thing: You shouldn't use TextField to populate ForeignKey, because django foreign keys are populated using dropdown/radio button to refer to the id of the object in another model. The error you got means you provided wrong information that doesn't match any id in another model(Person in your case).
What you can do is: not using ModelForm but Form. You might have some extra work to do after you call form.is_valid(), but at least you could code up your logic however you want.

Categories

Resources