Multiple Django Admin Arguments with Extensions - python

Is there a way to use multiple Django extensions in the admin.site.register() inside admin.py? I'm using "simple-history" and "import-export" extensions, but I can only have one of them in the admin.site.register().
Example: I have a model named, "Cars", that is using the "simple-history" extension so I need admin.site.register(Cars, SimpleHistoryAdmin), as their documentation says it should. I want to use the import/export extension as well to the same "Cars" model, but the admin.site.register() doesn't take multiple arguments for me to add it.
models.py
class Cars(models.Model):
Year = models.CharField(max_length=30)
Make = models.CharField(max_length=30)
Model = models.CharField(max_length=30)
history = HistoricalRecords()
class Meta:
verbose_name_plural = "Car Table"
def __str__(self):
return self.Make
admin.py
class CarResource(resources.ModelResource):
class Meta:
model = Cars
fields = ('id','Year', 'Make', 'Model',)
class CarAdmin(ImportExportModelAdmin):
resource_class = CarResource
pass
#I want to use the import/export extension (code above), along with simple-history
admin.site.register(Cars, CarAdmin)
admin.site.register(Cars, SimpleHistoryAdmin)
I've tried using a proxy and inlines, but the proxy makes a new model which I don't want and when using inlines I get an error saying that it requires a foreign key, but I'm not trying to get the model objects from a different model. Naming them the same model doesn't work because the model is already registered. Any help is much appreciated!

In python, class can have more than one parent. Just inherit from 2 parents at once. But both ImportExportModelAdmin and SimpleHistoryAdmin are inheriting from ModelAdmin, that's not good. There is also ImportExportMixin, we can use it instead of ImportExportModelAdmin, so there will be only one reference to ModelAdmin.
class CarResource(resources.ModelResource):
class Meta:
model = Cars
fields = ('id','Year', 'Make', 'Model',)
class CarAdmin(ImportExportMixin, SimpleHistoryAdmin):
resource_class = CarResource
pass
#I want to use the import/export extension (code above), along with simple-history
admin.site.register(Cars, CarAdmin)

Related

Django Rest Framework: Get field name from model definition

Within the Django Rest framework documentation it is suggested to declare the "field" list explicitly to avoid providing the data of new columns just by adding them to the model which may contain sensitive information.
The field list is an array of strings, containing the field ids. To avoid declaring field ids, which actually do not exist in the model (e.g. typos or changed models) I tried to declare the list using object references - but always end up with "DeferredAttribute: object has no attribute ".
I have read something that meta information is not available in objects and that you could solve that by defininig your own Meta class using Object._meta.get_fields() and store it in the class, but I thought there might be a simpler/more elegant way (and I do now know, how, in detail ;-)).
Example:
class Samples(models.Model):
# Meta data, primarily used in AdminSite.
class Meta:
verbose_name = _('Samples')
verbose_name_plural = _('Samples')
samples_boolfield = models.BooleanField
samples_textfield = models.CharField(max_length=2000, blank=True)
views.py:
class SamplesView(viewsets.ModelViewSet):
serializer_class = SamplesSerializer
queryset = Samples.objects.all()
serializers.py:
Version 1, which does not show any errors in pyCharm or makemigrations, but calling the API reults in "TypeError at /api/samples/: argument of type 'DeferredAttribute' is not iterable":
class SamplesSerializer(serializers.ModelSerializer):
class Meta:
model = Samples
fields = (
'id',
Samples.samples_boolfield,
Samples.samples_textfield,
)
Version 2, which does not show any errors in pyCharm, but makemigrations fails with "DeferredAttribute: object has no attribute name":
class SamplesSerializer(serializers.ModelSerializer):
class Meta:
model = Samples
fields = (
'id',
Samples.samples_boolfield.__name__,
Samples.samples_textfield.__name__,
)
Version 3, which does not show any errors in pyCharm, but makemigrations fails with "DeferredAttribute: object has no attribute get_attname":
class SamplesSerializer(serializers.ModelSerializer):
class Meta:
model = Samples
fields = (
'id',
Samples.samples_boolfield.get_attname(),
Samples.samples_textfield.get_attname(),
)
Is there a way to declare the field list using object references (so that it fails e.g. in pyCharm/during compilation)?
Thank you for your feedback.
Regards,
HerrB92

Expose multiple similar database fields as enumerable collection

I have a Django (1.8) Model for an underlying database table that has multiple columns that are logically a fixed-size array. For example:
from django.db import models
class Widget(models.Model):
# ...
description_1 = models.CharField(max_length=255)
description_2 = models.CharField(max_length=255)
description_3 = models.CharField(max_length=255)
# ...
I would like to be able to access these columns as if they were a collection on the model instance, e.g.:
instance = Widget.objects.get(...)
for description in instance.descriptions:
# do something with each description
My primary motivation is that I am exposing this model via Django Rest Framework (DRF), and would like the API clients to be able to easily enumerate the descriptions associated with the model. As it stands, the clients have to reference each logical 'index' manually, which makes the code repetitive.
My DRF serializer code is currently like this:
class WidgetSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Widget
There are a fixed number of descriptions for each Widget, and their ordering is important.
Is there a clean way to expose these fields as a collection on the Model object?
It really was as easy as adding a method to the Model class that returns the fields as a sequence, and then (for API clients), manually specifying that new method as a field to serialize.
So the Model definition becomes:
from django.db import models
class Widget(models.Model):
description_1 = models.CharField(max_length=255)
description_2 = models.CharField(max_length=255)
description_3 = models.CharField(max_length=255)
def descriptions(self):
return self.description_1, self.description_2, self.description_3
And the DRF serializer is updated like:
class WidgetSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Widget
fields = ('url', 'descriptions',)
This causes the API to return a JSON array for descriptions and omit all of the individual description_x fields.

