Django rest framework self.objects.all() as variable - python

I have parent id in my model:
parent = models.ForeignKey("self", null=True)
and in serializer:
parent = serializers.PrimaryKeyRelatedField(queryset=Category.objects.all(), required=False)
It shows me selectbox with items: "Category object" as it saves all items like that. What I can do to show Category names?
And there is no None option in selectbox.
Another question:
How to show Categories in select with parent=None?

In you model Category,define __unicode__ method
class Category(models.Model):
//your fields
def __unicode__(self):
return self.name

Related

AttributeError when trying to created nested serializer in Django REST Framework

I have two models of sets, and cards. Theses models have one to many relationship where there are many cards in a single set. These model are join by a foreign key - each card has set_id which is equal to the id of the set. These IDs are UUID.
I am trying to create a serializer using Django REST Framework where I return the details of the set, as well as including all the cards that are part of the set.
error
Got AttributeError when attempting to get a value for field `cards` on serializer `SetSerializers`.
The serializer field might be named incorrectly and not match any attribute or key on the `Set` instance.
Original exception text was: 'Set' object has no attribute 'cards'.
serializers.py
class CardSerializers(serializers.ModelSerializer):
class Meta:
model = Card
fields = ['id', 'number', 'name', 'set_id']
class SetSerializers(serializers.ModelSerializer):
cards = CardSerializers()
class Meta:
model = Set
fields = ['id', 'code', 'name', 'releaseDate','cards']
models.py
class Set(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
...
objects = models.Manager()
def __str__(self):
return self.name
class Card(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
...
set = models.ForeignKey(Set, on_delete=models.CASCADE, related_name='Cards', related_query_name='Cards')
objects = models.Manager()
def __str__(self):
return self.name
views.py
class SetsIndividualData(ListAPIView):
serializer_class = SetSerializers
def get_queryset(self):
setCode = self.kwargs.get('setCode')
queryList = Set.objects.filter(code=setCode.upper())
return queryList
There are a few mistakes in your code.
models.py:
In the Card model, the related_name of the FK should be lowercase as per below:
set = models.ForeignKey(Set, related_name="cards", on_delete=models.CASCADE)
serializers.py:
In your SetSerializers you had the right idea, but you need to be more specific with your CardSerializers, as you are describing a "to-many" relationship.
Please refer to the docs here: https://www.django-rest-framework.org/api-guide/relations/#nested-relationships
Moreover, from your views.py I can see you will only send GET requests, therefore you can have your cards to be read only.
So the serializer card attribute would look like the below:
cards = CardSerializers(many=True, read_only=True)
views.py:
It looks like you want to retrieve a set by id.
ListAPIView is the wrong generics, you should use RetrieveAPIView instead, as it provides a get method and is used to retrieve a single model instance.
Please refer to the docs for more information: https://www.django-rest-framework.org/api-guide/generic-views/#retrieveapiview

Reorganizing ManyToMany models into a different order

I have an setup similar to this.
class Author(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=40)
books = models.ManyToManyField(Book)
def __unicode__(self):
return self.title
class Book(models.Model):
title = models.CharField(max_length=100)
author = models.ForeignKey(Author)
def __unicode__(self):
return self.title
Now in my admin panel I can select an author and add Books underneath that specific author. When I print out all the books for each author it prints them in the order that they were added in the admin panel.
Is it possible to modify the order in the admin panel so that when they print, they print in the order of the admin panel?
admin.py
#admin.register(Author)
class AuthorAdmin(admin.ModelAdmin):
pass
#admin.register(Book)
class BookAdmin(admin.ModelAdmin):
pass
You can add inside every model a class Meta with ordering atribute, to get items in a certain order.
class Book(models.Model):
...
class Meta:
ordering = ['author']
Maybe it helps you.
as i understand you use TabularInline for books if that's right so you just need to make simple function called get_queryset
def get_queryset(self, request):
return super(BookInlineAdmin, self).get_queryset(request).order_by('YOURFIELD')

Pre-populate form field with data from table linked via foreign key

Probably a very novice Django question, but here goes. In my Django project, I have this in my models
#models.py
class Classes(models.Model):
classcode = models.CharField(max_length=15)
classname = models.TextField()
students = models.ManyToManyField(User)
class Test(models.Model):
classes = models.ForeignKey(Classes, on_delete=models.CASCADE)
name = models.TextField(max_length=100)
points = models.ManyToManyField(User, default=0)
I also have a form for Test, which is:
#forms.py
class TestForm(forms.ModelForm):
class Meta:
model = Test
fields = ('classes', 'name')
When I get to the actual form, the drop-down menu for 'classes' in TestForm merely comes up with 'Classes object' for the number of 'Classes' that I have in my DB. I want to change that so the form lists the names of the classes, which are stored in the 'Classes' model as 'classname'
Can anyone point me in the right direction please?
The easiest way to do it is to provide a string representation of your object, this would replace any where you access the class throughout your application
class Classes(models.Model):
classcode = models.CharField(max_length=15)
classname = models.TextField()
students = models.ManyToManyField(User)
def __str__(self):
return "{0}: {1}".format(self.classcode, self.classname)
From the docs
The __str__ (__unicode__ on Python 2) method of the model will be called to generate string representations of the objects for use in the field’s choices; to provide customized representations, subclass ModelChoiceField and override label_from_instance.

A 'related content' list with DetailView in Django

Based on an "Article" model, I'm trying to display a "related content" list in the template by filtering its model field named "category". This "category" field has a ManyToMany relationship to another model named "Category".
It's looks like a very simple task but I can't figure out how to achieve my purpose. By now, a list could be displayed but seems nothing was filtered out.
Below is my DetailView class with a "get_context_data()" method which can product a template tag for displaying a list. Apparently the "F()" class is not the solution.
class ArticleDetail(generic.DetailView):
model = Article
template_name = 'article/detail.html'
def get_context_data(self, **kwargs):
context = super(ArticleDetail, self).get_context_data(**kwargs)
context_related = Article.objects.filter(F('category')).distinct()
context['related'] = context_related
return context
Besides, I also tried to filter with arguments like "category" and "category__exact=F('category')" but still failed.
And here are the models (simplified for question):
class Article(models.Model):
title = models.CharField(max_length=100)
content_text = models.TextField()
category = models.ManyToManyField('Category', blank=True)
def __unicode__(self):
return self.title
class Category(models.Model):
title = models.CharField(max_length=100, unique=True)
def __unicode__(self):
return self.title
No, that's not what F() is for at all.
You don't explain exactly what you do want though. I presume you're looking for other articles in the same categories as the current article. That's easy enough:
Article.objects.filter(category__in=self.object.categories.all())

Reorder FK fields in Django, remain optional

I have a model (Application) tied to a foreign_key (Person) table. I was having trouble getting the Person-dropdown in the admin to sort by name instead of by key, and found this Reorder users in django auth as a solution. However, this made the fields mandatory and I can't figure out how to get them to stay optional.
app/models.py
class Person(models.Model):
Full_Name = models.CharField(max_length=200)
def __unicode__(self):
return self.Full_Name
class Application(models.Model):
Name = models.CharField(max_length=100)
Primary_Contact = models.ForeignKey(Person,blank=True,null=True,related_name='appprimarycontact')
def __unicode__(self):
return self.Name
admin.py
class OwnerAdminForm(forms.ModelForm):
Primary_Contact = forms.ModelChoiceField(queryset=Person.objects.order_by('Full_Name'),)
class Meta:
model = Application
class ApplicationAdmin(admin.ModelAdmin):
form = OwnerAdminForm
list_display = ('Name','Primary Contact')
Just add the required=False option on the form field
forms.ModelChoiceField(required=False, queryset=Person.objects.order_by('Full_Name'))
The thing is, if you override the default form widget that django's ModelForm would provide, you would have to explicitly specify required=False, since the default value is True

Categories