django 'ModelFormOptions' object has no attribute 'virtual_fields' - python

models.py
class Products(models.Model):
company = models.ForeignKey(Companys)
name = models.CharField(unique = True, max_length = 50)
description = models.CharField(unique = True, max_length = 500)
price = models.PositiveIntegerField()
in_stock = models.BooleanField(default = True)
crated = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.name
forms.py
class ProductForm(forms.ModelForm):
class Meta:
model = Products
fields = '__all__'
name = forms.CharField()
description = forms.CharField(widget = forms.Textarea, )
company = forms.ModelChoiceField(queryset = Companys.objects.all(), label = 'Company')
in_stock = forms.BooleanField(initial = True)
price = forms.IntegerField()
views.py
class ProductCreate(CreateView, ProductEditMixin):
model = ProductForm
template_name = 'store/product_add.html'
fields = '__all__'
def post(self, request, *args, **kwargs):
self.success_url = reverse('get_context_data', kwargs = {'pk' : Companys.objects.first().id})
return super(ProductCreate, self).post(request, *args, **kwargs)
Please help me. Without forms code work. But with forms i have AttributeError: 'ModelFormOptions' object has no attribute 'virtual_fields' error

ProductForm is a form, not a model. It should go in the view's form_class attribute, not model.
(I also don't understand why your ProductForm uses the Company model rather than Product, but never mind.)

Related

search models in django admin

There is a model of orders, where new orders with information fall, photo1
Part of the information is the model of sneakers, sometimes these sneakers need to be corrected, now this is done in the form of TabularInline, photo2 and photo3, there are a lot of sneakers and it takes a very long time to scroll through this drop-down list, is there a way to make a search by entering text, like search_fields?
admin.py
class SuitItemInOderInline(admin.TabularInline):
model = SuitInOder
extra = 0
class SuitOrderAdmin(admin.ModelAdmin):
inlines = [SuitItemInOderInline]
list_display = ('inst', 'created')
list_filter = ('status',)
class Meta:
model = OrderSuit
admin.site.register(OrderSuit, SuitOrderAdmin)
models.py
class SuitInOder(models.Model):
order = models.ForeignKey(OrderSuit, on_delete=models.CASCADE, verbose_name='Заказ', related_name='ordered_item')
item = models.ForeignKey(SuitItem, on_delete=models.CASCADE, verbose_name='Костюм', related_name='spb_item')
def __str__(self):
return f'{self.order} | {self.item.model.id} --- {self.item}'
def save(self, *args, **kwargs):
not_available = ['new', 'in_progress', 'completed']
if self.order.status in not_available:
self.item.in_stock = False
else:
self.item.in_stock = True
self.item.save(force_update=True)
super(SuitInOder, self).save(*args, **kwargs)
def delete(self):
self.item.in_stock = True
self.item.save(force_update=True)
super(SuitInOder, self).delete()
class Meta:
verbose_name = 'Костюм в заказе'
verbose_name_plural = 'Костюмы в заказе'
class OrderSuit(models.Model):
NEW = 'new'
IN_PROGRESS = 'in_progress'
COMPLETED = 'completed'
CANCELED = 'canceled'
choises = (
(NEW, 'Новый'),
(IN_PROGRESS, 'В работе'),
(COMPLETED, 'Выполнен'),
(CANCELED, 'Отменен')
)
name = models.CharField(max_length=32, verbose_name='Имя', blank=True)
phone_number = models.CharField(max_length=13, verbose_name='Номер телефона')
inst = models.CharField(max_length=64)
address = models.CharField(max_length=64, verbose_name='Адресс')
deliver_time = models.CharField(max_length=64, null=True, verbose_name='Время доставки')
comment = models.TextField(verbose_name='Комментарий')
status = models.CharField(max_length=32, choices=choises, null=True, verbose_name='Статус заказа')
created = models.DateTimeField(verbose_name='Время заказа', editable=False, default=datetime.now()+timedelta(hours=3))
def __str__(self):
return f'{self.name}'
def save(self, *args, **kwargs):
self.created = datetime.now() +timedelta(hours=3)
if self.id:
items = self.ordered_item.all()
for item in items:
item.save()
super(OrderSuit, self).save(*args, **kwargs)
class Meta:
verbose_name = 'Заказ костюма'
verbose_name_plural = 'Заказы костюмов'
If these are foreignKey fields, use raw_id_fields so you can search them in another window and it will make the load faster.
Photo1
need to use autocomplete_fields and register a new model for example SuitSearch, which has a search_fields which refers to model__name
admin.py
class SuitSearch(admin.ModelAdmin):
search_fields = ('model__name',)
class Meta:
model = SuitItem
admin.site.register(SuitItem, SuitSearch)
class SuitItemInOderInline(admin.TabularInline):
model = SuitInOder
autocomplete_fields = ('item',)
extra = 0
class SuitOrderAdmin(admin.ModelAdmin):
inlines = [SuitItemInOderInline]
list_display = ('inst', 'created')
list_filter = ('status',)
class Meta:
model = OrderSuit
admin.site.register(OrderSuit, SuitOrderAdmin)

How to use accessors in Django?

I've read previous Q and docs, however still not able to make it work..
I have the following models:
class Process(models.Model):
class Meta:
verbose_name_plural = "Processes"
name = models.CharField(max_length=120)
description = models.CharField(max_length=4)
parent_process = models.ForeignKey('self', related_name="parent_process+", on_delete=models.PROTECT, blank=True, null=True, verbose_name="parent process")
process_activities = models.CharField(max_length = 2048, blank=True, verbose_name="process activites")
owner = models.ForeignKey(User, related_name="owner+", on_delete=models.PROTECT, blank=True, null=True, verbose_name="owner")
def __str__(self):
return "{}".format(self.name)
class ControlTest(models.Model):
history = AuditlogHistoryField()
name = models.CharField(max_length=120)
description = models.CharField(max_length=120)
Now I want to use an accessor to access the name of the process and display in a table (tables.py):
class controltestTable(tables.Table):
class Meta:
hoofdproces = tables.Column(accessor='process.name')
model = ControlTest
fields = ['id',"name", "hoofdproces", "sub_process", 'description', 'control', 'delegate', 'owner', 'reviewer1', 'reviewer2', 'reviewer1_r', 'reviewer2_r', 'delegate_r',
'owner_r', 'reviewer_status', 'status', 'history', 'comments', 'review_comments', 'due_date', 'review1_due_date', 'review2_due_date', 'documentation']
template_name = "django_tables2/bootstrap-responsive.html"
Views.py:
class ControlTestView(SingleTableView, FormView, SingleTableMixin, FilterView):
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
queryset = kwargs.pop('object_list', None)
if queryset is None:
self.object_list = self.model.objects.all()
context['controltests'] = ControlTest.objects.all()
return context
def post(self, request, *args, **kwargs):
form = self.get_form()
print(form)
if form.is_valid():
instance = form.save(commit=True)
instance.save()
print('valid')
return self.form_valid(form)
else:
print(form.errors)
return self.form_invalid(form)
template_name = "control/ControlTest.html"
model = ControlTest
form_class = ControlTestForm
table_class = controltestTable
success_url = reverse_lazy('controltest')
However, nothing gets displayed in the hoofdproces column :(
How is that possible? What am I doing wrong?
Please help!

Django Class based UpdateView with Form for Multiple Uploaded Files

I have two questions in regards to the problem I am currently facing:
Is it best practice in django to overwrite the post method in the CreateView? If it isn't do you write a form _valid function on the CategoryFullForm or in the CreateView and how would it look? The CreateView currently works great, but want to make sure there isn't a better way to do this.
If this is best practice, how would you override the get function in the UpdateView so you would be able to edit the files that relate to the instance being uploaded and even add an additional File? Open to other ways to accomplish this task as well.
models.py
############ CATEGORY MODEL ################
class Category(models.Model):
category_id = models.AutoField(primary_key=True)
name = models.CharField(max_length=100, null=True, blank=True)
est_pr_sqft = models.FloatField(blank=True)
est_duration = models.IntegerField(blank=True)
preceding_job = models.CharField(max_length=100, blank=True)
category_notes = models.CharField(max_length=250, blank=True)
category_slug = models.SlugField(max_length=100, unique=True, null=False)
author = models.ForeignKey(User, on_delete=models.CASCADE, default=1)
date_posted = models.DateTimeField(auto_now_add=True)
date_modified = models.DateTimeField(auto_now=True)
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse('category-detail', kwargs={'slug': self.category_slug})
def save(self, *args, **kwargs):
if not self.category_slug:
self.category_slug = slugify(self.name)
return super().save(*args, **kwargs)
class CategoryFiles(models.Model):
category_id = models.ForeignKey(Category, on_delete=models.CASCADE)
document = models.FileField(upload_to="attachments",null=True,blank=True)
uploaded_date = models.DateTimeField(auto_now_add=True)
modified_date = models.DateTimeField(auto_now=True)
def delete(self, *args, **kwargs):
self.document.delete()
return super().delete(*args, **kwargs)
forms.py
class CategoryForm(forms.ModelForm):
class Meta:
model = Category
fields = ['name', 'est_pr_sqft', 'est_duration', 'preceding_job', 'category_notes']
class CategoryFullForm(CategoryForm):
files = forms.FileField(widget=forms.ClearableFileInput(attrs={'multiple': True}),required=False)
class Meta(CategoryForm.Meta):
fields = CategoryForm.Meta.fields + ['files']
views.py
####### CATEGORY VIEWS ########
class CategoryListView(LoginRequiredMixin, ListView):
model = Category
template_name = 'ProjectManagementApp/PM-Category-List.html'
context_object_name = 'categories'
slug_field = 'project_slug'
success_url = reverse_lazy('Category-list')
class CategoryDetailView(LoginRequiredMixin, DetailView):
model = Category
template_name = 'ProjectManagementApp/PM-Category-Detail.html'
slug_field = 'category_slug'
def get_context_data(self, **kwargs):
context = super(CategoryDetailView, self).get_context_data(**kwargs)
context['files'] = CategoryFiles.objects.all()
#context['photos'] = CategoryPhotos.objects.all()
return context
class CategoryCreateView(LoginRequiredMixin, CreateView):
model = Category
form_class = CategoryFullForm
template_name = 'ProjectManagementApp/PM-Category-Create.html' # Replace with your template.
#success_url = reverse_lazy('category-detail')
slug_field = 'category_slug'
def post(self, request, *args, **kwargs):
form_class = self.get_form_class()
form = self.get_form(form_class)
files = request.FILES.getlist('files')
if form.is_valid():
author = request.user
name = form.cleaned_data['name']
est_pr_sqft = form.cleaned_data['est_pr_sqft']
est_duration = form.cleaned_data['est_duration']
preceding_job = form.cleaned_data['preceding_job']
category_notes = form.cleaned_data['category_notes']
category_obj = Category.objects.create(name=name,est_pr_sqft=est_pr_sqft,est_duration=est_duration,preceding_job=preceding_job,category_notes=category_notes,author=author)
for f in files:
CategoryFiles.objects.create(category_id=category_obj,document=f)
return HttpResponseRedirect(reverse_lazy('Category-list'))
else:
return self.form_invalid(form)
class CategoryUpdateView(LoginRequiredMixin, UpdateView): #UserPassesTestMixin - makes sure user who made entry is only one who can update it.
model = Category
form_class = CategoryFullForm
template_name = 'ProjectManagementApp/PM-Category-Create.html' # Replace with your template.
slug_field = 'category_slug'
success_url = reverse_lazy('Category-list')
def post(self, request, *args, **kwargs):
form_class = self.get_form_class()
form = self.get_form(form_class)
files = request.FILES.getlist('files')
if form.is_valid():
author = request.user
name = form.cleaned_data['name']
est_pr_sqft = form.cleaned_data['est_pr_sqft']
est_duration = form.cleaned_data['est_duration']
preceding_job = form.cleaned_data['preceding_job']
category_notes = form.cleaned_data['category_notes']
category_obj = Category.objects.create(name=name,est_pr_sqft=est_pr_sqft,est_duration=est_duration,preceding_job=preceding_job,category_notes=category_notes,author=author)
for f in files:
CategoryFiles.objects.create(category_id=category_obj,document=f)
return HttpResponseRedirect(reverse_lazy('Category-list'))
else:
return self.form_invalid(form)
#
# #Doesnt allow you to update other users post
# #def test_func(self):
# # project = self.get_object()
# # if self.request.user == post.author:
# # return True
# # return False
#
#
def form_valid(self,form):
form.instance.author = self.request.user
return super().form_valid(form)
class CategoryDeleteView(LoginRequiredMixin, DeleteView): #UserPassesTestMixin - makes sure user who made entry is only one who can update it.
model = Category
template_name = 'ProjectManagementApp/PM-Category-Delete.html'
slug_field = 'category_slug'
success_url = reverse_lazy('Category-list')
#Doesnt allow you to delete other users post
#def test_func(self):
# project = self.get_object()
# if self.request.user == post.author:
# return True
# return False
If the urls.py/admin.py are needed am happy to provide, but don't think they are needed, as well as any of the html files.

Setting value of Django M2M through relationship via ModelForm

I am working on a set of product / category relationships in a Django application.
A product can belong to any category and needs to be ordered within that category, I am trying to do this using a Many to Many relationship with a "through=" option.
When a POST request is made via Ajax it takes the form of b'ordered_products=4&ordered_products=5', I received an error straight after the forms __init__ call that "5 is not one of the available choices" where 5 is the valid id of anOrderedCategoryManagedProduct object.
models.py
class Category(models.Model):
name = models.CharField(max_length=128)
slug = models.SlugField(max_length=128, unique=True)
class Product(models.Model):
name = models.CharField(max_length=128)
category_management = models.ManyToManyField(
Category,
related_name="category_managed_products",
through="OrderedCategoryManagedProduct",
blank=True,
verbose_name="Category Management",
)
class OrderedCategoryManagedProduct(SortableModel):
category = models.ForeignKey(
Category, on_delete=models.CASCADE, related_name="cm_products"
)
product = models.ForeignKey(
Product, on_delete=models.CASCADE, related_name="cm_categories"
)
class Meta:
ordering = ["sort_order"]
def get_ordering_queryset(self):
return self.product.category_management()
class SortableModel(models.Model):
sort_order = models.IntegerField(db_index=True, null=True)
class Meta:
abstract = True
views.py
# POST = <QueryDict: {'ordered_products': [5, 4]}>
#staff_member_required
#permission_required("menu.manage_menus")
def ajax_reorder_menu_items(request, category_pk):
category = get_object_or_404(Category, pk=category_pk)
form = ReorderCategoryProductsForm(request.POST, instance=category)
status = 200
ctx = {}
if form.is_valid():
form.save()
elif form.errors:
status = 400
ctx = {"error": form.errors}
return JsonResponse(ctx, status=status)
forms.py
class ReorderCategoryProductsForm(forms.ModelForm):
ordered_products = OrderedModelMultipleChoiceField(
queryset=OrderedCategoryManagedProduct.objects.none()
)
class Meta:
model = Category
fields = ["id"]
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if self.instance:
self.fields["ordered_products"].queryset = self.instance.cm_products.all()
pass
def save(self):
for sort_order, category in enumerate(self.cleaned_data["ordered_products"]):
category.cm_products.sort_order = sort_order
category.save()
return self.instance
class OrderedModelMultipleChoiceField(forms.ModelMultipleChoiceField):
def clean(self, value):
qs = super().clean(value)
keys = list(map(int, value))
return sorted(qs, key=lambda v: keys.index(v.pk))
Big thanks to the #django IRC channel for the help on this, if anyone suffers the same problem the correct code was as follows:
class ReorderCategoryProductsForm(forms.ModelForm):
ordered_products = OrderedModelMultipleChoiceField(
queryset=OrderedCategoryManagedProduct.objects.all()
)
class Meta:
model = Category
fields = ["id"]
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if self.instance:
self.fields["ordered_products"].queryset = self.instance.cm_products.all()
pass
def save(self):
for sort_order, ocmp in enumerate(self.cleaned_data["ordered_products"]):
ocmp.sort_order = sort_order
ocmp.save()
return self.instance

AttributeError with Django Rest nested serializer

I'm following the Django Rest documentation for writing nested serializer but it is giving me attribute error.
Here are my models:
class Objects(TimeStampModel):
projects = models.ForeignKey(Projects,related_name='proj_obj',on_delete=models.CASCADE)
object_name = models.CharField(max_length=50)
object_description = models.TextField()
object_main_table = models.CharField(max_length=50)
object_primary_key = models.CharField(max_length=50)
object_age_field = models.CharField(max_length=50)
date_format = models.CharField(max_length=50)
def __str__(self):
return self.object_name
class ObjectDefinition(TimeStampModel):
ATTRIBUTE = 'Attribute'
RELATION = 'Relation'
TYPE_CHOICES = (
(ATTRIBUTE, 'Attribute'),
(RELATION, 'Relation'),
)
obj = models.ForeignKey(Objects,related_name='obj_def',on_delete=models.CASCADE)
from_table = models.CharField(max_length=50)
from_table_field = models.CharField(max_length=50)
to_table = models.CharField(max_length=50)
to_table_field = models.CharField(max_length=50)
relation_type = models.CharField(max_length=50,choices=TYPE_CHOICES)
relation_sequence = models.CharField(max_length=50)
value_field = models.CharField(max_length=50, blank=True, null=True)
Here is my serializers.py snippet:
class ObjectDefinitionSerializer(serializers.ModelSerializer):
class Meta:
model = ObjectDefinition
fields = ('from_table','from_table_field','to_table','to_table_field','relation_type','value_field')
class ObjectSerializer(serializers.ModelSerializer):
definition = ObjectDefinitionSerializer(many=True)
object_description = serializers.CharField(required=False, allow_null=True, allow_blank=True
)
class Meta:
model = Objects
fields = ('projects','object_name','object_description','object_main_table','object_primary_key','object_age_field','date_format','definition')
def validate(self, data, *args, **kwargs):
date_format = data.get('date_format')
if date_format not in ['YYYYMMDD', 'DDMMYYYY']:
msg = ('Date format is incorrect')
raise serializers.ValidationError({'error_msg': msg})
return super(ObjectSerializer, self).validate(data, *args, **kwargs)
def create(self, validated_data):
definition_data = validated_data.pop('definition')
obj = Objects.objects.create(**validated_data)
for data in definition_data:
ObjectDefinition.objects.create(obj=obj, **data)
return obj
My views.py:
class CreateObject(CreateAPIView):
permission_classes = (IsAuthenticated,)
serializer_class = ObjectSerializer
After hitting POST, objects.create works fine for both the models but at return obj, it throws me this error:
Exception Value:
Got AttributeError when attempting to get a value for field definition on serializer ObjectSerializer.
The serializer field might be named incorrectly and not match any attribute or key on the Objects instance.
Original exception text was: 'Objects' object has no attribute 'definition'.
What am I missing?
The ObjectDefinition.obj's related_name is obj_def which doesn't match your serializer.
You can fix that by providing the source argument:
definition = ObjectDefinitionSerializer(source='obj_def', many=True)

Categories

Resources