Automatic avoidance of category duplicates - python

I have the problem with Category Model.
I have 2 tables:
class Category(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, null=True)
name = models.CharField(max_length=30, null=False)
class Movie(models.Model):
category = models.ForeignKey(Category, on_delete=models.CASCADE, null=True)
name = models.CharField(max_length=30, null=False)
so they are standard models with categories.
User can create Category by creating a movie with the name of category additionaly.
The problem is when user is trying to create Movie with category name that already exists, because it will create another category with the same name (like duplicate) and I want to avoid it.
How to do it?
I can't create unique name field, because many users can have same category (but I can use ManyToManyRelation) but still I don't know how to automatically avoid duplicates like bellow:
If Category with that Name and this User does not exist > create Category
If Category with that Name and this User exists > use this Category
Regards

Though your explanation is vague. But from your explanation, it seems like you want the categories to be unique with each user. Different users can have same categories, but same user can't have any duplicate one.
for that
class Category(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, null=True)
name = models.CharField(max_length=30, null=False)
class Meta:
unique_together = ["user","name"] #This will
#make a constraint to check if both user and name is unique
According to your comment you want unique constraints with nullable ForeignKey too. try overriding the clean method in the model class (Category model)
from django.core.exceptions import ValidationError
def clean(self):
if self.user is None and Category.objects.filter(name=self.name, user=None).exists():
raise ValidationError("Duplicate Category with name=%s already exists" % self.name)

This will prevent the categories duplication. Just set unique to True.
class Category(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, null=True)
name = models.CharField(max_length=30, unique=True)

Related

Django Models, on delete set pk

This is my models:
class Customer(models.Model):
nome = models.CharField(max_length=40)
indirizzo = models.CharField(max_length=40)
class Appo(models.Model):
appo = models.CharField(max_length=40)
customer = models.ForeignKey(Customer, on_delete=models.SET_NULL, null=True, blank=True, default=1,related_name='appocli')
now, if I delete a Customer I need SQL set in Appo models a specific PK for customer Foreign Key. For example 1.
Something like: on delete set 1
Please help
You can use SET_DEFAULT to set your foreign key to a default value
customer = models.ForeignKey(Customer, on_delete=models.SET_DEFAULT, default=1)

How to process data from one model field to another

