2

So I have a Django model which has few non nullable field with default values.

class Article(models.Model):
    id = models.UUIDField(default=uuid4, primary_key=True, editable=False)
    code = models.CharField(max_length=200, default=uuid4, unique=True, null=False)
    company = models.CharField(max_length=200, default=uuid4, unique=True, null=False)

Now i want to do a

Article.objects.get_or_create(company=company, code=am_row['Article code'])

But here the issue is am_row['Article code'] or company can be a None, and in that case i just want a new model to be created using that fields default values.

Currently passing None throws a NOT NULL constraint failed error. How can i achieve this?

So i think this boils down to achieving

Article.objects.create(company=company, code=am_row['Article code'])
4
  • Do you give company and code? or it insert by default? Commented Feb 7, 2019 at 16:54
  • have tried checking if either is none and if it is just creating a new object and saving it like obj = Foo.objects.create() obj.save() ? That should use the default values. You could also check if they are none and just pass in the default values Commented Feb 7, 2019 at 16:56
  • the am_row['Article code'] was None. So it was throwing this error. Commented Feb 7, 2019 at 16:57
  • @Taylor in this case i have only two variables, but what if i have more variables, checking if they are None and passing is not good option . Commented Feb 7, 2019 at 16:58

2 Answers 2

2

You can override the get_or_create method in your model manager, like this:

class CustomManager(models.Manager):
    def get_or_create(self, **kwargs):
        defaults = kwargs.pop('defaults', {})  # popping defaults from values
        for key, value in kwargs.items():
            if value == None:
                kwargs[key] = defaults.get(key)
        return super(CustomManager, self).get_or_create(**kwargs)


class Article(models.Model):
    # ...
    objects = CustomManager()

Then use it in your view like this:

Article.objects.get_or_create(
     company=company,
     code=am_row.get('Article code'),
     defaults={
        'company': uuid.uuid4(),
        'code': uuid.uuid4()
     }
)

If you want the default functionality of get_or_create, then use:

objects = Article._base_manager
objects.get_or_create(...)
Sign up to request clarification or add additional context in comments.

3 Comments

but here what if am_row['Article code'] is not None. In that case i want to create the object with that value only not the default value.
Yep, my mistake. I missed that part of documentation. Updating my answer shortly
awesome , Thanks
1

I'd use or operator in this case. Look at the example. If x is None some default value will be passed:

In [1]: import uuid

In [2]: def some_function(something):
   ...:     print(f'Something is {something}')
   ...:

In [3]: x = None

In [4]: some_function(x or uuid.uuid4())
Something is 518d7187-f74d-4620-90de-6104698a7d07

In [5]: x = 'Hello, world!'

In [6]: some_function(x or uuid.uuid4())
Something is Hello, world!

1 Comment

cool, i didn't knew we could use or directly while passing arguments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.