Django admin "add page" starting time datetime from GET parameters

I want to create a link that opens the django admin add page for a model with pre-populated fields.

I checked that you can add parameters to the GET dictionary of the add form, as in:

<a href='/admin/myapp/mymodel/add?name=John'>add new mymodel with name John</a> 

(actually I get url with {% url 'admin: myapp_mymodel_add'%}, but this should be explicit).

Now this works great with numeric values, text values ​​and foreign keys. But what about DateTime fields? When I try to pass such a field (I tried many formats, for example, "2014-05-09 10:10:00"), I always get a "server error" complaining that:

'unicode' object has no attribute 'date'

in the line of code:

django / forms / widgets.py unpacked, line 902

  def decompress(self, value): if value: value = to_current_timezone(value) return [value.date(), value.time().replace(microsecond=0)] ... return [None, None] 

where the variable "value" has the value that I pass to the url ...

Question 1. I would suggest that the server code should not throw an exception depending on the values ​​passed by the user ... is this an error in the django libraries?

Question 2. How can I solve my problem, for example, pass the initial datetime through the GET parameters to the "add" page of the model administrator?

+6
source share
2 answers

No, this is not a mistake; perhaps the argument that the default behavior can be improved, but the existing implementation is a reasonable first pass (as evidenced by the fact that it works with integers, strings, foreign keys, etc.). There is enough metadata about the model and enough deserialization code that processing could be improved a bit here, but I don't think this is a mistake.

The good news is that there is an official way to handle this; in the ModelAdmin class ModelAdmin define:

 def get_changeform_initial_data(self, request): 

This method accepts the request and converts this request to a value that will be passed as an argument to the initial form in the change list (for example, the add or edit page in Admin). As you would expect, the default implementation of this method is "accept GET arguments and convert to a dictionary"; if you do some extra processing for fields that you know are datetime, then

In addition, you do not have to use a query object. If you know that Person objects will always have an Unknown start name and a start date of January 1, 2014, then you can simply write:

 class PersonAdmin(ModelAdmin): ... def get_changeform_initial_data(self, request): return { 'name': 'Unknown', 'start_date': date(2014, 1, 1) } 

ie, ignore the request data, just enter the initial data manually. Since this is the source data in the form, any existing data about the object will override the value specified in initial , and that the source data will be used without the user having to provide any GET arguments in his request.

+3
source

The problem seems to be that you are passing a string when it expects a date. First you need to convert the string to a date.

You can use python datetime built-in library:

  import datetime value = datetime.datetime.strptime(value, "%Y-%m-%d %H:%M:%S") def decompress(self, value): ... 

Edit: alecxe correctly indicated that I did not answer your question correctly. With a bit of searching, I found what might be more relevant.

According to this answer, Django allows you to replace the GET dictionary before processing it. Borrowing from this example seems possible so that we can intercept your get parameters and replace string dates with datetime objects in the GET dictionary

  def add_view(self, request, form_url='', extra_context=None): // any extra processing can go here... g = request.GET.copy() g.update({ 'date':datetime.datetime.strptime(request.GET.get('date'), "%Y-%m-%d %H:%M:%S"), }) request.GET = g return super(MyModelAdmin, self).add_view(request, form_url, extra_context) 
+1
source

All Articles