best way to implement ManyToManyField check? - django

Want to create a Song object. How do I check if this Song object is in a particular user's UserProfile to avoid repetition?
tried this but threw me an error argument of type 'QuerySet' is not iterable;
songs_available = user.userprofile.liked_songs.all()
if not song in songs_available:
user.userprofile.liked_songs.add(song)
models.py
class Song(models.Model):
track_name = models.CharField(max_length=250)
artiste_name= models.CharField(
max_length=200)
album = models.ForeignKey(Album, on_delete= models.CASCADE, null=True, default=None, related_name =
"songs")
class Meta:
db_table="Song"
def __str__(self):
return self.track_name
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, default=None , null= True)
liked_songs = models.ManyToManyField("Song", null=True , default=None,
related_name="users_that_liked_me")
class Meta:
db_table = "UserProfile"
def __str__(self):
return self.user.username
views.py (part of it)
song, created = Song.objects.get_or_create(track_name = track,
artiste_name = artist,
album = album)
wanted to try if created but that only checks for the song model as many users could have the same song, it doesnt really help

You can do this, because I have improved your code
class Song(models.Model):
track_name = models.CharField(max_length=250)
artiste_name= models.CharField(
max_length=200)
album = models.ForeignKey(Album, on_delete= models.CASCADE, null=True,
related_name="songs")
class UserProfile(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, null= True)
liked_songs = models.ManyToManyField("Song"related_name="users_that_liked_me")

refer to Django's docs for many-to-many field management.
here you can't directly add a many-to-many fields.
first, you need to create an object then add many-to-many data to it.
https://docs.djangoproject.com/en/3.1/topics/db/examples/many_to_many/

So according to the Django Docs, as #iklinac stated in the comments, .add() prevents duplicate creation when populating a many to many field, as in my case. Eventually solved the problem like this.
song, created = Song.objects.get_or_create(track_name = track,
artiste_name = artist,
album = album)
user.userprofile.liked_songs.add(song)
All other code in my question remains the same.

Related

Django - ForeignKey Filter Choices

