django unique field - django

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

Related

Why do Get and Filter give different results? (Django)

I am developing an app where students can evaluate their teachers. I have several models, but the important ones for this question are these:
class Professor(models.Model):
name = models.CharField(max_length=50,null=True)
categories = models.ManyToManyField(Category, related_name='professors')
def __str__(self):
return self.name
class Student(models.Model):
name = models.CharField(max_length=50,null=True)
professors = models.ManyToManyField(Professor, related_name='students',through='Studentprofesor' )
def __str__(self):
return self.name
class Studentprofesor(models.Model):
student = models.ForeignKey(Student, on_delete=models.CASCADE)
professor = models.ForeignKey(Professor, on_delete=models.CASCADE)
tested = models.BooleanField(default=False)
As far as I knew the main difference between get and filter was that I couldn't use get when there were several objects with the features I was looking for. But apart from that, they worked in a similar way. get for a single object, filter for several objects.
However, in this case I get different results when I run get and filter.
if I use get:
Student.objects.get(name="Mike").professors.all()
I obtain:
<QuerySet [<Professor: Tom>, <Professor: Jenn>]>
But if I use filter:
Student.objects.filter(name="Mike").professors.all()
I obtain:
AttributeError: 'QuerySet' object has no attribute 'professors'
it's as if filter is not able to follow the manytomany relationship between the objects.
Why is this happening?
There are huge differences between .get(..) and .filter(..). In short: .get(..) obtains a single model instance that satisfies the given conditions whereas .filter(..) filters the queryset and produces a queryset that conceptually contains model instances (!) that satisfy the given conditions.
Django's .get(..)
.get means that you aim to retrieve exactly one instance. So that means that if you write:
Model.objects.get(..)
the result is a Model instance (given there is such instance). As a result we can thus obtain attributes (like .professors, etc.) from that single entity. We have guarantees if the call succeeds that: (1) there are no multiple objects for which the filter criteria hold; and (2) there is at least one element for which the filter criteria hold. So the output is always a model instance, not a None or a QuerySet.
The .get(..) function is evaluated eagerly: we immediately perform a query to the database. In case the database returns no entries, or two or more, the Model.DoesNotExist and MultipleObjectsReturned exceptions are respectively risen.
Note: since .get(..) acts eagerly, adding filters, etc. at the right of .get(..) has no use (well unless you define a filter function on that instance, but that is not a good idea either). You can however use functions like .values(), values_list, prefetch_related, etc. on the left side to change the type of output (and prefetch certain parts). For example:
Student.objects.values().get(name='Mike')
will result in a dictionary containing the values of that instance.
Django's .filter(..)
Filter on the other hand filters a queryset. That means that it is possible that after we filter, the queryset no longer contains any instances (if the filter is too restrictive) or two ore more (if the filter is too weak to pin to a single entry).
Django does not evaluate such .filter(..) eagerly. This means that by default Django will not make a query to the database to retrieve entries. Only if you call for example len(..) over the resulting queryset, or you iterate over it, Django will first perform a database query and then handle the corresponding result.
Since the result of a .filter(..) is another QuerySet, we can chain operations together. For example, we can call an extra .filter(..) or .exclude(..), values_list(..) or any other function supported by the QuerySet.
Since the result is not a model instance, we can not call the attributes of a model instance. What should be the outcome of a Student.objects.filter(..).name in case no student matches the criteria? Or what if there are multiple Students that match the given constraint?
We can however obtain the list of Professors that teach one or more Students with the name 'Mike' with:
# professors with a student called Mike
Professors.objects.filter(students__name="Mike")
A filter will never raise an Model.DoesNotExist or a MultipleObjectsReturned exception, since it is perfectly allowed to work with empty QuerySets, or QuerySets with multiple items.
Bacause filter() returns queryset (multiple students). But professors is attribute of single student instance. You can use first() with filter() to get single object:
Student.objects.filter(name="Mike").first().professors.all()

Counting number of model instances

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.

Django multiple Many2Many relationships

