Suppose I have a model called User, with a field called name. How can I determine whether a User instance, with a particular name Andrew, already exists in the database?
I could do:
matched_users = User.objects.filter(name = 'Andrew')
if matched_users.count() == 0:
# It does not exist
else:
# It does exist
But is there a way I can do this in one line, without having to retrieve all instances and then count them?
Yes, you can use exists():
if User.objects.filter(name='Andrew').exists():
# do something
But there might me multiple users with same name. You might want to lookup on some unique field e.g. username or email
If you want to insist using count method then it can be written as:
if User.objects.filter(name = 'Andrew').count() > 0:
# exists
Ask for forgiveness: let it try to create a duplicate and handle IntegrityError exception.
You need to define unique=True on the name field for this to work:
Field.unique
This is enforced at the database level and by model validation. If you
try to save a model with a duplicate value in a unique field, a
django.db.IntegrityError will be raised by the model’s save() method.
Related
I need to filter the options for a ForeignKey based on an other ForeignKey.
class LabValue(models.Model):
measurement = models.ForeignKey(
'LabMeasurement', on_delete=models.CASCADE)
unit = models.ForeignKey(
LabMeasurementUnit,
on_delete=models.CASCADE,
limit_choices_to={'parameter__id': self.measurement.parameter.id},
)
How can I retrieve self.measurement.parameter.id? If I manually enter an ID instead of self.measurement.parameter.id like for example "1" the query works.
def __str__(self):
return str(self.measurement.parameter.id)
also works as desired and returns e. g. 1 as result
I don't believe this is possible, not due to Django's ORM, but due to the way the database itself works. measurement is a ForeignKey, so it's a relationship between two tables. But relationships between tables don't deal with filtering.
Thus, you will have to implement this at the level of the forms which update the model, or, alternatively, override the model's save function and throw an error if the desired expectation is not satisfied.
For a very clear answer: You can't do that.
Explanation:
It's a django model when you create model object/save then only your model object is created and on that time valid foreign key of specified instance is to be passed, so giving a limit to specific choices to model directly is not possible you need to handle it from view.
So if you have handle the choices of option in view but as of alternatively you can override clean() method to raise errors.
in model you can use clean method as below:
def clean(self):
if self.measurement.parameter.id == 1:
# .. do whatever you want to write if this condition happens
pass
elif self.measurement.parameter.id in [1,2,3,4,55,6]: # or just pass set of ids, statically or with queryset
# .. code
else:
raise Exception("Unexpected selection of choice!!!")
Suppose I have:
from django.db import models
class MyContentClass(models.Model):
content = models.TextField()
another_field = models.TextField()
x = MyContentClass(content="Hello, world!", another_field="More Info")
Is there a more concise way to perform the following logic?
existing = MyContentClass.objects.filter(content=x.content, another_field=x.another_field)
if existing:
x = existing[0]
else:
x.save()
# x now points to an object which is saved to the DB,
# either one we've just saved there or one that already existed
# with the same field values we're interested in.
Specifically:
Is there a way to query for both (all) fields without specifying
each one separately?
Is there a better idiom for either getting the old object or saving the new one? Something like get_or_create, but which accepts an object as a parameter?
Assume the code which does the saving is separate from the code which generates the initial MyContentClass instance which we need to compare to. This is typical of a case where you have a function which returns a model object without also saving it.
You could convert x to a dictionary with
x_data = x.__dict__
Then that could be passed into the object's get_or_create method.
MyContentClass.objects.get_or_create(**x_data)
The problem with this is that there are a few fields that will cause this to error out (eg the unique ID, or the _state Django modelstate field). However, if you pop() those out of the dictionary beforehand, then you'd probably be good to go :)
cleaned_dict = remove_unneeded_fields(x_data)
MyContentClass.objects.get_or_create(**cleaned_dict)
def remove_unneeded_fields(x_data):
unneeded_fields = [
'_state',
'id',
# Whatever other fields you don't want the new obj to have
# eg any field marked as 'unique'
]
for field in unneeded_fields:
del x_data[field]
return x_data
EDIT
To avoid issues associated with having to maintain a whitelist/blacklist of fields you, could do something like this:
def remove_unneeded_fields(x_data, MyObjModel):
cleaned_data = {}
for field in MyObjModel._meta.fields:
if not field.unique:
cleaned_data[field.name] = x_data[field.name]
return cleaned_Data
There would probably have to be more validation than simply checking that the field is not unique, but this might offer some flexibility when it comes to minor model field changes.
I would suggest to create a custom manager for those models and add the functions you want to do with the models (like a custom get_or_create function).
https://docs.djangoproject.com/en/1.10/topics/db/managers/#custom-managers
This would be the cleanest way and involves no hacking. :)
You can create specific managers for specific models or create a superclass with functions you want for all models.
If you just want to add a second manager with a different name, beware that it will become the default manager if you don't set the objects manager first (https://docs.djangoproject.com/en/1.10/topics/db/managers/#default-managers)
I have been searching for best practice, but I did not found it. I was even unable to find solution I need used by anyone else.
I need to generate username of the user based on his other data (first name & last name), optionally appending integer at the end, until I get the unique username.
I strongly prefer doing that in model. Is there some standard way to do that? Or is it only appropriate in forms? I have been researching overloading of various User model methods, as well as signals, and did not find any proper place I could add it.
One possible solution could be through pre_save signal.
def my_callback(sender, **kwargs):
obj = kwargs['instance']
if not obj.id:
username = get_unique_username(obj) # method that combines first name and last name then query on User model, if record found, will append integer 1 and then query again, until found unique username
obj.username = username
pre_save.connect(my_callback, sender=User)
I'm using Django 1.3 for one of my projects and I need to get the ID of a record just saved in the database.
I have something like the code below to save a record in the database:
n = MyData.objects.create(record_title=title, record_content=content)
n.save()
The ID of the record just saved auto-increments. Is there a way to get that ID and use it somewhere else in my code?
Use n.id after the save.
See "Auto-incrementing primary keys".
It would be n.pk.
To quote "Model.pk":
Regardless of whether you define a
primary key field yourself, or let
Django supply one for you, each model
will have a property called pk. It
behaves like a normal attribute on the
model, but is actually an alias for
whichever attribute is the primary key
field for the model. You can read and
set this value, just as you would for
any other attribute, and it will
update the correct field in the model.
The ID will be automatically updated in your model, so immediately after your n.save() line you can read n.id and it will be populated.
Remove save() and get pk directly:
n = MyData.objects.create(record_title=title, record_content=content)
n.pk
If someone reading this question and after check the other answers still having problems accessing the id after the creation of the object.
Be sure you don't define id as an Integer in your model. If you decide to declare it anyways, use Autofield but you don't need to, It is for free with models.Model
#No
class TestModel(models.Model):
id = models.IntegerField(primary_key=True)
something...
#Ok
class TestModel(models.Model):
id = models.AutoField(primary_key=True)
something...
#Ok
class TestModel(models.Model):
something...
if you do define id as Integer, TestModel.objects.create( or with save() will return None.
I had a similar issue with accessing the id. In Django 3.0.5, this is how I accessed the id. Using your example and variable name, see below:
instance = n.save()
# return the id
instance[0].id
The variable 'instance' above is a list. Accessing id in the methods described above returns an AttributeError ("object has no attribute 'id'") in Django 3.
This answer applies when using modelformset_factory. This is true when creating a Form class from a Django model as described in the Django docs
is there another REGEX way (or another way) to ensure that a model class field would be unique? (it is not a key, or at least not declared as a key, is shoulb be a simple CharField)
Thanks
The normal way to make a single field unique is to use the unique argument to the field constructor.
If you need to make this unique on more than one field, have a look at:
unique-together
There are two ways of doing so.
The first is to mark the entire column as unique. For example:
product_name = models.Charfield(max_length=10, unique=True)
This method is good when you want your entire column to be inherently unique regardless of the situation. This can be used for username, id, key etc.
However, if the column cannot be inherently unique but it has to be unique in relation to others, you have to use the manual way.
from django.core.exceptions import ObjectDoesNotExist
try:
n = WishList.objects.get(user=sample_user, product=sample_product)
# already exists
return False
except ObjectDoesNotExist:
# does not exist
wish_list = WishList(user=sample_user, product=sample_product)
wish_list.save()
return True
Take this as an example. You have a wish list which none of the items can be unique. A single user can have many products and a single product can be in the wish list of many users. However, a single user cannot add one particular product to his or her wish list more than once. And this is where unique=True cannot be used and we have to use try and except