Django: ManyToMany Inline Admin view error - django

Here are the model definitions:
class ItemBrand(models.Model):
name = models.CharField(max_length = 30, unique = True)
def __unicode__(self):
return self.name
class WantedItem(models.Model):
name = models.CharField(max_length = 120)
description = models.TextField()
created = models.DateTimeField(auto_now = False, auto_now_add = True)
expires = models.DateTimeField(auto_now = False, auto_now_add = False)
type = models.ForeignKey(ItemType, related_name = "type wanted")
GENDER_CHOICES = (
(1, 'Male'),
(2, 'Female')
)
gender = models.IntegerField(choices = GENDER_CHOICES)
brands = models.ManyToManyField(ItemBrand, related_name = "wantedbrands", symmetrical = False)
colors = models.ManyToManyField(ItemColor)
sizes = models.ManyToManyField(ItemSize)
creator = models.ForeignKey(User, related_name = "wishlist creator")
def __unicode__(self):
return self.name
Here is the AdminModel code:
class BrandsInline(admin.TabularInline):
model = WantedItem.brands.through
class WantedItemAdmin(admin.ModelAdmin):
list_display = ('name', 'created', 'expires', 'type', 'gender', 'creator')
search_fields = ('name', 'description')
list_filter = ('created', 'brands',)
ordering = ('-created',)
inlines = [
BrandsInline,
]
exclude = ('brands',)
This is pulled basically right from the Django docs, and here's the error I am getting:
'ReverseManyRelatedObjectsDescriptor' object has no attribute 'through'
I am at a total loss... any ideas? Even if I literally create a linker table and set the "through" attribute in the Model I get the same error.
Broken?

You need to upgrade Django to the trunk.
Using inlines with many-to-many fields is new in the django development version (see docs).
Using a simplified version of your models, I get the same error as you for Django 1.1.1, but it works on the trunk (revision 11785).
As an aside, you don't need to specify symmetrical = False on your ItemBrand ManyToMany field. The symmetrical option is only intended for recursive relationships eg User <-> User.
You may want to have a look at the documentation on related names, and think about renaming them to something more logical as well. If creator is a User object, and want to get the set of wishlists they have created, the default when related_name is not specified is
creator.wishlist_set.all()
with your choice for related_name (when you add the underscore), this changes to
creator.wishlist_creator.all()
but I would recommend related_name='wishlists', in which case you would use
creator.wishlists.all()

While it may not be the cause of your error, spaces in the related_name attribute are invalid so I'd try removing those first.
"type wanted" => "type_wanted"
"wishlist creator" => "wishlist_creator"

Related

Django Model Serializer manyToMany relationship

I have problem with Django 4.1.2 (Python 3.8.9).
I have 2 entities: Idea and IdeaTheme, which have manyToMany relationship.
class Idea(models.Model):
short_name = models.CharField(max_length=70)
description = models.TextField(null=True,
blank=True,
default='')
class State(models.IntegerChoices):
CREATED = 0, _("Создано")
TEAM_SEARCHING = 1, _("Поиск команды")
IN_PROCESS = 2, _("Реализация")
READY = 3, _("Готово")
state = models.IntegerField(choices=State.choices,
default=State.CREATED)
wanted_skills = models.ManyToManyField(to=UserSkill)
themes = models.ManyToManyField(to=IdeaTheme,
null=True,
blank=True)
class IdeaTheme(models.Model):
name = models.CharField(max_length=70,
verbose_name="Название")
background_photo = models.ImageField(blank=True,
null=True,
verbose_name="Изображение для фронта")
Also I have ModelSerializer
class IdeaSerializer(serializers.ModelSerializer):
class Meta:
model = Idea
fields = '__all__'
depth = 1
extra_kwargs = {
'state': {
'read_only': True
},
'pk': {
'read_only': True
}
}
And when I using CreateAPIView in order to create Idea I face the problem, that I must provide IdeaTheme pks. But in the model there are Null and Blank option and I want to create idea without IdeaThemes.
I tried to specify IdeaTheme serializer inside IdeaSerializer like this, but Django still require not empty array of IdeaTheme.
themes = IdeaThemeSerializer(many=True, required=False)
Could someone help me, please, who already has experience using built-in serializers?

Display choicefield in admin as input field

I have a database of maybe 100 users that have each 5-10k products linked to them. In the admin panel loading that page is really slow because of the many products. So what I want to do is replacing it with a regex or at least a number input field that does not preload all the products:
models:
class Store(models.Model):
name = models.CharField("name", max_length = 128)
user = models.OneToOneField(User, on_delete = models.CASCADE, )
testproduct = models.Foreignkey(Product, on_delete = models.CASCADE, null = True, blank = True)
class Product(models.Model):
data = models.JSONField()
number = models.PositiveIntegerField()
store = models.ForeignKey(Store, on_delete = models.CASCADE)
admin:
class StoreAdmin(admin.ModelAdmin):
list_display = ["name", ...]
raw_id_fields = ["testproduct", ...]
This way I get an id input field on the admin page:
Is there any way I can make it a regex field, so I can search through the data attribute of my products as well as the number attribute?
I think, best way to achieve your goal is to add extra field to your model admin form and override save method for it, try this:
#admin.py
from django import forms
class StoreAdminModelForm(forms.ModelForm):
regex_field = forms.CharField()
def save(self, commit=True):
product_regex = self.cleaned_data.get('regex_field', None)
instance = super(StoreAdminModelForm, self).save(commit=commit)
# put some more regex validations here
if len(product_regex) > 0:
product = Product.objects.filter(data__regex=product_regex).first()
if product:
instance.testproduct = product
else:
raise forms.ValidationError('Product with data satisfying regex was not found!')
if commit:
instance.save()
return instance
class Meta:
model = Store
fields = '__all__'
class StoreAdmin(admin.ModelAdmin):
form = StoreAdminModelForm
raw_id_fields = ["testproduct", ]
fields = ('name ', 'user', 'testproduct', 'regex_field')
readonly_fields = ('user', )
So, the result - you will have special field for regex expression and you will try to get testproduct based on that field (without touching raw_id_field)