I have created a model where I define a Place, which has several properties (M2M) and each property has several choices. A user is able to vote for one or more of the choices, therefore I define a M2M relationship from the choices to a user. However I do not achieve the required functionality, as the user is connected only to the choices and not to the specific place that has the choices. my model is as follows:
class Place(models.Model):
StoreName=models.CharField(max_length=200)
Pic=models.ImageField(upload_to="media",blank=True,null=True)
Address=models.CharField(max_length=200)
def __unicode__(self):
return self.StoreName
class TypeProperty(models.Model):
Place = models.ManyToManyField(Place)
TypePropertyName=models.CharField(max_length=42)
def __unicode__(self):
return self.TypePropertyName
class TypeChoices(models.Model):
TypeProperty = models.ForeignKey(TypeProperty)
TypeChoiceName=models.CharField(max_length=42)
UserVoted=models.ManyToManyField(User,blank=True,null=True)
How can I achieve the functionality
A User has voted for the Choice that for the specific Place
From User you can get TypeChoices:
user_instance.typechoices_set.all()
Then, you can loop through each TypeChoice and access the Place queryset through the TypeProperty attribute:
typechoice_instance.TypeProperty.Place.all()
Then you would need to loop through each Place to do whatever.
Now, looking at that, it should be immediately apparent that there's some serious flaws here. The code makes no sense, and it's not readable. This is why coding conventions exist. Please give the Python Style Guide (PEP8) a thorough read.
In particular to your code here, attributes on a class should be all lower-case and words in the attribute's name should be separated by underscores, i.e. store_name NOT StoreName.
Then, attribute names should parallel what they represent: Place makes no sense for a field that will return multiple places. Name it places to indicate that it returns multiple items (and in particular returns a queryset rather than a model instance).
UPDATE
If you want that, then you need to work backwards and select the TypeChoices:
TypeChoices.objects.filter(UserVoted=some_user, TypeProperty__Place=some_place)

Django Set Default as Subset of ManyToMany Model Field

class UserProfile(models.Model):
project_assignments = models.ManyToManyField('drawingManager.Project', default=SetDefaultProject(self,default_assignment))
user = models.OneToOneField(User)
default_project
def SetDefaultProject(self,default_assignment):
if default_assignment:
self.default_project = default_assignment
else:
self.default_project = #somehow choose newest project
def __unicode__(self):
admin_reference = self.user.first_name + self.user.last_name
return admin_reference
I'm trying to achieve the following behavior. When a user is added at least one project assignment is set at the default. And they can later, through an options interface set their default to any of the subset of project_assignments. But it's not clear to me when you can use Foreign Key and Many to Many Fields as just python code and when you can't.
If I understand you correctly, you're not understanding that ForeignKeys and ManyToManyFields return different things.
A ForeignKey is a one-to-many relationship, with the 'one' on the side that it's pointing to. That means that if you defined default_project as a ForeignKey, self.default_project returns a single Project instance which you can use and assign as any other instance.
However, a ManyToManyField - as the name implies - has "many" relationships on both sides. So self.project_assignments doesn't return a single instance, it returns a QuerySet, which is the way Django handles lists of instances retrieved from the database. So you can use add and remove to manipulate that list, or slice it to get a single instance.
For example, if you wanted to set the default_project FK to the first project in the project assignments list, you would do:
self.default_project = self.project_assignments.all()[0]
(although in real code you would have to guard against the probability that there are no assignments, so that would raise an IndexError).
I'm not sure I undertsand what you mean by "it's not clear to me when you can use Foreign Key and Many to Many Fields as just python code", but your pseudo code would work with the following changes:
def SetDefaultProject(self,default_assignment):
if default_assignment:
self.project_assignments.add(default_assignment)
else:
self.project_assignments.add(self.project_assignments.latest('id'))
# note: i don't know what your intent is, so please adapt to your needs
# the key here is `MyModel.objects.latest('id')` to retrieve the latest object
# according to the field specified. 'id', 'date_created', etc.
PS: it's recommended to use lowercase names & underscores for method names (to not confuse them with ClassNameFormatRecommendations)
http://www.python.org/dev/peps/pep-0008/

unique_together foreign key object properties

I've got two models: Common and ARecord. ARecord has a ForeignKey relationship to Common. I want to ensure that ARecord is unique with a combination of items from ARecord and Common.
class Common(models.Model):
NAIC_number = models.CharField(max_length=5)
file_location_state = models.CharField(max_length=2)
file_location_code = models.CharField(max_length=2)
class ARecord(models.Model):
common = models.ForeignKey(Common)
coverage_code = models.CharField(max_length=6)
record_type = models.CharField(max_length=1)
class Meta:
unique_together = ('coverage_code', 'common__NAIC_number')
However, when I attempt to access the foreign key object property via the usual double underscore, I get a model validation error.
`arecord.arecord: "unique_together" refers to common__NAIC_number, a field that doesn't exist. Check your syntax.`
This seems like it should be possible and, a slightly different question was asked that indicates it is , but perhaps I'm missing something obvious?
As Manoj implies, you can't do this with unique_together, because that is a database constraint and the sort of thing you want can't be done with database constraints.
Instead, you want do this programmatically, probably via model validation, which will ensure that no instances are created that violate your constraint.
This doesn't make sense to me. The documentation defines unique_together thus:
This is a list of lists of fields that must be unique when considered together. It's used in the Django admin and is enforced at the database level (i.e., the appropriate UNIQUE statements are included in the CREATE TABLE statement).
(Emphasis added)
I don't know how an UNIQUE statement can be added at the database level for such a case (using one column in the current table and another in a different table accessed through a foreign key). I hope those who know better about databases will correct me if I am wrong.