I'd like to filter the choices that a user can choose in my ForeignKey Field.
I basically have a ForeignKey for the subject of the Test and the actual topic of the Test. These topics come from a different model and are linked to a subject. Now I'd like to filter the choices to only include the topics that are linked to the currently selected subject. Is that possible and if so, how?
models.py
class Test(models.Model):
student = models.ForeignKey(Person, on_delete=models.CASCADE, blank=True, null=True)
subject = models.ForeignKey(Subject, on_delete=models.CASCADE, blank=True, null=True)
thema = models.ForeignKey(Thema, on_delete=models.CASCADE, blank=True, null=True)
school_class = models.ForeignKey(SchoolClass, on_delete=models.CASCADE, blank=True, null=True)
grade = models.FloatField(validators=[MinValueValidator(0), MaxValueValidator(6)], blank=True, null=True)
date = models.DateField(default=datetime.date.today)
def save(self, *args, **kwargs):
if not self.school_class and self.student:
self.school_class = self.student.klasse
return super().save(*args, **kwargs)
class Thema(models.Model):
subject = models.ForeignKey(Subject, on_delete=models.CASCADE, blank=True, null=True)
thema = models.CharField(max_length=50)
class Subject(models.Model):
teacher = models.ForeignKey(Person, on_delete=models.CASCADE, blank=True, null=True)
name = models.CharField(max_length=20)
The Problem if I use this:
# thema model #staticmethod
def return_thema(subject):
themen = Thema.objects.filter(subject=subject)
return {'thema': themen}
#test model
thema = models.ForeignKey(Thema, on_delete=models.CASCADE, blank=True, null=True,limit_choices_to=Thema.return_thema(subject))
Is that I get the Error:
django.core.exceptions.AppRegistryNotReady: Models aren't loaded yet.
Meaning I can't get the objects of the Thema Model while the models are loading
EDIT (for Swift):
That seemed to resolve the error when trying to makemigrations, but I now get this error, when visiting the admin portal to create a new Test:
File "/Users/di/Code/Schule/GymnasiumApp/venv/lib/python3.10/site-packages/django/db/models/sql/query.py", line 1404, in build_filter
arg, value = filter_expr
ValueError: too many values to unpack (expected 2)
I think what you are looking for ideally would be ForeignKey.limit_choices_to
Please see the docs:
https://docs.djangoproject.com/en/dev/ref/models/fields/#django.db.models.ForeignKey.limit_choices_to
You can limit the choices available at a model level, which is enforced throughout the django app, including forms automatically.
Edit because OP provided more information
Ok so I believe if you declare the thema field on the test model like so, it will solve the issue, and I will explain why after:
class Test(models.Model):
student = models.ForeignKey(Person, on_delete=models.CASCADE, blank=True, null=True)
subject = models.ForeignKey(Subject, on_delete=models.CASCADE, blank=True, null=True)
thema = models.ForeignKey(Thema, on_delete=models.CASCADE, blank=True, null=True, limit_choices_to=Q('thema_set__subject_set'))
school_class = models.ForeignKey(SchoolClass, on_delete=models.CASCADE, blank=True, null=True)
grade = models.FloatField(validators=[MinValueValidator(0), MaxValueValidator(6)], blank=True, null=True)
date = models.DateField(default=datetime.date.today)
def save(self, *args, **kwargs):
if not self.school_class and self.student:
self.school_class = self.student.klasse
return super().save(*args, **kwargs)
We are essentially telling Django to evaluate the relationship between the limited choices "lazily" I.e. when the form is loaded dynamically. Django forms will look at the limit_choices_to field argument and apply it to the available choices.
I'm not 100% about the relationship of your models so the Q(...) I added, might actually need to be Q('subject_set')
If you use django forms you can use the model choice field.
In your view you can set your queryset of this choicefield. Zo you can filter it.
fields['your model field'].queryset = yourmodel.objects.filter(your filter parameters)
I think there is also problem in save method also. Aren't you need to write the name of the model inside like
return super(<modelName>).save(*args, **kwargs)

How to add Category while adding product in Django form? Just like the Django admin form

So I am trying to build an inventory system.
I have 2 models, Categories and Product connected through the ManyToMany field.
I want to add a category while I am adding the product just like it happens in the Django admin form.
How can I do that?
My model.py File
class Categories(models.Model):
name = models.CharField(max_length=30)
organisation = models.ForeignKey(UserProfile, on_delete=models.CASCADE)
def __str__(self):
return f"{self.name}"
class Product(models.Model):
category = models.ManyToManyField(Categories)
brand = models.CharField(max_length=20)
model = models.CharField(max_length=20)
hac = models.CharField(max_length=20, null=True, blank=True)
rate = models.DecimalField(max_digits=6, decimal_places=2)
stock = models.IntegerField(default=0)
# organisation = models.ForeignKey(UserProfile, on_delete=models.CASCADE)
date_added = models.DateTimeField(auto_now_add=True)
date_updated = models.DateTimeField(auto_now=True)
def __str__(self):
return f"{self.brand} {self.model} "
My form.py file
class ProductModelForm(forms.ModelForm):
class Meta:
model = Product
fields = '__all__'
**My code output **
See the below screenshots to understand what I want to do. I basically want that plus button option to add a category from the product form itself.
You should show snippets of codes that we need to provide an answer.

Django Foreign Key select in admin dashboard

