I am building a notification system for a company, where admin users can create Projects and add users to them. The Project model has 9 attributes but I only want to show 3 or 4 fields when a Project is created, but show them all when an existing Project is updated.
This change will only need to be reflected on the Django admin site, so I have extended the ProjectAdmin with my own ProjectForm, where I extend the init method to check if it is a new instance and if so remove certain fields.
# models.py
class Project(models.Model):
project_number = models.IntegerField()
name = models.CharField(max_length=100)
permit = models.CharField(max_length=100, blank=True, default='')
is_active = models.BooleanField(default=True)
users = models.ManyToManyField(CustomUser, blank=True, related_name='project_users')
# add a default
levels = models.ManyToManyField('Level', blank=True, related_name='project_levels')
total_contract_hours = models.IntegerField(default=0, blank=True, verbose_name='Total Design Hours')
hours_used = models.IntegerField(default=0, blank=True, verbose_name='Total Design Hours Used')
notes = models.ManyToManyField('notes.ProjectNote', related_name='core_project_notes', blank=True)
history = HistoricalRecords()
def __str__(self):
ret_str = "{} {}".format(self.project_number, self.name)
if self.permit:
ret_str += " | Permit: {}".format(self.permit)
return ret_str
# admin.py
class ProjectForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(ProjectForm, self).__init__(*args, **kwargs)
attrs = {'class': 'form-control', 'required': True}
if self.instance and self.instance.pk is None:
# creating project
exclude = ['is_active', 'users', 'levels', 'hours_used', 'notes']
for field in exclude:
try:
del self.fields[field]
except ValueError:
print('{} does not exist'.format(field))
for field in self.fields.values():
field.widget.attrs = attrs
class Meta:
model = Project
fields = ['project_number', 'name', 'total_contract_hours']
class ProjectAdmin(admin.ModelAdmin):
form = ProjectForm
fields = ['project_number', 'name', 'permit', 'is_active', 'users', 'levels', 'total_contract_hours', 'hours_used', 'notes']
As I stated I only want basic Project fields on creation, but show all attributed when updating existing Project. With just these changes, I now get a KeyError:
KeyError: "Key 'is_active' not found in 'ProjectForm'. Choices are:
name, permit, project_number, total_contract_hours."
However, when I print the available fields it returns an OrderedDict with all of the model attributes as keys. What am I doing wrong? Thanks!
I figured it out, the field must be in listed in Meta and then you just set the field to be a hidden field.
class ProjectForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(ProjectForm, self).__init__(*args, **kwargs)
print("Adding project")
if not self.instance or self.instance.pk is None:
for name, field in self.fields.items():
if name in ['design_manager', ]:
field.widget = forms.HiddenInput()
class Meta:
model = Project
fields = ['project_number', 'name', 'design_manager', 'total_contract_hours']
class ProjectAdmin(admin.ModelAdmin):
form = ProjectForm
def save_model(self, request, obj, form, change):
obj.design_manager = request.user
super().save_model(request, obj, form, change)
Related
I want to make a queryset on a field in an inline formset.. I have Inovice and Product models and InvoiceDetails model to link the manytomany relation between them.
here are the models:
class Invoices(models.Model):
"""The Invoice Creation Class."""
invoice_number = models.CharField(
_('invoice_number'), max_length=100, unique=True, null=True)
....
class Products(models.Model):
"""Product Creation Class."""
company = models.ForeignKey(Company, default=1)
barcode = models.CharField(_('barcode'), max_length=200, null=True)
....
class InvoiceDetail(models.Model):
invoice = models.ForeignKey(Invoices, related_name='parent_invoice')
product = models.ForeignKey(Products, related_name='parent_product')
quantity_sold = models.IntegerField(_('quantity_sold'))
...
when crearting an invoice i have inline formsets for the products which create an invoice details for every product.. now i want to filter the products that appear for the user to choose from them by the company. i searched a lot on how to override the queryset of inline formsets but found nothing useful for my case.
my forms:
class InvoiceForm(forms.ModelForm):
class Meta:
model = Invoices
fields = ('customer', 'invoice_due_date', 'discount', 'type')
def __init__(self, *args, **kwargs):
self.agent = kwargs.pop('agent')
super(InvoiceForm, self).__init__(*args, **kwargs)
def clean_customer(self):
.....
def clean(self):
......
class BaseDetailFormSet(forms.BaseInlineFormSet):
def clean(self):
......
DetailFormset = inlineformset_factory(Invoices,
InvoiceDetail,
fields=('product', 'quantity_sold'),
widgets= {'product': forms.Select(
attrs={
'class': 'search',
'data-live-search': 'true'
})},
formset=BaseDetailFormSet,
extra=1)
and use it in the views like that:
if request.method == 'POST':
invoice_form = InvoiceForm(
request.POST, request.FILES, agent=request.user)
detail_formset = DetailFormset(
request.POST)
.......
else:
invoice_form = InvoiceForm(agent=request.user)
detail_formset = DetailFormset()
so, how can it filter the products that show in detail_formset by company?
I solved it be passing the user to init and loop on forms to override the queryset.
def __init__(self, *args, **kwargs):
self.agent = kwargs.pop('agent')
super(BaseDetailFormSet, self).__init__(*args, **kwargs)
for form in self.forms:
form.fields['product'].queryset = Products.objects.filter(company=self.agent.company)
in views:
detail_formset = DetailFormset(agent=request.user)
I start to create REST API for my web-application with Django and Django rest framework and I need one logic problem.
There are entities Instruction and Tag. The user visit my service and create self Instruction and add exists Tag OR new Tag for it.
I created my model seriallizer class with using PrimaryKeyRelatedField for relation Instruction<->Tag. But if I do POST for a new Instruction with new Tag I got error: "Invalid pk \"tagname\" - object does not exist.".
I solved this problem with the overriding of the to_internal_value method in my field class.
What is the best practice for solving this problem? It seems to me this problem is typical for web and REST API.
My models:
class Tag(Model):
name = CharField(max_length=32, verbose_name=_("Name"),
unique=True, validators=[alphanumeric], primary_key=True)
def __str__(self):
return self.name
class Instruction(Model):
user = ForeignKey(settings.AUTH_USER_MODEL,
related_name='instructions',
on_delete=CASCADE,
blank=False, null=False,
verbose_name=_("User"))
title = CharField(max_length=256,
verbose_name=_("Title"),
blank=False, null=False)
created_datetime = DateTimeField(verbose_name=_("Creation time"), editable=False)
modified_datetime = DateTimeField(
verbose_name=_("Last modification time"), blank=False, null=False)
tags = ManyToManyField(Tag,
related_name="instructions",
verbose_name=_("Tags"))
class Meta:
ordering = ['-created_datetime']
# singular_name = _("")
def save(self, force_insert=False, force_update=False, using=None,
update_fields=None):
n = now()
if self.id is None:
self.created_datetime = n
self.modified_datetime = n
super(Instruction, self).save(force_insert, force_update, using, update_fields)
def __str__(self):
return self.title
my serializers:
class TagSerializer(serializers.ModelSerializer):
class Meta:
model = Tag
fields = ('name',)
class InstructionSerializer(serializers.ModelSerializer):
tags = PrimaryKeyCreateRelatedField(many=True, queryset=Tag.objects.all())
author = serializers.SerializerMethodField()
def get_author(self, obj):
return obj.user.username
class Meta:
model = Instruction
fields = ('id', 'user', 'title', 'created_datetime', 'modified_datetime', 'tags', 'author')
read_only_fields = ('modified_datetime',)
I created new field class class PrimaryKeyCreateRelatedField and overrided to_internal_value method for creating the new Tag object instead raising with message 'does_not_exist':
PrimaryKeyCreateRelatedField(serializers.PrimaryKeyRelatedField):
def to_internal_value(self, data):
if self.pk_field is not None:
data = self.pk_field.to_internal_value(data)
try:
return self.get_queryset().get(pk=data)
except ObjectDoesNotExist:
# self.fail('does_not_exist', pk_value=data)
return self.get_queryset().create(pk=data)
except (TypeError, ValueError):
self.fail('incorrect_type', data_type=type(data).__name__)
my view:
class InstructionViewSet(viewsets.ModelViewSet):
queryset = Instruction.objects.all()
serializer_class = InstructionSerializer
permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
def create(self, request, *args, **kwargs):
data = dict.copy(request.data)
data['user'] = self.request.user.pk
serializer = InstructionSerializer(data=data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
Update
models.py
alphanumeric = RegexValidator(r'^[0-9a-zA-Z]*$',
_('Only alphanumeric characters are allowed.'))
class Tag(Model):
name = CharField(max_length=32, verbose_name=_("Name"),
unique=True, validators=[alphanumeric], primary_key=True)
def __str__(self):
return self.name
class Step(PolymorphicModel):
instruction = ForeignKey(Instruction,
verbose_name=_("Instruction"),
related_name='steps',
blank=False, null=False,
on_delete=CASCADE)
position = PositiveSmallIntegerField(verbose_name=_("Position"), default=0)
description = TextField(verbose_name=_("Description"),
max_length=2048,
blank=False, null=False)
class Meta:
verbose_name = _("Step")
verbose_name_plural = _("Steps")
ordering = ('position',)
unique_together = ("instruction", "position")
def __str__(self):
return self.description[:100]
class Instruction(Model):
user = ForeignKey(settings.AUTH_USER_MODEL,
related_name='instructions',
on_delete=CASCADE,
blank=False, null=False,
verbose_name=_("User"))
title = CharField(max_length=256,
verbose_name=_("Title"),
blank=False, null=False)
created_datetime = DateTimeField(verbose_name=_("Creation time"), editable=False)
modified_datetime = DateTimeField(
verbose_name=_("Last modification time"), blank=False, null=False)
tags = ManyToManyField(Tag,
related_name="instructions",
verbose_name=_("Tags"))
# thumbnail = #TODO: image field
class Meta:
ordering = ['-created_datetime']
# singular_name = _("")
def save(self, force_insert=False, force_update=False, using=None,
update_fields=None):
n = now()
if self.id is None:
self.created_datetime = n
self.modified_datetime = n
super(Instruction, self).save(force_insert, force_update, using, update_fields)
def __str__(self):
return self.title
views.py
class InstructionViewSet(viewsets.ModelViewSet):
queryset = Instruction.objects.all()
permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
def get_serializer_class(self):
"""Return different serializer class for different action."""
if self.action == 'list':
return InstructionSerializer
elif self.action == 'create':
return InstructionCreateSerializer
serialiers.py
class PrimaryKeyCreateRelatedField(serializers.PrimaryKeyRelatedField):
def to_internal_value(self, data):
if self.pk_field is not None:
data = self.pk_field.to_internal_value(data)
try:
return self.get_queryset().get(pk=data)
except ObjectDoesNotExist:
# self.fail('does_not_exist', pk_value=data)
return self.get_queryset().create(pk=data)
except (TypeError, ValueError):
self.fail('incorrect_type', data_type=type(data).__name__)
class InstructionCreateSerializer(serializers.ModelSerializer):
tags = PrimaryKeyCreateRelatedField(many=True, queryset=Tag.objects.all())
steps = InstructionStepSerializer(many=True)
user = serializers.HiddenField(default=serializers.CurrentUserDefault())
class Meta:
model = Instruction
fields = ('id', 'user', 'title', 'created_datetime', 'modified_datetime', 'tags', 'steps')
read_only_fields = ('modified_datetime',)
def create(self, validated_data):
tags_data = validated_data.pop('tags')
steps_data = validated_data.pop('steps')
# NOTE: tags need add after creation of the Instruction object otherwise we will got exception:
# "needs to have a value for field "id" before this many-to-many relationship can be used."
instruction = Instruction.objects.create(**validated_data)
for tag in tags_data:
instruction.tags.add(tag)
for step in steps_data:
Step.objects.create(instruction=instruction,
description=step['description'],
position=step['position'])
return instruction
class InstructionSerializer(serializers.ModelSerializer):
tags = serializers.StringRelatedField(many=True)
author = serializers.SerializerMethodField()
steps = InstructionStepSerializer(many=True)
def get_author(self, obj):
return obj.user.username
class Meta:
model = Instruction
fields = ('id', 'user', 'title', 'created_datetime', 'modified_datetime', 'tags', 'author', 'steps')
read_only_fields = ('modified_datetime',)
In my case to solve the problem I need to override the method run_validation. That allow make check of tags and create their (if not exists) before validation.
class InstructionCreateSerializer(serializers.ModelSerializer):
steps = InstructionStepSerializer(many=True)
user = serializers.HiddenField(default=serializers.CurrentUserDefault())
class Meta:
model = Instruction
fields = ('title', 'created_datetime', 'modified_datetime', 'tags', 'steps', 'id', 'user')
read_only_fields = ('modified_datetime',)
def run_validation(self, data=serializers.empty):
if 'tags' in data:
for tag in data['tags']:
Tag.objects.get_or_create(name=tag)
return super(InstructionCreateSerializer, self).run_validation(data)
def create(self, validated_data):
tags_data = validated_data.pop('tags')
steps_data = validated_data.pop('steps')
# NOTE: tags need add after creation of the Instruction object otherwise we will got exception:
# "needs to have a value for field "id" before this many-to-many relationship can be used."
instruction = Instruction.objects.create(**validated_data)
for tag in tags_data:
instruction.tags.add(tag)
for step in steps_data:
Step.objects.create(instruction=instruction,
description=step['description'],
position=step['position'])
return instruction
Apart from the answers given by #YPCrumble and #SijanBhandari, I just had to comment on something in your code.
In the models.py, you have overridden the save method for adding created_at and modified_on. For that you could just add
created_at = models.DateTimeField(auto_now_add=True)
modified_on = DateTimeField (auto_now=True)
The auto_now_add option sets when the object is created for the first time.
It's not editable. The auto_now setting sets whenever the object is saved, ie, whenever object.save() method is called upon.
These usually are used for timestamping the objects for future references.
Why write so many lines, when you could do this on just 2 lines of code.
Just a heads up though!!
For further details, go to the documentation here
In "regular" Django you usually want to create your model instance in the form's save method, not the view. DRF is similar, in that you want to create your model instances in the serializer's create or update methods. The reason for this is that if you need to add a new endpoint to your API you can reuse the serializer and would not have to write duplicate code creating or updating your model instance.
Here's how I'd refactor your code:
Remove the entire create method from your ModelViewSet - you don't need to override that.
Remove the custom PrimaryKeyCreateRelatedField - you just need a PrimaryKeyRelatedField
Add two methods to your serializer - create and update:
In the create method, create your tag objects before saving the instruction object like you can see in the DRF docs. You can get the current user like you were doing in your view via self.context['request'].user in this create method. So you might create the Instruction like Instruction.objects.create(user=self.context['request'].user, **validated_data) and then loop through the tags (like they do for tracks in the docs) to add them to the Instruction.
The docs don't have an example update method but essentially your update method also takes an instance parameter for the existing instruction. See this answer from the creator of DRF for more details
The best way would be sort out everything at your CREATE method of the view.
I believe you tags will be sent from your front-end to the back-end at the format of
[ 1,
{'name': "TEST"},
{'name': 'TEST2'}
]
Here '1' is the existing tag id and 'TEST' and 'TEST2' are the two new tags inserted by
the user. Now you can change your CREATE method as follows:
class InstructionViewSet(viewsets.ModelViewSet):
queryset = Instruction.objects.all()
serializer_class = InstructionSerializer
permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
def create(self, request, *args, **kwargs):
data = dict.copy(request.data)
data['user'] = self.request.user.pk
# MODIFICATION.....
tags = self.request.get('tags', None)
tag_list = []
if tags:
for tag in tags:
if isinstance(tag, dict):
new_tag = Tag.objects.create(name=tag['name'])
tag_list.append(new_tag.id)
else:
tag_list.append(int(tag))
data = {
'title': ....
'tags': tag_list,
'user': ...
'author': ...
......
}
serializer = InstructionSerializer(data=data)
I hope it will be helpful for you.
I have some issue to solve with editing profile form of django-userena. I want to use EditProfileFormExtra (it is an extension of userena EditProfileForm) to edit related extra fields (choice fields) for Settings model, which are in OneToOne relation with Accounts aplication, a field: default_house_system.
Saving is ok, but initial value of default_house_system does not work, always display first value of tuple. I want do this without including any code in original files in Django-Userena.
Models:
class UserProfile(UserenaBaseProfile):
user = models.OneToOneField(User,
unique=True,
verbose_name='user',
related_name='user_profile')
settings = models.OneToOneField(Settings, unique=True, verbose_name="Ustawienia", blank=True, null=True)
is_virtual = models.BooleanField(default=False)
class Settings(models.Model):
points = models.IntegerField(default=0)
default_house_system = models.CharField(choices=HOUSE_SYSTEMS, max_length=24, default="Placidus")
Userena Form:
class EditProfileForm(forms.ModelForm):
""" Base form used for fields that are always required """
first_name = forms.CharField(label=_(u'First name'),
max_length=30,
required=False)
last_name = forms.CharField(label=_(u'Last name'),
max_length=30,
required=False)
def __init__(self, *args, **kw):
super(EditProfileForm, self).__init__(*args, **kw)
# Put the first and last name at the top
new_order = self.fields.keyOrder[:-2]
new_order.insert(0, 'first_name')
new_order.insert(1, 'last_name')
self.fields.keyOrder = new_order
class Meta:
model = get_profile_model()
exclude = ['user']
def save(self, force_insert=False, force_update=False, commit=True):
profile = super(EditProfileForm, self).save(commit=commit)
# Save first and last name
user = profile.user
user.first_name = self.cleaned_data['first_name']
user.last_name = self.cleaned_data['last_name']
user.save()
I replace an urls definition, putting into accounts/urls.py:
url(r'^(?P<username>[\.\w]+)/edit/$',
'userena.views.profile_edit',
{'edit_profile_form': EditProfileFormExtra},
name='userena_profile_edit'),
... and here is definition of EditProfileFormExtra:
class EditProfileFormExtra(EditProfileForm):
default_house_system = forms.ChoiceField(choices=HOUSE_SYSTEMS)
def __init__(self, *args, **kw):
super(EditProfileFormExtra, self).__init__(*args, **kw)
new_order = self.fields.keyOrder[:-1]
new_order.insert(3, 'default_house_system')
self.fields.keyOrder = new_order
class Meta:
model = get_profile_model()
fields = ['mugshot', 'default_house_system']
def save(self, force_insert=False, force_update=False, commit=True):
profile = super(EditProfileFormExtra, self).save(commit=commit)
settings_profile = profile.settings
settings_profile.default_house_system = self.cleaned_data['default_house_system']
settings_profile.save()
profile.save()
return profile
Now IMPORTANT stuff. If I put:
'default_house_system': user.user_profile.settings.default_house_system
into dict in userena/views.py/profile_edit method (it is class-based view):
user_initial = {'first_name': user.first_name,
'last_name': user.last_name,
'default_house_system': user.user_profile.settings.default_house_system}
it is work fine! But I do not want to including any code in original files in Django-Userena.
Is there another way instead of copying whole profile_edit method from userena/views.py to my app accounts/views.py?
I would appreciate any tips or advices, thank you.
I have some models like that:
class BaseModel(models.Model):
created_by = models.ForeignKey(User, related_name="%(app_label)s_%(class)s_created")
created_date = models.DateTimeField(_('Added date'), auto_now_add=True)
last_updated_by = models.ForeignKey(User, related_name="%(app_label)s_%(class)s_updated")
last_updated_date = models.DateTimeField(_('Last update date'), auto_now=True)
class Meta:
abstract = True
class Image(BaseModel):
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = generic.GenericForeignKey('content_type', 'object_id')
name = models.CharField(_('Item name'), max_length=200, blank=True)
image = models.ImageField(_('Image'), upload_to=get_upload_path)
def save(self, *args, **kwargs):
if self.image and not GALLERY_ORIGINAL_IMAGESIZE == 0:
width, height = GALLERY_ORIGINAL_IMAGESIZE.split('x')
super(Image, self).save(*args, **kwargs)
filename = os.path.join( settings.MEDIA_ROOT, self.image.name )
image = PILImage.open(filename)
image.thumbnail((int(width), int(height)), PILImage.ANTIALIAS)
image.save(filename)
super(Image, self).save(*args, **kwargs)
class Album(BaseModel):
name = models.CharField(_('Album Name'), max_length=200)
description = models.TextField(_('Description'), blank=True)
slug = models.SlugField(_('Slug'), max_length=200, blank=True)
status = models.SmallIntegerField(_('Status'),choices=ALBUM_STATUSES)
images = generic.GenericRelation(Image)
I use BaseModel abstract model for my all models to track save and update logs. I can use ModelAdmin class to set user fields automatically:
class BaseAdmin(admin.ModelAdmin):
def save_model(self, request, obj, form, change):
if not change:
obj.created_by = request.user
obj.last_updated_by = request.user
obj.save()
class AlbumAdmin(BaseAdmin):
prepopulated_fields = {"slug": ("name",)}
list_display = ('id','name')
ordering = ('id',)
That works. All BaseAdmin fields are filled automatically. But I want to add Images to Albums by Inline. So, I change my admin.py like that:
from django.contrib.contenttypes import generic
class ImageInline(generic.GenericTabularInline):
model = Image
extra = 1
class AlbumAdmin(BaseAdmin):
prepopulated_fields = {"slug": ("name",)}
list_display = ('id','name')
ordering = ('id',)
inlines = [ImageInline,]
When I save page, I get an error: gallery_image.created_by_id may not be NULL on first super(Image, self).save(*args, **kwargs) row of Image model save method. I know it's because of GenericTabularInline class doesn't have a "save_model" method to override.
So, the question is, how can I override save method and set current user on InlineModelAdmin classes?
I have found a solution on another question: https://stackoverflow.com/a/3569038/198062
So, I changed my BaseAdmin model class like that, and it worked like a charm:
from models import BaseModel
class BaseAdmin(admin.ModelAdmin):
def save_model(self, request, obj, form, change):
if not change:
obj.created_by = request.user
obj.last_updated_by = request.user
obj.save()
def save_formset(self, request, form, formset, change):
instances = formset.save(commit=False)
for instance in instances:
if isinstance(instance, BaseModel): #Check if it is the correct type of inline
if not instance.created_by_id:
instance.created_by = request.user
instance.last_updated_by = request.user
instance.save()
Note that, you must extend same abstract class for the ModelAdmin that contains the inlines to use this solution. Or you can add that save_formset method to ModelAdmin that contains the inline specifically.
I wanted the user to be set on all my models no matter where/how they were manipulated. It took me forever to figure it out, but here's how to set it on any model using middleware:
"""Add user created_by and modified_by foreign key refs to any model automatically.
Almost entirely taken from https://github.com/Atomidata/django-audit-log/blob/master/audit_log/middleware.py"""
from django.db.models import signals
from django.utils.functional import curry
class WhodidMiddleware(object):
def process_request(self, request):
if not request.method in ('GET', 'HEAD', 'OPTIONS', 'TRACE'):
if hasattr(request, 'user') and request.user.is_authenticated():
user = request.user
else:
user = None
mark_whodid = curry(self.mark_whodid, user)
signals.pre_save.connect(mark_whodid, dispatch_uid = (self.__class__, request,), weak = False)
def process_response(self, request, response):
signals.pre_save.disconnect(dispatch_uid = (self.__class__, request,))
return response
def mark_whodid(self, user, sender, instance, **kwargs):
if instance.has_attr('created_by') and not instance.created_by:
instance.created_by = user
if instance.has_attr('modified_by'):
instance.modified_by = user
In addition to mindlace's answer; when the created_by field happens to have null=True the not instance.created_by gives an error. I use instance.created_by_id is None to avoid this.
(I'd rather have posted this as a comment to the answer, but my current reputation doesn't allow...)
Recently I downloaded the Pinax project 0.7 to see what I can apply to my own project. Particularly, I ran Pinax and looked at the Bookmarks app that Pinax applied to itself. I copied the Bookmark apps and its dependencies to my own. However, Pinax runs on Django 1.0.4 and mine was 1.2.4 and there are some error in the form validation. Following are snippets from the bookmarks app:
class BookmarkInstance(models.Model):
bookmark = models.ForeignKey(Bookmark, related_name="saved_instances", verbose_name=_('bookmark'))
user = models.ForeignKey(User, related_name="saved_bookmarks", verbose_name=_('user'))
saved = models.DateTimeField(_('saved'), default=datetime.now)
description = models.CharField(_('description'), max_length=100)
note = models.TextField(_('note'), blank=True)
tags = TagField()
Form:
class BookmarkInstanceForm(forms.ModelForm):
url = forms.URLField(label = "URL", verify_exists=True, widget=forms.TextInput(attrs={"size": 40}))
description = forms.CharField(max_length=100, widget=forms.TextInput(attrs={"size": 40}))
redirect = forms.BooleanField(label="Redirect", required=False)
tags = TagField(label="Tags", required=False)
def __init__(self, user=None, *args, **kwargs):
self.user = user
super(BookmarkInstanceForm, self).__init__(*args, **kwargs)
# hack to order fields
self.fields.keyOrder = ['url', 'description', 'note', 'tags', 'redirect']
def clean(self):
if 'url' not in self.cleaned_data:
return
if BookmarkInstance.objects.filter(bookmark__url=self.cleaned_data['url'], user=self.user).count() > 0:
raise forms.ValidationError(_("You have already bookmarked this link."))
return self.cleaned_data
def save(self, commit=True):
self.instance.url = self.cleaned_data['url']
return super(BookmarkInstanceForm, self).save(commit)
class Meta:
model = BookmarkInstance
The params passed in were (<QueryDict: {u'url': [u'amazon.com'], u'note': [u'foo'], u'description': [u'bar'], u'tags': [u'']}>,) but did not cause a model validation error in 1.0.4. So, how can I make minimal adjustments in my view, possibly to skip the model validation to accommodate for this difference?