Display admin TabularInline in list_display

I have two models, which are linked reverse by foreign key from my admin point of view:
class Product(models.Model):
name = models.CharField("name", max_length = 128)
class Store(models.Model):
store_id = models.PositiveIntegerField(unique = True)
product = models.ForeignKey(Product, on_delete = models.CASCADE, null = True, blank = True)
And I have an admin view where I want to display the store_id of each product it is available in list_display.
I ask because I found TabularInline - my apporach:
class StoreInline(admin.TabularInline):
model = Store
readonly_fields = ['store_id', "product"]
#admin.register(Product)
class ProductAdmin(admin.ModelAdmin):
list_display = ["name",]
inlines = [StoreInline,]
But how would i be able to display the store_id value in list_displays using the Inlines method?
--- workaround (this is only a motviation for my question above), not a solution ---
I worked around by creating a custom method but, I feel like from reading (1, 2, 3) that I have solved it "by hand" and not using a path Django already has. This works:
#admin.register(Product)
class ProductAdmin(admin.ModelAdmin):
list_display = ["name", "get_stores"]
def get_stores(self, obj):
return [s.store_id for s in Store.objects.filter(product = obj)]

Rest Framework Django - Disable field to accept null values

Rest Framework Django - Disable field to accept null values
How can I configure for the serialized Model to accept blank fields?
Warning
{"Operacao": ["This field can not be blank."]}
Model
class SEF(models.Model):
operacao = models.CharField(max_length=10, null=True)
documento = models.CharField(max_length=50, null=True)
user = models.ForeignKey(User)
Serializer
class SEFCreateSerializer(serializers.ModelSerializer):
class Meta:
model = SEF
fields = ('operacao', 'documento', 'user')
View
sef_create = SEFCreateSerializer(data=data, many=True)
if sef_create.is_valid():
sef_create.save()
salvo = HTTP_200_OK
else:
salvo = sef_create.errors
Include allow_blank=True in the field definition as this:
operacao = serializers.CharField(allow_blank=True, allow_null=True)
class SEFCreateSerializer(ModelSerializer):
class Meta:
model = SEF
fields = ('operacao', 'documento', 'user')
extra_kwargs = {'operacao': {'required': False}}
You can set default value like
operacao = models.CharField(max_length=10, default=0)
if you specify a field in model like this it will take default value as 0 if nothing is present.
or in serializer
operacao = serializers.CharField(allow_null = True)

how could I use Model._meta.get.fields() to read all fields in my model

I want to display some fields and I know I could do it by as follows:
In models.py:
class Person(models.Model):
person_id = models.UUIDField(default=uuid.uuid4, primary_key = True)
date_registered = models.DateField(auto_now_add=True)
first_name = models.CharField(max_length = 50)
last_name = models.CharField(max_length = 100)
date_of_birth = models.DateField()
email = models.EmailField()
In my admin.py:
class AuthorAdmin(admin.ModelAdmin):
list_display = ('last_name', 'first_name', 'last_name', 'date_of_birth' )
fields = [('first_name' ,'last_name'), 'date_of_birth']
pass
admin.site.register(Author, AuthorAdmin)
Unfortunately, my table has many fields and I do not want to write them individually. I found that ._meta.get.fields() could read all fields. However, I can not get it correct. Using it as follows in my admin.py:
admin.site.register(PersonLogin)
admin.site.register(LoginHistory)
class PersonAdmin(admin.ModelAdmin):
list_display = [field.name for field in Person._meta.get_fields() if not field.primary_key]
readonly_fields = ('person_id',)
pass
admin.site.register(Person, PersonAdmin)
it says that _meta is undefined variable.
Latest Django in use.
Thank you in advance.
PG
_meta being unavailable means Django didn't set up its environment yet. You can set it up by adding:
import django
django.setup()
at the top, but this is somewhat dirty. See if you can get away with moving the list comprehension to the __init__:
class PersonAdmin(admin.ModelAdmin):
def __init__(self, model, admin_site):
self.list_display = [
field.name for field in Person._meta.get_fields()
if not field.primary_key
]
super().__init__(model, admin_site)
EDIT: To accommodate the Eclipse introspection errors you can use getattr to explicitly tell it that it's a runtime thing:
self.list_display = [
field.name for field in getattr(Person, '_meta').get_fields()
if not field.primary_key
]