Django Foreign Key select in admin dashboard - django

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.

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)

drf create manytomany fields

models
class CreatorRawArtwork(models.Model):
id = models.AutoField(primary_key=True)
title = models.CharField(max_length=500)
descripton = models.TextField()
editions = models.IntegerField(null=True, blank=True)
price = models.CharField(max_length=500)
created_at = models.DateTimeField(auto_now_add=True, null=True, blank=True)
medias = models.FileField(null=True, blank=True, upload_to="raw-medias")
user = models.ForeignKey(to=Login, on_delete=models.CASCADE, related_name="creatorrawartwork", null=True, blank=True
)
collection = models.ForeignKey(
to=DesignerCollection, on_delete=models.CASCADE, related_name="creatorrawartwork", null=True, blank=True)
categories = models.ManyToManyField(DesignerCategories, related_name='creatorrawartwork')
def __str__(self):
return self.title
serializer
class CreatorRawArtworkSerializer(serializers.ModelSerializer):
categories = serializers.PrimaryKeyRelatedField(queryset=DesignerCategories.objects.all(), many=True)
class Meta:
model = CreatorRawArtwork
fields = "__all__"
depth=1
views
class CreatorRawArtworkView(viewsets.ModelViewSet):
queryset = CreatorRawArtwork.objects.all()
serializer_class = CreatorRawArtworkSerializer
Here i am trying to create manytomany fields using drf serialier it is showing some error
plese check the screenshot for parameter and responses
What can be the issue please take a look
class CreatorRawArtworkSerializer(serializers.ModelSerializer):
collection = DesignerCollectionSerializer(read_only=True) #assuming you have already defined serializer for *DesignerCollectionSerializer*
categories = DesignerCategoriesSerializer(many=True)
class Meta:
model = CreatorRawArtwork
fields = "__all__"
depth=1
I tested with your code and your code is working fine
just make sure your request data is json

best way to implement ManyToManyField check?

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.

How do I get related Model field in Django using the Django Admin

I think that my problem here is Django specific and not necessarily a reflection on
my understanding of relational databases (hopefully).
I have a Django app that stores information on Contacts.
With that one table things seemed to work fine. When I wanted to categorize
the type of relationship - is this a professional relationship, family, friends, etc.
That's when things didn't show up like I wanted. I finally got the migration to work
with the new table.
I'm using python 3 with the latest version of django. I have a mysql
database. I want a one to many relationship, where one contact can
be characterized by many categories. When I work with the django admin
and try to enter a contact, I'm not seeing a field for entering relationship categories.
So, here is my models.py for the contacts app.
from django.db import models
class Resource(models.Model):
first_name = models.CharField(max_length=40)
last_name = models.CharField(max_length=40)
organization = models.CharField(max_length=60, null=True, blank=True)
street_line1 = models.CharField("Street Line 1", max_length=50, null=True, blank=True)
street_line2 = models.CharField("Street Line 2", max_length=50, null=True, blank=True)
city = models.CharField(max_length=40, null=True, blank=True)
state = models.CharField(max_length=40, null=True, blank=True)
zipcode = models.CharField(max_length=20, blank=True, null=True)
phone1 = models.CharField(max_length=20, null=True, blank=True)
phone2 = models.CharField(max_length=20, null=True, blank=True)
email = models.EmailField(max_length=60, null=True, blank=True)
website = models.URLField(max_length=90, null=True, blank=True)
def __str__(self):
return "%s %s \t%s" % (self.first_name, self.last_name, self.organization)
class Meta:
ordering = ('last_name',)
class Relationship(models.Model):
category = models.CharField(max_length=120)
resource = models.ForeignKey(Resource, related_name='category')
def __str__(self):
return self.category
class Meta:
ordering = ('category',)
Thanks in advance for any help,
Bruce

Django migrations Many2Many Through model, ValueError: Cannot alter field

Hey guys I want to sort my many to many field and in that case I want to through. My code look something like this:
class SkirunRatePoint(models.Model):
latitude = models.DecimalField(u'lat', max_digits=10, decimal_places=6)
longitude = models.DecimalField(u'lng', max_digits=10, decimal_places=6)
elevation = models.DecimalField(max_digits=10, decimal_places=6, blank=True, null=True)
name = models.CharField(u'Name', max_length=200, blank=True, null=True)
class Meta:
verbose_name = u'Point'
verbose_name_plural = u'Points'
def __unicode__(self):
return unicode('{0} / {1}'.format(self.latitude, self.longitude))
class SkirunRoute(models.Model):
skirun = models.ForeignKey(Skirun, verbose_name=u'Path')
ratepoints = models.ManyToManyField(
SkirunRatePoint,
through="SkirunRatePointThrough",
verbose_name=u'Points',
blank=True,
)
class Meta:
verbose_name_plural = u'trasy z punktami'
def __unicode__(self):
return unicode(self.skirun)
class SkirunRatePointThrough(models.Model):
skirunroute = models.ForeignKey(SkirunRoute, related_name="skirun_route")
skirunratepoint = models.ForeignKey(SkirunRatePoint, related_name="skirun_rate_points")
order = models.IntegerField(
blank=True,
null=True,
)
Don't mind about indents, they are find on my pc.
Makemigrations is going fine, but when I try to migrate it throws me an error which says:
ValueError: Cannot alter field skirun.SkirunRoute.ratepoints into skirun.SkirunRoute.ratepoints - they are not compatible types (you cannot alter to or from M2M fields, or add or remove through= on M2M fields)
Any ideas what might be the problem ?