django-localflavor fields not showing up in Django admin models? - django

I am trying to implement django-localflavors into my Django app.
I import USStateSelect & USZipCodeField at the beginning of my models.py and then include them as a field in my model along with other fields, like so:
from localflavor.us.forms import USStateSelect, USZipCodeField
...
Class MyModel(models.Model):
...
state = USStateSelect()
zip_5 = USZipCodeField()
However, when I go to Django admin and try to create a new Model object, I see every other field I wrote (CharFields, etc.) EXCEPT any of the localflavor fields. They are simply not showing up at all as an input field in my Model object form. I have done migrations on my database so that is not the issue.
Am I misunderstanding how to use django-localflavor? I read in an answer to a different post that localflavor doesn't actually create input fields, only stores data... but then I've also read that it DOES let you input data. At this point I am confused. Any help would be appreciated!

I think what you are looking for are the model fields. The form fields are used when building your own forms (usually outside the admin, such as a contact form). Localflavor has a couple fields that should do what you need. Note that these are essentially CharFields that have some extra validation to make sure the follow the desired format.

You need to specify choices option.
Change your code a little as below:
from localflavor.us.forms import USStateSelect, USZipCodeField
...
Class MyModel(models.Model):
...
state = USStateSelect(choices=STATE_CHOICES) # add choices
zip_5 = USZipCodeField() # no change on this line

Related

Change date format in Django admin page [duplicate]

I recently added a new model to my site, and I'm using an admin.py file to specify exactly how I want it to appear in the admin site. It works great, but I can't figure out how to get one of my date fields to include seconds in it's display format. I'm only seeing values like "Aug. 27, 2011, 12:12 p.m." when what I want to be seeing is "Aug. 27, 2011, 12:12*:37* p.m."
Try this in the ModelAdmin:
def time_seconds(self, obj):
return obj.timefield.strftime("%d %b %Y %H:%M:%S")
time_seconds.admin_order_field = 'timefield'
time_seconds.short_description = 'Precise Time'
list_display = ('id', 'time_seconds', )
Replacing "timefield" with the appropriate field in your model, of course, and adding any other needed fields in "list_display".
digging around I ended here but applied a different approach to my app.
Changing django admin default formats could be done changing the django locale formats for every type you want.
Put the following on your admin.py file (or settings.py) to change datetime default format at your django admin.
from django.conf.locale.es import formats as es_formats
es_formats.DATETIME_FORMAT = "d M Y H:i:s"
It will change the ModelAdmin's datetime formats on that file (or whole site if in settings).
It does not breaks admin datetime filters and order features as #Alan Illing has point out in comments .
hope this help in future
Extra info:
You can change it for every available locale in django, which are a lot.
You can change the following formats using this approach
from django.conf.locale.es import formats as es_formats
es_formats.DATETIME_FORMAT
es_formats.NUMBER_GROUPING
es_formats.DATETIME_INPUT_FORMATS
es_formats.SHORT_DATETIME_FORMAT
es_formats.DATE_FORMAT
es_formats.SHORT_DATE_FORMAT
es_formats.DATE_INPUT_FORMATS
es_formats.THOUSAND_SEPARATOR
es_formats.DECIMAL_SEPARATOR
es_formats.TIME_FORMAT
es_formats.FIRST_DAY_OF_WEEK
es_formats.YEAR_MONTH_FORMAT
es_formats.MONTH_DAY_FORMAT
If you've tried gabriel's answer but it did not work, try to set USE_L10N = False in settings.py, it works for me.
Note that if USE_L10N is set to True, then the locale-dictated format has higher precedence and will be applied instead
See: https://docs.djangoproject.com/en/2.0/ref/settings/#std:setting-DATETIME_FORMAT
The accepted answer is correct, however I found it a bit confusing to understand how/why it works. Below is a small example that I hope illustrates how to do this more clearly.
Django provides a few ways to display "custom" fields in your admin view. The way I prefer to achieve this behavior is to define a custom field in the ModelAdmin class and display that instead of your intended field:
from django.contrib import admin
from django.db import models
class Person(models.Model):
name = models.CharField(max_length=50)
birthday = models.DateField()
class PersonAdmin(admin.ModelAdmin):
#admin.display(description='Birthday')
def admin_birthday(self, obj):
return obj.birthday.strftime('%Y-%m-%d')
list_display = ('name', 'admin_birthday')
Notice that instead of displaying the actual birthday field from the Person model, we define a custom field (admin_birthday) as a method in the PersonAdmin and display that instead by adding it to the list_display attribute. Furthermore, the admin.display() decorator modifies how Django will display this custom field in the admin view. Using this approach, the admin panel will show the NAME and BIRTHDAY fields but using your preferred date formatting for the date.
The reason I prefer this approach is you keep the Model field definitions separate from how you display them in the admin panel. You can read more about alternative approaches in the Django admin documentation.

Modify createView so as to post to two different forms from same template?

I have two models which have common fields, say
class model1(models.Model):
commonfield1 = ...
commonfield2 = ...
class model2(models.Model):
commonfield1 = ...
commonfield2 = ...
extrafields=..
....
Now I have two different create forms for these both models using forms.ModelForm
Now, my requirement is that when I create a new object for model2, I also want to save an object in model1.
As of now, I am using CreateView to save the form for model2.
I want to give the user an option such that if he presses that save two objects button both the models should be updated accordingly.
Is there any way I can do this using CreateView? Thanks!
This isn't a duplicate question, but this link should help you out.
In order to do this, you need to first add a field to your modelForm, and second, overwrite form_valid. If your custom field is checked, then you should manually call model2.objects.create(...) with the proper fields from the form.