I have models of Exercise, Training and Workout.
Training contains some exercises (Exercise)
Workout contains trainings (Training).
Snippet of my models.py:
class Exercise(models.Model):
user = models.ForeignKey(User, related_name='exercises',
on_delete=models.CASCADE)
name = models.CharField(max_length=80)
description = models.TextField(max_length=300)
details = models.ManyToManyField(ExerciseDetail, blank=True)
...
class Training(models.Model):
user = models.ForeignKey(User, related_name='trainings',
on_delete=models.CASCADE)
name = models.CharField(max_length=80)
description = models.CharField(max_length=250)
exercises = models.ManyToManyField(Exercise, related_name='trainings',
blank=True)
...
class Workout(models.Model):
user = models.ForeignKey(User, related_name='workouts',
on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now=True)
name = models.CharField(max_length=200)
description = models.TextField(max_length=400, blank=True)
trainings = models.ManyToManyField(Training, related_name='workouts',
blank=True)
...
I would like to have possibility to use something like Workout.objects.get(name='workout').exercises.objects.all() to get a list/set of all exercises included in trainings of chosen Workout.
I would also like to have possibility to use exercises`` field with Django Rest Framework to list all exercises, possibly with link to particularExercise``` model serializer.
Can someone give a hint how can I do that?
You can query this with:
Exercise.objects.filter(
trainings__workouts__name='workout'
)
With the consecutive underscores (__), you thus can look "through" relations.
This will thus return the Exercises that belong to Trainings that belong to Workouts with as name 'Workout'.

Django OneToOneField allow online one reference

I am trying to create a one to one reference and want to make sure that that reference is not allowed to be used for another model or instance.
For example
Say I have an address model, Person Model and Company Model
Person has a OneToOneField field to Address
Company also has a OneToOneField field to Address
address=Address(data="some address")
company=Company(name="some company",address=address)
person=Person(name="my name",address=address)
Models:
class Address(models.Model):
data = models.CharField(max_length=255, blank=True, null=True)
class Company(models.Model):
name = models.CharField(max_length=255, blank=True, null=True)
address=models.OneToOneField(Address,on_delete=models.CASCADE)
class Person(models.Model):
name = models.CharField(max_length=255, blank=True, null=True)
address=models.OneToOneField(Address,on_delete=models.CASCADE)
I would like the system to throw an error on this since I am setting the same address to 2 different models.
Also this would delete both person and company if I delete address.
Usually you catch this with code and not make a stupid mistake like this.
But can system catch it since it is one to one ?
In the case of the deletion you could use on_delete=models.PROTECT. In the other case you could add unique=True so a person id = 1 will have a address id = 1, a person id = 2 can't have a address id = 1 anymore. But it would only solve for one model:
address=models.ForeignKey(Address, unique=True, on_delete=models.PROTECT)
A new approach would be create a model to reference the address of both company and person and be able to forbid the creation with the same address id:
class AddressExample(models.Model):
id_address = models.ForeignKey(Address, unique=True,on_delete=models.PROTECT)
id_person = models.ForeignKey(Person, blank=True, null=True, unique=True, on_delete=models.PROTECT)
id_company = models.ForeignKey(Person, blank=True, null=True, unique=True, on_delete=models.PROTECT)
Note that I used blank=True, null=True so you can create an instance only with a Person or a Company, without the need to create a instance with both. There is a Meta to use combination of primary keys too.
class AddressExample(models.Model):
id_address = models.ForeignKey(Address, unique=True,on_delete=models.PROTECT)
id_person = models.ForeignKey(Person, blank=True, null=True, unique=True, on_delete=models.PROTECT)
id_company = models.ForeignKey(Person, blank=True, null=True, unique=True, on_delete=models.PROTECT)
class Meta:
unique_togther = ('id_address', 'id_person', 'id_company')
# Not sure if it will throw a error here because `id_person` and `id_company` can be blank
# or null. But the use of `unique together` is for cases where you want to guarantee
# the combination of the primary keys will be unique.
Hope it helps.

Get models ordered by an attribute that belongs to its OneToOne model

Let's say there is one model named User and the other named Pet which has a OneToOne relationship with User, the Pet model has an attribute age, how to get the ten User that owns the top ten oldest dog?
class User(models.Model):
name = models.CharField(max_length=50, null=False, blank=False)
class Pet(models.Model):
name = models.CharField(max_length=50, null=False, blank=False)
owner = models.OneToOneField(User, on_delete=models.CASCADE)
age = models.IntegerField(null=False)
In User, there is an attribute friends that has a ManyToMany relationship with User, how to get the ten friends of User Tom that owns the top ten oldest dog?
class User(models.Model):
name = models.CharField(max_length=50, null=False, blank=False)
friends = models.ManyToManyField(self, ...)
class Pet(models.Model):
name = models.CharField(max_length=50, null=False, blank=False)
owner = models.OneToOneField(User, on_delete=models.CASCADE)
age = models.IntegerField(null=False)
Use the double-underscore syntax.
User.objects.order_by('-pet__age')[:10]
Edit
To get the ten friends of Tom, you can get the instance and filter:
User.objects.get(name='Tom').friends.order_by('-pet__age')[:10]
or if you already have Tom:
tom.friends.order_by('-pet__age')[:10]
Another solution (alternative to order_by) is using nlargest function of heapq module, this might be better if you already have friends list (tom's friends in this case) with a large number of items (I mean from performance perspective).
import heapq
heapq.nlargest(
10,
User.objects.get(name='Tom').friends.all(),
key=lambda f: f.pet.age
)
Note: You have also nsmallest function that you can use to get the youngest pets.
Try this :
First define unicode in model User like this:
By this,User model objects will always return name field of the user records.
class User(models.Model):
name = models.CharField(max_length=50, null=False, blank=False)
friends = models.ManyToManyField(self, ...)
def __unicode__(self):
return self.name
Then use this query:
User.objects.filter(friends='Tom').order_by('-pet__age')[:10]

Django ORM: Models with 2 table referencing each other

I have 2 tables. User and Group. 1:Many relationship. Each user can only belong to a single group.
here's the model.py.
class Group(models.Model):
group_name = models.CharField(max_length=150, blank=True, null=True)
group_description = models.TextField(blank=True, null=True)
group_creator = models.ForeignKey(User, models.DO_NOTHING)
class User(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
...
group = models.ForeignKey(Group, models.DO_NOTHING)
The issue I have is that they are both referencing each other which is acceptable in MySQL and Oracle, but, I get an error when migrating:
group_creator = models.ForeignKey(User, models.DO_NOTHING)
NameError: name 'User' is not defined
Now when I reverse the order (so, User first than Group), I get
group = models.ForeignKey(Group, models.DO_NOTHING, blank=True, null=True)
NameError: name 'Group' is not defined
This is getting quite frustrating. I have a few work around (make it a many:many and keep creator on Group class), but before I start destroying my datamodel and move data move all the data around, I wonder if anyone has this issue before. How did you solve this? Do you really have to change your datamodel?
as Pourfar mentioned in a comment, you may avoid the NameError via the quoting the model object as string. also it is safe to set related_name for accessing this relation.
class Group(models.Model):
...
group_creator = models.ForeignKey('User', related_name='creator_set')
and then, with your constraint,
Each user can only belong to a single group.
in that case, OneToOneField is more appropriate.
class User(models.Model):
...
group = models.OneToOneField(Group)
then you can access the relations as follows:
# USER is a User object
GROUP_BELONGED = USER.group # access to 1-1 relation
GROUP_CREATED = USER.creator_set.all() # reverse access to foreignkey relation
# now GROUP_BELONGED is a Group object
CREATOR = GROUP_BELONGED.group_creator # access to foreignkey relation
Add related_name to your ForeignKey fields:
class Group(models.Model):
group_name = models.CharField(max_length=150, blank=True, null=True)
group_description = models.TextField(blank=True, null=True)
group_creator = models.ForeignKey('User',related_name='myUser')
class User(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
group = models.ForeignKey('Group', related_name='MyGroup')

Categories