Django inline elements gives error for many-to-many relationship - python

In the admin I want to use inline elements. I want category to display
the items it is related to.
But I get this error:
Exception at /admin/store/category/7/
<class 'store.models.Item'> has no ForeignKey to
<class 'store.models.Category'>
It's true, of-course, since I chose to use Category to point to the
items it has.
But, how can I get the admin to list in-line all the items that a
given Category has?
How can I get around this error?
CONTEXT:
class Category:
items=models.ManyToManyField(Item,through='Categoryhasitem')'
class Categoryhasitem(models.Model):
category = models.ForeignKey(Category, db_column='category')
item = models.ForeignKey(Item, db_column='item')
class Item(models.Model):
id = models.AutoField(primary_key=True)
This is my admin.py file.
class ItemInline(admin.TabularInline):
model=Item
class CategoryAdmin(admin.ModelAdmin):
inlines=[ItemInline,]
class ItemAdmin(admin.ModelAdmin):
pass
admin.site.register(Category, CategoryAdmin)
admin.site.register(Item, ItemAdmin)

The syntax is slightly different to display many-to-many relations using an inline.
class ItemInline(admin.TabularInline):
model = Category.items.through
class CategoryAdmin(admin.ModelAdmin):
inlines = [
ItemInline,
]
exclude = ('items',)
See the django admin docs for working with many-to-many models for more details.

Related

Django Rest Framework Nested Different Serializer Saving Problem

I have Category and Product Models. I have created 2 serializers for each model. When i want to add a new product i send this json: {"name":"name","price":1,"category":{"id":1}} but django gives error and says that i need to specify category name too. I have already given id so why do i have to give category name too (category that has id 1 already exists. I am trying to add new product to this category )?. If i make name field of category not required django doesn't give error. But when i want to add new category it doesn't give error if i don't specify name field in json. I want django to give "name required" error when i try to add new category but i don't want it to give error when i try to add new product. If i make category read_only it doesn't update category_id of product when i want to update a product.
class Product(models.Model):
name=models.CharField(max_length=32)
price=models.FloatField()
category=models.ForeignKey("Category",on_delete=models.CASCADE)
class Category(models.Model):
name=models.CharField(max_length=32)
class CategorySerializer(ModelSerializer):
class Meta:
model=Category
fields="__all__"
class ProductSerializer(ModelSerializer):
class Meta:
model=Product
fields="__all__"
category=CategorySerializer()
I have same issue.
My solution is:
class CategorySerializer(ModelSerializer):
class Meta:
model=Category
fields="__all__"
class ProductSerializer(ModelSerializer):
class Meta:
model=Product
fields="__all__"
category = CategorySerializer(read_only=True)
category_id = PKR(queryset=Category.objects.all(),
source="category",write_only=True)
in this way:
when you want add or update use category_id field to use exist category
if you want read serializer return category with all fields :)

Django, Many-to-one relationship with Abstract entities

Say object contains multiple types of objects (Models) in an array, like a Page, that could contain a Post, Blog, Picture, in any quantity or order, where the user scrolls down and sees the following element and that depending on the page, is next element one of these types of elements. Thus a Page could contain:
A Post
A Post
A Picture
Or something pretty different such as:
A Picture
A Blog
A Picture
An element could be an abstract entity that has an attribute as a ForeignKey relating itself with Page, and its inheritance would gain access to that relationship:
class Page(models.Model):
...
class PageElement(models.Model):
page = models.ForeignKey(Page, verbose_name="Page", on_delete=CASCADE)
class Meta:
abstract = True
class Post(PageElement):
...
class Blog(PageElement):
...
class Picture(PageElement):
...
With this approach, you can serialize Page with a REST serializer, but you wouldn't have access to an pageElement_set, instead you would need to call post_set, blog_set, picture_set and loose the order of the objects.
By just adding a related_name key in the ForeignKey, we get an error:
pages.Picture.page: (fields.E305) Reverse query name for 'Picture.page' clashes with reverse query name for 'Post.page'.
HINT: Add or change a related_name argument to the definition for 'Picture.page' or 'Post.page'.
The question is: How do you implement such relationships in Django?
So that you can have an order set of PageElement instances, and be able to have the desired order.
Since you want to query multiple Models in order and you can see that your models are in Model is a PageElement relationship, then instead of inheriting from an abstract Model you need to have a OneToOneField with a common model:
class PageElement(models.Model):
POST = 'PO'
BLOG = 'BL'
PICTURE = 'PI'
ELEMENT_TYPE_CHOICES = [
(POST, 'Post'),
(BLOG, 'Blog'),
(PICTURE, 'Picture'),
]
element_type = models.CharField(
max_length=2,
choices=ELEMENT_TYPE_CHOICES,
default=POST,
)
# common fields
class Post():
page_element = models.OneToOneField(
PageElement,
on_delete=models.CASCADE,
related_name = "post"
)
class Blog():
page_element = models.OneToOneField(
PageElement,
on_delete=models.CASCADE,
related_name = "blog"
)
class Picture():
page_element = models.OneToOneField(
PageElement,
on_delete=models.CASCADE,
related_name = "picture"
)
You can inherit from a common abstract class that has the OneToOneField for ease if needed.

