Basically in a popup (bootstrap) I would like to have all specified pre-populated fields from my model.
I found this code (https://groups.google.com/forum/#!searchin/django-rest-framework/HTMLFormRenderer/django-rest-framework/s24WFvnWMxw/hhmaD6Qw0AMJ)
class CreatePerformanceForm(forms.ModelForm):
model = Performance
fields = ('field1', 'field2')
class PerformanceCreateView(ListCreateAPIView):
serializer_class = PerformanceCreateSerializer
model = Performance
template_name = 'core/perform.html'
def get(self, request, format=None):
data = {'
form': CreatePerformanceForm()
}
return Response(data)
My question is the same.
Is there a way to create the form directly from the serializer so I don't have to create a Django form?
I looked at HTMLFormRenderer, but the DRF doc is quiet poor about this issue.
Thanks,
D
See this issue. Important part:
There are some improvements that could be made there [to HTMLFormRenderer], notably supporting error messaging against fields, and rendering the serializer directly into html without creating a Django form in order to do so [...]
So basically, HTMLFormRenderer also uses Django forms. Also, you are right, the documentation doesn't provide too much support for it. Even more, it seems that this renderer might soon change. See here. Quote:
Note that the template used by the HTMLFormRenderer class, and the context submitted to it may be subject to change. If you need to use this renderer class it is advised that you either make a local copy of the class and templates, or follow the release note on REST framework upgrades closely.
I know this doesn't help much, but for now there is no better way than the way you did it.
Related
I have a project with around 60 models so creating a unique Detail, Create, Update, Delete APIView for each would be a lot of wasted resources (or so it feels like). Would it be better performance-wise (or safe?) to simply create a generic view that could cycle between each model like so?
_CLASSES = <Dictionary of my classes>
class GenericModelView(APIView):
def get(self, request, model_name): # model_name would be a required part of the URL.
model_class = _CLASSES[model_name]
serializer_class = model_class.serializer_class # I would instantiate a serializer for each model_class
return Response(serializer_class(model_class.objects.all()).data)
I think, there should not be any concerns safety wise. However, in my experience, this approach will not last long. You will have to customize the functionality for different model according to the requirements. At that stage, you will need to create separate views. Also, it may become complicated to read and understand logs as always same function is being called. So my final recommendation would be to use different views. It should not take you more than an hour. Just copy and paste. Customize later according to your needs.
I am writing a web site using Django REST framework. This is my first days with the REST, so please bear with me. Basically, the question is,
Can I come up with a class-based view which could serve both as an API for Android developers (with JSON response) and a view rendering regular Django template? Or I have to define two different views for this purpose ?
If the answer to question 1 is that I have to define two separate views, then what is the most DRY method to do that taking into account that the querysets are the same ?
The view:
class TestList(APIView):
renderer_classes = [TemplateHTMLRenderer]
template_name = 'android/test.html'
def get(self, request):
queryset = Test.objects.all()
return Response({'test_qs': queryset})
Put in other words, imagine that I have a model queryset, I want to both render this on my site to my end user, and to send it to my Android developers. What is the best practice in terms of REST framework code architecture? Two different class based views? Or one view with two methods inside it ? Or one view with one magic method which would do both jobs for me ?
I would suggest to keep it separate. With simple CRUD - you will not have the issues with DRY because they are simply different views, consider:
DRF (basically this is all for CRUD, if you want only a list use: ListModelMixin):
class ServiceViewSet(viewsets.ModelViewSet):
queryset = Service.objects.all()
serializer_class = ServiceSerializer
I think that merging this into one View - sooner or later will get you into troubles.
What kind of troubles?
Your templates can at some point use much more data to display the page to the user than your REST API (simple example: current time) - you will start to implement different context for template and different for REST;
and nothing more came to my mind ;) but I have a feeling that two separate views make it much more clean.
I also understand the risk of repeating the same code twice - but you can always extract the repeating code to some helping structures.
As for queryset - if it's simple - do not bother with one place for storing it. If it can get complicated - again - there's no problem to store the queryset in some helping structure and use in both views:
class ProjectQuerysets(object):
my_test_qs = Test.objects.filter(created_at__gte=now-timedelta(seconds=30)).all()
or event something more sophisticated:
class TestQSMixni(object):
def get_queryset(self, *args, **kwargs):
return Test.objects.filter(user=self.request.user) # something like that;
And later:
class TestList(TestQSMixin, APIView):
def get(self, *args, **kwargs):
queryset = self.get_queryset()
# and in REST:
class ServiceViewSet(TestQSMixin, viewsets.ModelViewSet):
serializer_class = ServicesSerializer
# no queryset needed here
(sorry for example with this services, but I have this in some notes :))
Hope this will help you a little.
At the end - it all depends on your needs :) And the project requirements.
Happy coding.
I know that many questions exist about this same topic, but i am confused on one point.
My intent is to show two ModelChoiceFields on the form, but not directly tie them to the Game model.
I have the following:
forms.py
class AddGame(forms.ModelForm):
won_lag = forms.ChoiceField(choices=[('1','Home') , ('2', 'Away') ])
home_team = forms.ModelChoiceField(queryset=Player.objects.all())
away_team = forms.ModelChoiceField(queryset=Player.objects.all())
class Meta:
model = Game
fields = ('match', 'match_sequence')
Views.py
def game_add(request, match_id):
game = Game()
try:
match = Match.objects.get(id=match_id)
except Match.DoesNotExist:
# we have no object! do something
pass
game.match = match
# get form
form = AddGame(request.POST or None, instance=game)
form.fields['home_team'].queryset = Player.objects.filter(team=match.home_team )
# handle post-back (new or existing; on success nav to game list)
if request.method == 'POST':
if form.is_valid():
form.save()
# redirect to list of games for the specified match
return HttpResponseRedirect(reverse('nine.views.list_games'))
...
Where i am confused is when setting the queryset filter.
First i tried:
form.home_team.queryset = Player.objects.filter(team=match.home_team )
but i got this error
AttributeError at /nine/games/new/1
'AddGame' object has no attribute 'home_team'
...
so i changed it to the following: (after reading other posts)
form.fields['home_team'].queryset = Player.objects.filter(team=match.home_team )
and now it works fine.
So my question is, what is the difference between the two lines? Why did the second one work and not the first? I am sure it is a newbie (i am one) question, but i am baffled.
Any help would be appreciated.
Django Forms are metaclasses:
>>> type(AddGame)
<class 'django.forms.forms.DeclarativeFieldsMetaclass'>
They basically create a form instance according to the information given in its definition. This means, you won't get exactly what you see when you define the AddGame form. When you instantiate it, the metaclass will return the proper instance with the fields provided:
>>> type(AddGame())
<class 'your_app.forms.AddGame'>
So, with the instance, you can access the fields by simply doing form.field. In fact, it is a bit more complicated than that. There are two types of fields you can access. With form['field'] you'll be accessing a BoundField. Which is used for output and raw_input.
By doing form.fields['fields'] you'll be then accessing to a field that python can understand. This is because if the from already got any input, there's where validation and data conversion take places (in fact, those are the fields used for this, the general process of validation is a bit more complicated).
I hope this might clear a little the issue for you but as you may see, the whole form's API is really big and complicated. Is very simple for end-users but it has a lot of programming behind the curtains :)
Reading the links provides will help clear your doubts and will improve your knowledge about this very useful topic and Django in general.
Good luck!
UPDATE: By the way, if you want to learn more about Python's Metaclasses, this is a hell of an answer about the topic.
In you views.py, you have this line:
form = AddGame(request.POST or None, instance=game)
So form is a Form object of class AddGame (Side note: you should change the name to AddGameForm to avoid confusion).
Since home_team is a field in AddGame class, it's not an attribute in form object. That's why you can't access it via form.home_team.
However, Django Form API provides fields attribute to any form object, which is a dict contains all form fields. That's why you can access form.fields['home_team'].
And finally since home_team is a ModelChoiceField, it can contain a queryset attribute, that's why you can access form.fields['home_team'].queryset
I'm not talking about just custom fields to the form or static data, I'm talking about adding a section which actually has it's own code. Kind of a new entry in the fieldset but which introduces not a new field but some small reports on the users's activity.
Actually this questions stands for any model's change page. The Django docs show you how to overwrite the template for this page but what good is that without adding some python code also?
You can overrride default templates and default views.
Django has two different views and templates for admin record displaying. One for creating a new one and one for displaying an existing one and editing it. Related methods are:
Add Form Template and Add View for adding a new record
Change Form Template and Change View for displaying and changing an existing record
This is an example of how to prepare related override views (taken from Add/Change View link)
class MyModelAdmin(admin.ModelAdmin):
# A template for a very customized change view:
change_form_template = 'admin/myapp/extras/openstreetmap_change_form.html'
def get_osm_info(self):
# ...
pass
def change_view(self, request, object_id, form_url='', extra_context=None):
extra_context = extra_context or {}
extra_context['osm_data'] = self.get_osm_info()
return super(MyModelAdmin, self).change_view(request, object_id,
form_url, extra_context=extra_context)
You must check default django add and change templates from django source code (and maybe copying it as your new template and editing afterwards) to see how you can prepare your custom templates.
A final note, Never edit django template or vieew codes directly from source, since they are used by many different applications and and update to django source code might override your edit or may cause problems.
The Django admin is very extensible beyond overriding the templates.
Make sure you look at the ModelAdmin methods section in the documentation.
You can modify pretty much any behavior of the ModelAdmin.
You should also look at the custom form validation and ModelForms documentation, as a custom form for your model attached to its ModelAdmin gives you another (deeper, in most ways) level of customization.
Is there any good articles that explain custom form fields in django, not custom model fields? I couldn't find any through google.
Form fields are easy to customize:
class UpperCaseField(forms.CharField):
def clean(self, value)
try:
return value.upper()
except:
raise ValidationError
basically you just create a class that inherits from the field that most resembles what you want, then rewrite the clean() method so that it returns the value you want. Here is another example:
class MyObjectField(forms.ModelChoiceField):
# in this case, 'value' is a string representing
# the primary key of a MyObject
def clean(self, value):
try:
return MyObject.objects.get(pk=value)
except:
raise ValidationError
custom widgets on the other hand, are a little more useful, but a little more hard to do because there are a few more methods that need to be written so that they work smoothly.
As always with open-source code, you'll learn a great deal by reading the source itself. See the django.forms.fields module to see how all the different form fields are defined - most of them are subclasses of others already, so you can just replicate that and change what you need.
It's not a tutorial, but django's docs talks about this a little:
If the built-in Field classes don't
meet your needs, you can easily create
custom Field classes. To do this, just
create a subclass of
django.forms.Field. Its only
requirements are that it implement a
clean() method and that its __init__()
method accept the core arguments
mentioned above (required, label,
initial, widget, help_text).
You can read about the clean method and see an example at the django docs. Again, not a tutorial, but useful.
I find I am learning a lot by reading the code in some of the the django app projects that are available, such as django-extensions, which override the form fields and are good learning tools (for me, at least). This can help get you started.