How can i remove extra "s" from django admin panel?

I am really very much irritated by the extra "s" added after my class name in django admin eg class 'About' in my model.py becomes 'Abouts' in admin section. And i want it not to add extra 's'. Here is my model.py file-
class About(models.Model):
about_desc = models.TextField(max_length=5000)
def __unicode__(self): # __str__ on Python 3
return str(self.about_desc)
Please anybody suggest me how django can solve my problem.
You can add another class called Meta in your model to specify plural display name. For example, if the model's name is Category, the admin displays Categorys, but by adding the Meta class, we can change it to Categories.
I have changed your code to fix the issue:
class About(models.Model):
about_desc = models.TextField(max_length=5000)
def __unicode__(self): # __str__ on Python 3
return str(self.about_desc)
class Meta:
verbose_name_plural = "about"
For more Meta options, refer to https://docs.djangoproject.com/en/1.8/ref/models/options/
Take a look at the Model Meta in the django documentation.
Within a Model you can add class Meta this allows additional options for your model which handles things like singular and plural naming.
This can be used in the following way (in english we do not have sheeps) so verbose_name_plural can be used to override djangos attempt at pluralising words:
class Sheep(model.Model):
class Meta:
verbose_name_plural = 'Sheep'
inside model.py or inside your customized model file add class meta within a Model Class.
If not mentioned then a extra 's' will be added at the end of Model Class Name which will be visible in Django Admin Page.
class TestRoles(model.Model):
class Meta: verbose_name_plural = 'TestRoles'

Django: "UserProfileRole.userProfile" must be a "UserProfile" instance

I'm having a strange riddle to solve:
I extended my django-1.4 user-objects with a UserProfile, as described at https://docs.djangoproject.com/en/dev/topics/auth/ and wanted to implement project-specific roles. So my models look like the following:
class UserProfile(models.Model):
user = models.ForeignKey(User, unique=True)
projects = models.ManyToManyField(Project, through='UserProjectRole')
[...]
class UserProjectRole(models.Model):
userProfile = models.ForeignKey(UserProfile)
project = models.ForeignKey(Project)
group = models.ForeignKey(Group)
[...]
I needed to pass a css-class, so I created a model-form for UserProjectRole and implemented the userProfile-Field with a widget:
class ProjectRoleForm(forms.ModelForm):
userProfile = forms.ModelMultipleChoiceField(label='Users',
queryset=UserProfile.objects.all(),
widget=forms.SelectMultiple(attrs={'class': 'select-multiple'}))
class Meta:
model = UserProjectRole
The form is presented correctly, however, it's crashing during save-process with the following error
Cannot assign "[<UserProfile: MyUser>]": "UserProjectRole.userProfile" must be a "UserProfile" instance.
Does anyone have an idea?
My guess is it's because you are using a forms.SelectMultiple widget. Which gives you a list of UserProfile instances ( [<UserProfile: MyUser>] ) and not a single UserProfile instance which is of course required to set on a ForeignKey field (UserProjectRole.userProfile). Thus I suggest to try using a forms.Select widget instead.

How can I update only certain fields in a Django model form?

I have a model form that I use to update a model.
class Turtle(models.Model):
name = models.CharField(max_length=50, blank=False)
description = models.TextField(blank=True)
class TurtleForm(forms.ModelForm):
class Meta:
model = Turtle
Sometimes I don't need to update the entire model, but only want to update one of the fields. So when I POST the form only has information for the description. When I do that the model never saves because it thinks that the name is being blanked out while my intent is that the name not change and just be used from the model.
turtle_form = TurtleForm(request.POST, instance=object)
if turtle_form.is_valid():
turtle_form.save()
Is there any way to make this happen? Thanks!
Only use specified fields:
class FirstModelForm(forms.ModelForm):
class Meta:
model = TheModel
fields = ('title',)
def clean_title(self....
See http://docs.djangoproject.com/en/dev/topics/forms/modelforms/#controlling-which-fields-are-used-with-fields-and-exclude
It is common to use different ModelForms for a model in different views, when you need different features. So creating another form for the model that uses the same behaviour (say clean_<fieldname> methods etc.) use:
class SecondModelForm(FirstModelForm):
class Meta:
model = TheModel
fields = ('title', 'description')
If you don't want to update a field, remove it from the form via the Meta exclude tuple:
class Meta:
exclude = ('title',)

Categories

Resources