I'm implementing the schema fields by using the method get_schema_fields in DRF. On the swagger UI for the form field instead of the name which ["metrics"] I have given it is displaying the data as the name. Also the model example is also not coming.
This is the code
def get_schema_fields(self, view):
return [
coreapi.Field(
name='metrics',
location='form',
required=True,
schema=coreschema.Object(),
description='metrics type',
),
How can rename that field name from data to metrics also how to display the model sample?
I'm not sure why you want to change data to metrics, all I know is you can add or remove fields in the "Example Value" or "Model" using get_manual_fields or get_serializer_fields, here there is an example:
def get_serializer_fields(self, path, method):
fields = []
if path == 'my_path' and method == 'PUT':
fields = [coreapi.Field(
"custom_field",
required=True,
location="",
schema=coreschema.String()
)]
return fields
Here more documentation:
http://www.django-rest-framework.org/api-guide/schemas/#get_serializer_fieldsself-path-method
Related
I have a snippet which is a proxy of one of my standard django models.
search_fields works fine when filtering on standard fields, the problem is I can't seem to get foreign keys to work.
This page has an example on the bottom that shows how to create searchable snippets:
https://docs.wagtail.org/en/stable/topics/snippets.html
The main model has a field called "day" which is a foreign key to a Day-table. A day has a calendar_year, which I would like to be able to filter on while searching in the wagtail snippets area. in the def str method I'm able to display the name in the list, the search is the problem here.
Suggestions?
#register_snippet
class EventSnippet(index.Indexed, Event):
# We make a proxy model just to be able to add to this file or potentially if we want custom methods on it.
panels = [
FieldPanel('name'),
]
search_fields = [
index.SearchField('day__calendar_year', partial_match=True), # This prompts an error
index.SearchField('name', partial_match=True),
]
class Meta:
proxy = True
def __str__(self):
return f"{self.name} {self.day.calendar_year}"
When running python manage.py update_index i get the following warning:
EventSnippet.search_fields contains non-existent field 'day__calendar_year
You can't use complex lookups with double-underscores inside SearchField - search queries work by populating a central table (the search index) in advance with the data you're going to be searching on, which means you can't do arbitrary lookups and transformations on it like you would with a standard database query.
However, you can use any method or attribute in SearchField - not just database fields - so you could add a method that returns the year, and use that:
#register_snippet
class EventSnippet(index.Indexed, Event):
# ...
def get_year(self):
return self.day.calendar_year
search_fields = [
index.SearchField('get_year', partial_match=True),
index.SearchField('name', partial_match=True),
]
I would like to add plan names to dj-stripe django admin so I can see a readable name for what each subscription is associated with. Adding "cancel_at" worked, but I can't use the name of a Product from a Plan.
In my_app\admin.py I do this:
from djstripe.models import Subscription
from djstripe.admin import StripeModelAdmin, SubscriptionItemInline
...
class SubscriptionAdmin(StripeModelAdmin):
list_display = ("plan__product__name", "customer", "status", "cancel_at")
list_filter = ("status", "cancel_at_period_end")
list_select_related = ("customer", "customer__subscriber")
inlines = (SubscriptionItemInline,)
def _cancel(self, request, queryset):
"""Cancel a subscription."""
for subscription in queryset:
subscription.cancel()
_cancel.short_description = "Cancel selected subscriptions" # type: ignore # noqa
actions = (_cancel,)
admin.site.unregister(Subscription)
admin.site.register(Subscription, SubscriptionAdmin)
...
Which produces this error:
Subscription has no field named 'plan__product__name'
How do I add extra columns in dj-stripe that require foreign key lookups?
One solution is to make a callable then reference it in the modeladmin class.
Per the docs:
ModelAdmin.list_display
Set list_display to control which fields are displayed on the change list page of the admin.
There are four types of values that can be used in list_display. All but the simplest may use the display() decorator is used to
customize how the field is presented:
A callable that accepts one
argument, the model instance. For example:
#admin.display(description='Name')
def upper_case_name(obj):
return ("%s %s" % (obj.first_name, obj.last_name)).upper()
class PersonAdmin(admin.ModelAdmin):
list_display = (upper_case_name,)
Which means in my case I can do this to add a combined tier + interval column:
#admin.display(description='Subscription Tier and Interval')
def subscription_tier_interval(obj):
return ("%s - %s" % (obj.plan.product.name, obj.plan.interval))
class SubscriptionAdmin(StripeModelAdmin):
list_display = ("customer", "status", subscription_tier_interval, "cancel_at")
list_filter = ("status", "cancel_at_period_end")
list_select_related = ("customer", "customer__subscriber")
inlines = (SubscriptionItemInline,)
def _cancel(self, request, queryset):
"""Cancel a subscription."""
for subscription in queryset:
subscription.cancel()
_cancel.short_description = "Cancel selected subscriptions" # type: ignore # noqa
actions = (_cancel,)
admin.site.unregister(Subscription)
admin.site.register(Subscription, SubscriptionAdmin)
I'm learning and new to Django Rest Framework and I'm having an issue in serializer validations and ListSerializer update method.
I have an APIView class which handles the put request. I just wanted to have a custom validation and so I've overridden validate method in the serializer class.
From postman I'm sending a JSON data to this APIView Class.
Sample JASON data:
[
{
"id": 1,
"ip": "10.1.1.1",
"host_name": "hostname 1"
},
{
"id": 2,
"ip": "10.1.1.2",
"host_name": "hostname 2"
}
]
When I receive the data and do serializer.is_valid() it passes the flow to the overridden validate function. But in there when I check for the attrs argument, I get all the fields except the id. The key and value for id are not present. It shows None.
The same issue occurred to me when I was trying to override the update method in ListSerializer.
when I tried the below code in the ListSerializer's update method,
data_mapping = {item['id']: item for item in validated_data}
I got an error saying KeyError 'id'.
It seems it's not accepting id field and I'm not sure why! Please, someone explain this to me if I'm wrong anywhere.
Serializer class
from rest_framework import serializers
from .models import NoAccessDetails
class NoAccessDetailsListSerializer(serializers.ListSerializer):
def update(self, instance, validated_data)
data_mapping = {data.id: data for data in instance}
#Here I'm getting KeyError ID
validated_data_mapping = {item['id']: item for item in validated_data}
return
class NoAccessDetailsSerializer(serializers.ModelSerializer):
class Meta:
model = NoAccessDetails
list_serializer_class = NoAccessDetailsListSerializer
fields = ("id", "ip", "host_name")
def validate(self, data):
id_val = data.get('id')
ip = data.get('ip')
host_name = data.get('host_name')
#here the id value is None
print('id val {} '.format(id_val))
return data
If I am understanding correctly, the issue is that you do not see the id field inside of validated_data. If so, I believe this is intentional in the framework:
https://github.com/encode/django-rest-framework/issues/2320
Basically, the id field is read_only by default. Let me know if you have questions that are not answered by Tom's response to that issue.
EDIT: Also feel free to share the higher level use case (what you are planning on doing with the ID inside of validation), and maybe we can offer alternative approaches.
I have a form in a formset where I would like to display multiple drop down menus under a single field 'tests'. I have achieved this in the form of having a single dropdown menu within 'optgroup' tags (see image below).
I guess this way you can only choose a single value.
However, is it possible to 'nest' these drop downs? I.e have them all under one field 'tests', but be able to have several dropdowns with 'tags' and choose results for each tag? Or do I need a field for each 'tag'?
My forms.py:
class ReportForm(forms.ModelForm):
summary = forms.CharField(
widget=forms.Textarea(attrs={'rows':3, 'cols':70}),
label='',
required=False)
tests = forms.CharField(widget=forms.HiddenInput())
class Meta:
model = ClinicallyReportedSample
fields = ('id', 'summary', 'tests', 'hilis_reported')
def __init__(self, *args, **kwargs):
json_data = kwargs.pop('json_data', None)
super(ReportForm, self).__init__(*args, **kwargs)
crs_obj = self.instance
for j in json_data:
if j['lab_no'] == str(crs_obj):
json = j
summary = json['summary']
self.fields['summary'].initial = summary
self.fields['reported'].label = crs_obj
tests = json.get('tests', None)
if tests:
test_choices = (
('mutated', 'mutated'),
('mutated - see comments', 'mutated - see comments'),
('awaiting confirmation', 'awaiting confirmation'),
)
self.fields['tests'] = forms.ChoiceField(
required=True,
label='Current or repeat samples?',
choices=((k, test_choices) for k in tests),
)
What I get now:
I would instead want a dropdown for each gene, and those choices. Do I need to make a field for each gene? The problem I have with doing this is that each result can have 0-10 genes, and this would be incredibly difficult to render in a HTML table.
Thanks
You probably want to implement something template/client-side to handle that, such as Chosen or Selectize.js (see the option groups examples).
Then on your form class implement a clean and/or clean_[field_name] method if you need to get your selected data in the format you want.
I am developing an application using django where the UI needs to be updated when user interacts with it. For instance I have a Drop down field where the user selects a drink and submits it then based on that a dropdown with the places that drink is available, price and quantity at each place needs to be displayed. The user will then further submit the form for second process.
From my understanding the Forms in django are pre-defined and I am not able to think of a way using which I could achieve this.
What I could come up was defining a regular form class
class dform(forms.Form):
SOURCES_CHOICES = (
(A, 'A'),
(E, 'E'),
)
drink = forms.ChoiceField(choices = SOURCES_CHOICES)
location = forms.ChoiceField(choices = **GET THIS FROM DATABASE**)
quantity = forms.ChoiceField(choices = **GET THIS FROM DATABASE**)
.
.
.
My view is like,
def getdrink():
if request.method == 'POST':
#code for handling form
drink = dform.cleaned_data['drink']
#code to get values from database
I have no idea how to generate or populate or append the values i get from the database to the choicefield in my form. I did try looking up on SO but none of the solutions here explained properly how to do it. Also, due to certain requirements I am not using the models. So my database is not at all related to the models.
I am at a total loss Please help me out
class MyForm(forms.Form):
my_choice_field = forms.ChoiceField(choices=MY_CHOICES)
So if you want the values to be dynamic(or dependent of some logic) you can simply modify your code to something like this:
either
def get_my_choices():
# you place some logic here
return choices_list
class MyForm(forms.Form):
my_choice_field = forms.ChoiceField(choices=get_my_choices())
or
User_list = [ #place logic here]
class MyForm(forms.Form):
my_choice_field = forms.ChoiceField(choices=get_my_choices())
but once database value is updated, new data value will be popoulated only on restart of server.
So write a function like this in forms:
class MyForm(forms.Form):
def __init__(self, *args, **kwargs):
super(MyForm, self).__init__(*args, **kwargs)
self.fields['my_choice_field'] = forms.ChoiceField( choices=get_my_choices() )
or in place of the get_my_choices u can ad the USER_LIST too.
If you have models for location and quantity, a ModelChoiceField should work:
class dform(forms.Form):
location = forms.ModelChoiceField(queryset = Location.objects.all())
Otherwise, you'll need to query the database directly, for example:
class dform(forms.Form):
location = forms.ChoiceField(choices = get_location_choices())
# elsewhere
from django.db import connection
def get_location_choices():
cursor = connection.cursor()
cursor.execute("select location_id, name from location_table")
return cursor.fetchall()
The SQL query to use here depends on your database engine and table schema.
I think that, based on my understanding of your question, the best solution would be to include JSON objects with your form and load these using jQuery instead of submitting the form over and over. Included in your form, you should add something like:
class MyForm(forms.Form):
CHOICE_DICT = {
'choice_1': [
'option_1',
'option_2',
],
etc...
Then you should include form.CHOICE_DICT in your context, load that with jQuery, and render it depending on changes to other fields.