Not quite sure how to accomplish this.
I have a Post model which references a foreign key to the Category model.
class Post(models.Model):
STATUS_CHOICES = (
('draft', 'Draft'),
('published', 'Published'),
)
title = models.CharField(max_length=250)
slug = models.SlugField(max_length=250, unique_for_date='publish')
author = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='feature_posts')
body = models.TextField("Body")
lead_in = models.CharField("Lead In", max_length=500, default='', blank=True)
is_featured = models.BooleanField("Is Featured?", default=False)
likes = models.IntegerField(default=0, blank=True)
views = models.IntegerField(default=0, blank=True)
category = models.ForeignKey('Category', null=True, blank=True)
class Category(models.Model):
name = models.CharField(max_length=200)
slug = models.SlugField()
parent = models.ForeignKey('self',blank=True, null=True ,related_name='children')
class Meta:
unique_together = ('slug', 'parent',)
verbose_name_plural = "categories"
All works as intended pretty nicely, except for this in the admin dashboard:
Can anyone give me the pro-tip to avoid this...? It's probably line 1 of the Django admin handbook but I can't for the life of me find line 1! :D
Looked through Django 1.11 admin documentation in models, foreignkey fields, admin etc etc but to no luck.
N.B. It might be worth noting that I am using wagtail, if there are any subtle differences
If you are OK with changing the representation of the category in other places:
class Category(models.Model):
# ...
def __str__(self): # what will be displayed in the admin
return self.name
Otherwise use the solution described in Django admin - change ForeignKey display text.

Filter Album with empty set of tracks Django-Model

I have two models:
class Album(models.Model):
album_name = models.CharField(max_length=100)
artist = models.CharField(max_length=100)
class Track(models.Model):
album = models.ForeignKey(
Album, related_name='tracks',
on_delete=models.CASCADE,
null=True
)
order = models.IntegerField()
title = models.CharField(max_length=100)
duration = models.IntegerField()
Now how can i get the collection of Album with empty set of tracks?
Try to use isnull:
Album.objects.filter(tracks__isnull=True)
Just read the doc here. You can't save a model with field who haven't value or you need to had null=True to allow null field save in your database
models.py
class Album(models.Model):
album_name = models.CharField(max_length=100, null=True)
artist = models.CharField(max_length=100, null=True)
class Track(models.Model):
album = models.ForeignKey(Album, related_name='tracks', on_delete=models.CASCADE, null=True)
order = models.IntegerField(null=True)
title = models.CharField(max_length=100, null=True)
duration = models.IntegerField(null=True)
Info: if your database is Postgre, it's recommended to initialize field at null=True.
EDIT: thank so much for people who had negative point but never give answer.
To get list of Album with empty tracks. You need to save empty tracks first, related to the album (it's why you need to add null=True) and do a query like that :
Album.tracks.all()
This query take the Album of your choice, and select all tracks who have this album was related name. So the result is a query with the list of tracks who have Album has key.

Django inheritence question

some body please explain me the following i have two classes Userprofile and Staff.staff inherits userprofile
My Question is that if any entry has to be made to a staff table .1.It would be mandatory to fill out the details of user profile right?
Please explain this inheritence.Thanks
class Profile(models.Model):
user = models.ForeignKey(User, unique=True)
created_date = models.DateTimeField(auto_now_add=True)
emp_first_name = models.CharField(max_length=255)
emp_last_name = models.CharField(max_length=255)
gender = models.CharField(max_length=2, choices = GENDER_CHOICES, null=False)
date_of_birth = models.DateField(blank=True,null=True)
address1 = models.CharField(max_length=255)
city = models.CharField(max_length=48)
state = models.CharField(max_length=48)
country = models.CharField(max_length=48)
email_id = models.EmailField(blank=True)
class Staff(UserProfile):
role = models.ManyToManyField(Role)
designation = models.CharField(max_length=48, blank=True, null=True)
education = models.CharField(max_length=255, blank=True, null=True)
If you take a look at https://docs.djangoproject.com/en/dev/topics/db/models/#multi-table-inheritance you'll see that automatic One-to-One mappings are created. Therefore, an entry for UserProfile is saved, and an entry for Staff is saved with a OneToOne field that points to the UserProfile entry.
However, if you want Staff to just inherit all the fields, I'd recommend setting abstract = True in your UserProfile. This means that Staff inherits all those fields, but you can never create a UserProfile by itself (as described at
https://docs.djangoproject.com/en/dev/topics/db/models/#abstract-base-classes )
class Meta:
abstract = True