Django admin panel list_display show none even after fetching data

I am displaying data in Django admin panel for many to many relationship tables. I got None instead of a list of names.
I am using:
Python: 3.6
Django: 2.2
List_display for ManytoMany fields in Admin panel
I had also already asked a related question on this topic. That being said I changed my model since then (I also got not answers).
models:
class Assessment(models.Model):
name = models.CharField(max_length=255)
class Participant(models.Model):
user = models.OneToOneField(User,on_delete=models.CASCADE)
first_name = models.CharField(max_length=255,blank=True,null=True)
class Seminar(models.Model):
topic = models.CharField(max_length=255)
assessment = models.ManyToManyField(Assessment,blank=True)
participant = models.ManyToManyField(Participant,blank=True,through='SeminarParticipant',through_fields=('seminar','participant'))
class SeminarParticipant(models.Model):
seminar = models.ForeignKey(Seminar,blank=True,on_delete=models.CASCADE)
participant = models.ForeignKey(Participant,blank=True,on_delete=models.CASCADE)
request_time = models.PositiveIntegerField(default=0,validators=[MinValueValidator(0),])
is_survey_completed = models.BooleanField(default=False)
admin:
#admin.register(Seminar)
class SeminarAdmin(admin.ModelAdmin):
list_display = ('topic''assessment')
def assessment(self,obj):
return "\n".join([item for item in obj.assessment.all()])
I was expecting name of assessment in list_display of seminar admin but got assessments.Assessment.None in list_display of admin panel.
Snapshot of output:
Thank you very much for your help
assessment is the name of the field, which will be found before your method. Call the method something else and use that name in list_display.
class SeminarAdmin(admin.ModelAdmin):
list_display = ('topic', 'assessment_list')
def assessment_list(self, obj):
return "\n".join([item for item in obj.assessment.all()])
(Although note, assessment is an odd name for a field that contains many assessments; you should think about renaming the field itself.)

Django: how can I a create categories field/dropdown menu?

This is a very simple question, how can I create dropdown field in Django with only specific categories(something similar to the countries dropdown, but not with countries).
With the choice attribute of a Field if it is for fixed values. Or with a ForeignKey field if the Categories should be created dynamicly.
For the ForeignKey field you would do the following:
from django.db import models
class Category(models.Model):
name = models.Charfield(max_length=255)
# ...
def __str__(self):
return self.name
class Item(models.Model):
category = models.ForeignKey(Category)
# ...
Django's most powerful feature is to offer you direct forms.
It's a broad question but you want to define a model that can be paired with a form that you can put in a template.
Take a look here: https://docs.djangoproject.com/en/1.8/topics/forms/ and here:
Django options field with categories and here Creating a dynamic choice field

Storing list of objects in Django model

Is there a way in Django to have multiple objects stored and manageable (in Django admin) inside another object?
Example, I have two models: Items and RMA. The RMA may have multiple Items inside of it. Each Item is unique in the sense that it is an inventoried part, so I can't just reference the same item multiple times with foreignKey (though maybe I'm misunderstanding its use/implementation).
So for now, I have an Item model:
class Item(models.Model):
serial_number = models.CharField(max_length=200)
name = models.CharField(max_length=200)
part_number = models.CharField(max_length=200)
location = models.CharField(max_length=200)
def __unicode__(self):
return self.name
And an RMA model:
class RMA(models.Model):
number = models.AutoField(primary_key=True)
items = ?????
Ultimately I'd like to be able to maintain use of the Django admin functionality to add/remove items from an RMA if necessary, so I've been staying away from serializing a list and then deserializing on display. Any help would be much appreciated.
You're modeling a has-many relationship.
This would be modeled with a Foreign Key on Item to RMA:
class Item(models.Model):
serial_number = models.CharField(max_length=200)
name = models.CharField(max_length=200)
part_number = models.CharField(max_length=200)
location = models.CharField(max_length=200)
rma = models.ForeignKey(RMA)
def __unicode__(self):
return self.name
To make it accessible in the admin of RMA you need djangos InlineAdmin functionality.
You can find examples in the django tutorial part2.
You are effectively describing a Many-To-One relation and to do this you are going to have to add the ForeignKey reference to the Item model, not to the RMA model.
You can also add a related_name to give the RMA model an attribute that you can call.
For example:
class Item(models.Model):
rma = models.ForeignKey(RMA,related_name="items")
serial_number = models.CharField(max_length=200)
# etc...
To manage the creation of these, you'll need an InlineModelAdmin form, so your admin.py file will need to look like this:
from django.contrib import admin
class ItemInline(admin.TabularInline):
model = Item
class RMAAdmin(admin.ModelAdmin):
inlines = [
ItemInline,
]

Categories

Resources