I get this error when trying to create a custom Form on the Admin view, I don't see any solution on stackoverflow (yes similar problems) so I think it's a good idea to post it:
My Models.py:
class Webhook(models.Model):
url = models.CharField('URL', max_length = 60, unique = True)
description = models.CharField('Descripcion', max_length = 255)
enabled = models.BooleanField('Enabled', default=True)
event = models.CharField('Evento', max_length=1, choices=Events.EVENTS_CHOICES)
My Forms:
class WebhookForm(forms.ModelForm):
class Meta:
model = Webhook
fields = '__all__'
def save(self, commit=True):
print('saveeeeeee')
webhook = super().save(commit=False)
webhook.code = webhook.id
# Get token
response_token = TOKEN.get()
if response_token['success']:
# Create Webhook
url = 'https://sandbox.bind.com.ar/v1/webhooks'
headers = {
'Content-type': 'application/json',
'Authorization': 'JWT ' + response_token['token']
}
data = {
'url': webhook.url, # Debera responder status_code == 200
'description': webhook.description,
'code': webhook.id,
'enabled': webhook.enabled,
'events': webhook.event
}
data_json = json.dumps(data)
response = requests.put(url, data= data_json, headers = headers)
response_json = response.json()
# Result
result = {}
if response.status_code == 409:
result['success'] = False
result['details'] = response_json
else:
result['success'] = True
result['data'] = response_json
# If ok, Save
if commit & result['success']:
webhook.save()
return result['success']
My Admin.py
class WebhookAdmin(forms.ModelForm): # Only to override a form in admin
class Meta:
model = WebhookForm
fields = '__all__'
# Style to add a new User
add_form = WebhookForm
add_fieldsets = (
(None, {
'classes': ('wide',),
'fields': ('url', 'description', 'code', 'enabled', 'events',)}
),
)
# Style to edit a new User
form = WebhookForm
fieldsets = (
(None, {
'classes': ('wide',),
'fields': ('url', 'description', 'code', 'enabled', 'events',)}
),
)
admin.site.register(Webhook, WebhookAdmin)
And I get this error when I try to do python manage.py makemigrations:
AttributeError: 'ModelFormOptions' object has no attribute 'private_fields'
You have subclassed the wrong thing. The admin class needs to inherit from admin.ModelAdmin, not forms.ModelForm.
ModelAdmin classes don't have an inner Meta class. You need to remove that class altogether.
The Attribute error was because I was trying to assign a Form into the class Meta, and it needs a Model:
class Meta:
model = WebhookForm
fields = '__all__'
Related
Here is my code where I generate a PDF file, (like an invoice), but I can't retrieve the fields from the admin.TabularInline.
In my model.py I have to class: Sale and SaleItems,and in admin.py I have :
class SaleItemsInLine(admin.TabularInline):
model = SaleItems
extra = 1
readonly_fields = ('total', )
formfield_overrides = {
models.CharField: {'widget': TextInput(attrs={'size':'100%'})},
}
#admin.register(Sale)
class SaleAdmin(DjangoObjectActions, admin.ModelAdmin):
fields = (
('order', 'created', 'due_date'),
('profile'),
('pay_method', 'tax_card'),
('therapist' ,'activity',),
('notes'),
('totals'),
('pay', 'payOne','payTwo'),
('subtotal', 'status'),
)
readonly_fields = ('created', 'totals', 'order','subtotal', 'status', 'tax_card')
search_fields = ['profile__name', 'profile__cpf',
'profile__phone', 'activity', ]
autocomplete_fields = ('profile',)
list_display = ('profile', 'order', 'created', 'due_date', 'totals', 'status')
inlines = [SaleItemsInLine]
formfield_overrides = {
models.CharField: {'widget': TextInput(attrs={'size':'30'})},
models.TextField: {'widget': Textarea(attrs={'rows':4, 'cols':100})},
}
def generate_pdf(self, request, obj):
html_string = render_to_string('sales/invoice.html', {'obj': obj})
html = HTML(string=html_string, base_url=request.build_absolute_uri())
html.write_pdf(target='/tmp/{}.pdf'.format(obj), presentational_hints=True);
fs = FileSystemStorage('/tmp')
with fs.open('{}.pdf'.format(obj)) as pdf:
response = HttpResponse(pdf, content_type='application/pdf')
response['Content-Disposition'] = 'filename="{}.pdf"'.format(obj)
return response
return response
I get fields from Sale with {{ obj.name }}, {{ obj.created}}, etc...
How I get the fields from SaleItems(TabulaInline) ???
I found a solution making a query inside the generate_pdf and passing as a new context:
def generate_pdf(self, request, obj):
qs = SaleItems.objects.filter(sale_id=obj.pk)
html_string = render_to_string('sales/invoice.html', {'obj': obj, 'qs': qs })
...
I'm creating a comment api but when i run the server give this error:
FieldError at /
Related Field got invalid lookup: is_null
i don't know how to fix it. i'm creating a nested comment api. this is my code:
#serializer
class CommentSerializer(serializers.ModelSerializer):
loadParent = serializers.SerializerMethodField("loadPrentData")
def loadPrentData(self, comment):
comments = Comment.objects.filter(parent=comment)
comments_ser = CommentSerializer(comments, many=True).data
return comments_ser
class Meta:
model = Comment
fields = ['id', 'user', 'product', 'parent', 'body', 'created', 'loadParent']
class ProductSerializer(serializers.ModelSerializer):
comments = serializers.SerializerMethodField("loadProductComments")
def loadProductComments(self, _product):
_comments = Comment.objects.filter(product=_product, parent__is_null=True)
_comments_ser = CommentSerializer(_comments, many=True, read_only=True).data
return _comments_ser
class Meta:
model = Product
fields = ['id', 'category', 'name', 'slug', 'image_1',
'image_2', 'image_3', 'image_4', 'image_5',
'description', 'price', 'available', 'created', 'updated', 'comments']
lookup_field = 'slug'
extra_kwargs = {
'url': {'lookup_field': 'slug'}
}
#views:
#api_view()
def AddComent(request, parent_id=None):
parent = request.data.get("parent_id")
serializer = CommentSerializer(data=request.data)
if serializer.is_valid():
if parent is not None:
comment = Comment.objects.create(user=request.user, product=serializer.validated_data['product'],
parent_id=serializer.validated_data['parent'],
body=serializer.validated_data['body'])
else:
comment = Comment.objects.create(user=request.user, product=serializer.validated_data['product'],
body=serializer.validated_data['body'])
comments_ser = CommentSerializer(comment,many=False, read_only=True).data
return Response(comments_ser, status=status.HTTP_200_OK)
return Response(status=status.HTTP_400_BAD_REQUEST)
Your line
_comments = Comment.objects.filter(product=_product, parent__is_null=True)
should be
_comments = Comment.objects.filter(product=_product, parent__isnull=True)
I am newer in Django rest api. My code is bellow:
class PatientViewSet(viewsets.ModelViewSet):
queryset = Patient.objects.all()
serializer_class = PatientSerializer
filter_backends = (DjangoFilterBackend, filters.OrderingFilter)
filterset_fields = ['id', 'email', 'mobile', 'status', 'type', 'gender']
ordering_fields = ['id', 'name']
def get_queryset(self):
queryset = Patient.objects.all()
status = self.request.query_params.get('status')
name = self.request.query_params.get('name')
if not status:
queryset = queryset.exclude(status="DELETE")
if name:
queryset = queryset.filter(name__icontains=name)
return queryset
def retrieve(self, request, pk=None):
queryset = Patient.objects.all()
patient = get_object_or_404(queryset, pk=pk)
serializer = PatientSerializer(patient)
summary = dict()
summary['payment'] = list(PatientPayment.objects.filter(patient_id=pk).aggregate(Sum('amount')).values())[0]
summary['appointment'] = DoctorAppointment.objects.filter(patient_id=pk).count()
d_appoint = DoctorAppointment.objects.filter(patient__id=pk).last()
appoint_data = DoctorAppointmentSerializer(d_appoint)
summary['last_appointment'] = appoint_data
content = {"code": 20000, "data": serializer.data, "summary": summary}
return Response(content)
Here url is:
http://127.0.0.1:8000/api/patients/2/
When I run in postman it getting the error bellow:
TypeError at /api/patients/2/
Object of type 'DoctorAppointmentSerializer' is not JSON serializable
Here problem with the code snippet:
d_appoint = DoctorAppointment.objects.filter(patient__id=pk).last()
appoint_data = DoctorAppointmentSerializer(d_appoint)
My question is how can I getting my result?
DoctorAppointmentSerializer Class:
class DoctorAppointmentSerializer(serializers.HyperlinkedModelSerializer):
patient = PatientSerializer(read_only=True)
patient_id = serializers.IntegerField()
doctor = DoctorSerializer(read_only=True)
doctor_id = serializers.IntegerField()
doc_image = Base64ImageField(
allow_null=True, max_length=None, use_url=True, required=False
)
doc_file = Base64ImageField(
allow_null=True, max_length=None, use_url=True, required=False
)
class Meta:
model = DoctorAppointment
fields = ['id', 'name', 'mobile', 'problem', 'age', 'gender', 'description', 'doctor', 'doctor_id', 'patient',
'patient_id', 'advice', 'doc_image', 'doc_file', 'created_at']
You have to call the .data property of DoctorAppointmentSerializer class
appoint_data = DoctorAppointmentSerializer(d_appoint).data
^^^^^^
When executing my Flask application I get the following warnings:
C:\Python27\lib\site-packages\flask_admin\model\base.py:1324: UserWarning: Fields missing from ruleset: password
warnings.warn(text)
C:\Python27\lib\site-packages\flask_admin\model\base.py:1324: UserWarning: Fields missing from ruleset: new_password
warnings.warn(text)
* Restarting with stat
C:\Python27\lib\site-packages\flask_admin\model\base.py:1324: UserWarning: Fields missing from ruleset: password
warnings.warn(text)
C:\Python27\lib\site-packages\flask_admin\model\base.py:1324: UserWarning: Fields missing from ruleset: new_password
warnings.warn(text)
I've normally used form_excluded_columns to remove unwanted fields from my form, but this time I have a hard time to get rid of those errors.
Here's my view:
class AdministratorView(sqla.ModelView):
page_size = 10
column_searchable_list = (
'username',
'description'
)
column_list = (
'username',
'apikey',
'description',
'active'
)
column_exclude_list = list = (
'apikey',
'source'
)
form_excluded_columns = (
'source',
'photos'
)
column_labels = {
'apikey': 'API Key'
}
form_widget_args = {
'apikey':{
'readonly':True
}
}
form_create_rules = (
rules.FieldSet(('username', 'password', 'description'), 'Personal'),
rules.FieldSet(('roles', 'apikey', 'active'), 'Permission'),
)
form_edit_rules = (
rules.FieldSet(('username', 'description'), 'Personal'),
rules.FieldSet(('roles', 'apikey', 'active'), 'Permission'),
rules.Header('Reset password'),
rules.Field('new_password')
)
def on_model_change(self, form, model, is_created):
if is_created is False:
if form.new_password.data:
model.password = generate_password_hash(form.new_password.data)
def scaffold_form(self):
form_class = super(AdministratorView, self).scaffold_form()
form_class.password = fields.PasswordField('Password', [validators.Required()])
form_class.new_password = fields.PasswordField('New Password')
return form_class
def is_accessible(self):
if login.current_user.is_authenticated:
return login.current_user.has_role('admin')
The purpose of this view is to have a single, required Password-field on the create form and a optional "New password"-field on the edit-form. I understand that the warnings arise when I don't include password/new_password in form_create_rules and form_edit_rules, but adding those fields to form_excluded_columns doesn't fix it.
Any tips on how I can get rid of the warnings?
Edit:
I suppose I should rather use get_create_form and get_edit_form instead of only scaffold_form. One benefit is that this makes it easier to override each form separately. Can I simplify this further? Should I do requirement validation like this or add nullable=False to the database schema (SQLAlchemy)?
class AdministratorView(sqla.ModelView):
page_size = 10
column_searchable_list = (
'username',
'description'
)
column_list = (
'username',
'apikey',
'description',
'active'
)
column_exclude_list = list = (
'apikey',
'source'
)
form_excluded_columns = (
'source',
'photos'
)
column_labels = {
'apikey': 'API Key'
}
form_widget_args = {
'apikey':{
'readonly':True
}
}
form_create_rules = (
rules.FieldSet(('username', 'password', 'description'), 'Personal'),
rules.FieldSet(('roles', 'apikey', 'active'), 'Permission'),
)
form_edit_rules = (
rules.FieldSet(('username', 'description'), 'Personal'),
rules.FieldSet(('roles', 'apikey', 'active'), 'Permission'),
rules.Header('Reset password'),
rules.Field('new_password')
)
def get_create_form(self):
form = self.scaffold_form()
form.username = fields.StringField('Username', [validators.Required()])
form.password = fields.PasswordField('Password', [validators.Required()])
return form
def get_edit_form(self):
form = self.scaffold_form()
delattr(form, 'password')
form.new_password = fields.PasswordField('New Password')
return form
def on_model_change(self, form, model, is_created):
if is_created is False:
if form.new_password.data:
model.password = generate_password_hash(form.new_password.data)
def is_accessible(self):
if login.current_user.is_authenticated:
return login.current_user.has_role('admin')
Perhaps this will help: How can I avoid Flask-Admin 2.1 warning "UserWarning: Fields missing from ruleset"?
Here's the relevant code from that answer:
import warnings
with warnings.catch_warnings():
warnings.filterwarnings('ignore', 'Fields missing from ruleset', UserWarning)
admin.add_view(UserView())
Hi I am creating an model admin with dynamic inline's.
class InlineProfile(admin.TabularInline):
model = Profile
# max_num = 1
class InlineProfileOne(admin.TabularInline):
model = TableOne
# max_num = 1
class InlineProfileTwo(admin.TabularInline):
model = TableTwo
# max_num = 1
class UserDisplay(admin.ModelAdmin):
inlines = [InlineProfile]
def get_inline_instances(self, request, obj=None):
up=UserProfile.objects.get(pk=obj.id)
if (up.job_type.job_type==1):
self.inlines.append(InlineProfileOne)
elif (up.job_type.job_type==2):
self.inlines.append(InlineProfileTwo)
return obj and super(UserDisplay, self).get_inline_instances(request, obj) or []
# def get_formsets(self, request, obj):
# print obj
# for inline in self.get_inline_instances(request, obj):
# yield inline.get_formset(request, obj)
list_display = [f.name for f in LCUser._meta.fields]
field_set = list(list_display)
field_set.remove('id')
field_set.remove('api_key')
field_set.remove('api_secret')
readonly_fields=['last_login_ip','last_login_timestamp','created_at','updated_at']
fieldsets = (
(None, {
'fields': field_set,
}),
('Advanced options', {
'classes': ('collapse',),
'fields': ('api_key', 'api_secret'),
}),
)
search_fields=list_display
list_filter=['user_type','profile_complete']
list_editable=list(list_display)
list_editable.remove('id')
list_editable.remove('updated_at')
list_editable.remove('created_at')
list_editable.remove('last_login_timestamp')
list_editable.remove('last_login_ip')
class Meta:
model = LCUser
On display I somtimes see two inline rows instead of one and when I try to update it I get "ManagementForm data is missing or has been tampered with"
Figured out what I was doing wrong. looks like I forgot to initialize the inlinse variable. So everytime I clicked on an object it added the same inline model again, which caused errors when I tried to save it.