0

I am using Django Rest Framework. I am using this suggestion for adding new value in auto-suggest Select2 dropdown but allow new values by user? . But it seems almost impossible for me.

Payee is the foreign key field. If string along with '(NEW)' is returned instead of primary key, I need to create the object in the Contacts model and should set primary key of the newly created object to payee field.

models.py

class Contacts(models.Model):
    no = models.AutoField(primary_key=True)
    name = models.CharField(max_length=25)
class Transactions(models.Model):
    payee = models.ForeignKey(Contacts,null=True, related_name = 'transactions_payee')
    reminder = models.ForeignKey(Reminders, related_name='transaction_reminders',blank=True, null=True) 

serializers.py

class TransactionSerializer(serializers.ModelSerializer):
    reminder = ReminderSerializer()

    class Meta:
      model = Transactions
      fields=('pk','payee','reminder'...)

    def validate_payee(self, value):
      if "  (NEW)" not in value:
        return value
      else:
        payee = value.replace("  (NEW)", "")
        contact = Contacts.objects.create(name = payee)
        value = contact.no
        return value

    def create(self, validated_data):
       ...  #writable nested serializer for reminder field.

    def update(self, instance, validated_data):
       ...  #writable nested serializer for reminder field.

The validate_payee is not even called. I even tried adding the same logic inside create() but somewhere the django's default validator comes before all of that and throws the error message saying

{payee: ["Incorrect type. Expected pk value, received unicode."]}

I am a beginner in Django. I have search almost all the stackoverflow questions. Nothing works for me or maybe I am making a mistake somewhere.

Community
  • 1
  • 1
Aswin Kumar K P
  • 1,023
  • 2
  • 12
  • 21

1 Answers1

0

Solution #1

{payee: ["Incorrect type. Expected pk value, received unicode."]}

Above error happens because TransactionSerializer is handling field "payee" as ForeignKeyField (like a PK).

So when your validate_payee method is called instead of return a PK value, you are returning a unicode string.

I think that you are trying to handle payee in valdiate_payee as an instance of Payee model.

If that is what you want, then my suggestion will be to update TransactionSerializer and try adding one of this lines:

reminder = ReminderSerializer()
payee = PayeeSerializer() # This is one
payee = ContactSerializer() # Or this one.

Doing the above make sure your validate_payee function returns an instance of Contact.

If validation is not ok, just raise ValidationError (http://www.django-rest-framework.org/api-guide/exceptions/#validationerror)

Solution #2 Try to change: value = contact.no by value = contact.id

Recomendation, if you are just starting with DRF, to inspect your code, just insert: import ipdb; ipdb.set_trace() this will set a break-point with interactive python shell so you can check if that code is being executed and also you can check the current content of your variables.

In your case if you want to check if validate_payee is being executed, try:

def validate_payee(self, value):
      import ipdb; ipdb.set_trace()
      if "  (NEW)" not in value:
        return value
      else:
        payee = value.replace("  (NEW)", "")
        contact = Contacts.objects.create(name = payee)
        value = contact.no
        return value

Hope this can help.

Fer Mena
  • 273
  • 2
  • 12
  • Firstly for your Recommmendation, I used `logger.debug("Inside Validate")` inside the validate_payee() function. It didnot log at all. Your solution #1 gives the error saying `payee: {non_field_errors: ["Invalid data. Expected a dictionary, but got unicode."]}` . `no` is the Primary Key field in the Contacts model. I also tried `payee = serializers.PrimaryKeyRelatedField(queryset=Contacts.objects.all(), source='payee', write_only=True, validators=[validate_payee])` but the error comes as `validate_payee() takes exactly 1 argument (2 given)`. Please Help. :) – Aswin Kumar K P Jan 07 '16 at 04:21
  • Ok, I figured it out, it is not entering to your validate function, because TransactionSerializer in payee field is expecting an integer. But your application can send also strings. I would suggest you to set payee=serializers.CharField() this way you can receive almost everything in your TransactionSerializer, then you will be able to handle value in your validation function. – Fer Mena Jan 07 '16 at 22:47
  • I also tried that. When I use that, it successfully validates, removes '(NEW). But it throws error in the create() method saying that `payee: Expecting Foreign Key field but got some string....` . I think there must be some hack for that. – Aswin Kumar K P Jan 08 '16 at 02:58
  • Thats perfectly fine just override your create method in TransactionSerializer. Inside create method you just need to pop payee from validated_data (def create(self, validated_data)) and then create your payee instance acording to the value you pop out. Remember validated_data is a dictionary which contains arguments needed to create the instance inside create method, just make sure your create method returns something like: instance = Transactions.objects.create(**validated_data). – Fer Mena Jan 08 '16 at 15:25
  • I have already mentioned in the question. When I use the logic in the create() field, django's default validation comes in even before create is and says `{payee: ["Incorrect type. Expected pk value, received unicode."]}`. – Aswin Kumar K P Jan 08 '16 at 16:26
  • I know and thats why you need to pop payee from validated_data and then set a proper FK for payee inside validated_data. – Fer Mena Jan 10 '16 at 04:26