django generic view update/create: update works but create raises IntegrityError

I'm using CreateView and UpdateView directely into urls.py of my application whose name is dydict. In the file forms.py I'm using ModelForm and I'm exluding a couple of fields from being shown, some of which should be set when either creating or updating. So, as mentioned in the title, update part works but create part doesn't which is obvious because required fields that I have exluded are sent empty which is not allowed in my case. So the question here is, how should I do to fill exluded fields into the file forms.py so that I don't have to override CreateView?
Thanks in advance.
Well, you have to set your required fields somewhere. If you don't want them to be shown or editable in the form, your options are to set them in the view (by using a custom subclass of CreateView) or if appropriate to your design in the save method of the model class. Or declare an appropriate default value on the field in the model.
It would also work to allow the fields into the form, but set them to use HiddenInput widgets. That's not safe against malicious input, so I wouldn't do that for purely automated fields.
You cannot exclude fields, which are set as required in the model definition. You need to define blank=True/null=True for each of these model fields.
If this doesn't solve your issue, then please show us the model and form definitions, so we know exactly what the code looks like.

How do you save the order of a django inline formset?

In Django, I'm using an inlineformset with can_order = True, on a model that has order_with_respect_to set. I've set up drag and drop on the front end, which results in Django's autogenerated ORDER form fields (which I've hidden) changing to reflect the new order. I've verified I'm POSTing the new order correctly to the server, but Django seems to ignore it, and saves the models in the original order. The automatically-created _order fields in the database never change.
How can I get Django to save the models using order specified in the formset? Do I need to do anything special other than calling save() on the formset?
Evan Borgstrom proposed solution does not work together with can_delete=True.
Here is my solution that also works with can_delete=True:
for instance in formset.save(commit=False):
# ... do something with m2m relationships ...
for form in formset.ordered_forms:
form.instance.order = form.cleaned_data['ORDER']
form.instance.save()
I had the same problem and after digging through the Django source figured that it's something you need to do on your own.
My original implementation looked something like this:
services = service_formset.save(commit=False)
for service in services:
# ... do something with m2m relationships ...
service.save()
However, as you've found this doesn't set the ORDER. So instead my implementation now looks like:
for form in service_formset:
service = form.save(commit=False)
# ... do something with m2m relationships ...
service.order_order = form.cleaned_data['ORDER']
service.save()
In my example above 'order_order' is the field I'm using to track order on my models.
Also remember that you need to specify the 'ordering' attribute of your model's Meta class to ensure that when you generate the formset again the elements are in the correct order.
class Service(models.Model):
# ...
order_order = models.IntegerField(default=0)
class Meta:
ordering = ['order_order',]

Django - Customizeable UserProfile

So I've got a UserProfile in Django that has certain fields that are required by the entire project - birthday, residence, etc. - and it also contains a lot of information that doesn't actually have any importance as far as logic goes - hometown, about me, etc. I'm trying to make my project a bit more flexible and applicable to more situations than my own, and I'd like to make it so that administrators of a project instance can add any fields they like to a UserProfile without having to directly modify the model. That is, I'd like an administrator of a new instance to be able to create new attributes of a user on the fly based on their specific needs. Due to the nature of the ORM, is this possible?
Well a simple solution is to create a new model called UserAttribute that has a key and a value, and link it to the UserProfile. Then you can use it as an inline in the django-admin. This would allow you to add as many new attributes to a UserProfile as you like, all through the admin:
models.py
class UserAttribute(models.Model):
key = models.CharField(max_length=100, help_text="i.e. Age, Name etc")
value = models.TextField(max_length=1000)
profile = models.ForeignKey(UserProfile)
admin.py
class UserAttributeInline(admin.StackedInline):
model = UserAttribute
class UserProfile(admin.ModelAdmin):
inlines = [UserAttibuteInline,]
This would allow an administrator to add a long list of attributes. The limitations are that you cant's do any validation on the input(outside of making sure that it's valid text), you are also limited to attributes that can be described in plain english (i.e. you won't be able to perform much login on them) and you won't really be able to compare attributes between UserProfiles (without a lot of Database hits anyway)
You can store additional data in serialized state. This can save you some DB hits and simplify your database structure a bit. May be the best option if you plan to use the data just for display purposes.
Example implementation (not tested)::
import yaml
from django.db import models
class UserProfile(models.Model):
user = models.OneToOneField('auth.User', related_name='profile')
_additional_info = models.TextField(default="", blank=True)
#property
def additional_info(self):
return yaml.load(self._additional_info)
#additional_info.setter
def additional_info(self, user_info_dict):
self._additional_info = yaml.dump(user_info_dict)
When you assign to profile.additional_info, say, a dictionary, it gets serialized and stored in _additional_info instead (don't forget to save the instance later). And then, when you access additional_info, you get that python dictionary.
I guess, you can also write a custom field to deal with this.
UPDATE (based on your comment):
So it appears that the actual problem here is how to automatically create and validate forms for user profiles. (It remains regardless on whether you go with serialized options or complex data structure.)
And since you can create dynamic forms without much trouble[1], then the main question is how to validate them.
Thinking about it... Administrator will have to specify validators (or field type) for each custom field anyway, right? So you'll need some kind of a configuration option—say,
CUSTOM_PROFILE_FIELDS = (
{
'name': 'user_ip',
'validators': ['django.core.validators.validate_ipv4_address'],
},
)
And then, when you're initializing the form, you define fields with their validators according to this setting.
[1] See also this post by Jacob Kaplan-Moss on dynamic form generation. It doesn't deal with validation, though.