Using Django/html forms can I pass multiple user inputs/values into a list to return/filter a database - django-forms

I would like to filter or return certain data sets with the same "lookup_ref" but I would like to be able to look up multiple "lookup_ref" at one time.
I have searched and I can't find a way of doing this... my thoughts are:
with form checkboxes to see which data sets the user would like to return
use that input to create a list
only return data base entries which have the "lookup_ref" in that list.
have I gone down the wrong route? is there a better way of doing this?
models.pys
class qtable(models.Model):
lookup_ref_choices = (
('gen', 'gen'),
('stolen_car', 'stolen_car'),
('assault', 'assault'),
)
lookup_ref = models.CharField(choices = lookup_ref_choices, max_length=20)
quest = models.CharField(max_length = 500)
order = models.FloatField(default = None)
views.py
def get_user_input(request):
form = Input_Form
context = {'form':form}
return render(request, 'input.html',context )
forms.py
class Input_Form(forms.ModelForm):
class Meta:
model = qtable
fields = "__all__"
exclude = ['quest', 'order']
qtable = forms.ModelMultipleChoiceField(
widget = forms.CheckboxSelectMultiple,
queryset = qtable.objects.all()
)

Related

Django Rest - get related data in M2M relation

I have 2 models:
class Artist(models.Model):
name = models.CharField(max_length=255)
music_type = models.CharField(max_length=50)
class Event(models.Model):
event_name = models.CharField(max_length=255)
description = models.TextField()
place = models.CharField(max_length=50)
longitude = models.DecimalField(max_digits=9, decimal_places=6)
latitude = models.DecimalField(max_digits=9, decimal_places=6)
date = models.DateField()
artists = models.ManyToManyField(Artist)
For every artist I would like to get list of other artists if they have ever been in any event together.
I was able to create close solution, but only for specific artist:
def get_related_artists(request):
artist_id = 2
related_events = Artist.objects.filter(id=artist_id).first().event_set.all()
related_artists_ids = []
for event in related_events:
related_artists_ids = related_artists_ids + list(event.artists
.all()
.values_list('id', flat=True)
.all())
related_artists = Artist.objects\
.filter(id__in=set(related_artists_ids))\
.exclude(id=artist_id)
serializer = ArtistRelatedSerializer(related_artists, many=True)
return JsonResponse(serializer.data, safe=False)
So firstly I get all event where specific artist took part. Later I iterate over this events and get other artist's ids. Another step is to remove duplicated ids and specific artist id. At the end I use serializer to return data.
Serializer looks like:
class ArtistRelatedSerializer(serializers.ModelSerializer):
class Meta:
model = Artist
fields = '__all__'
Unfortunately I think it isn't optimal solution and works only for hardcoded artist's id. I would like to get all artists and for ech list of other artists.
I was thinking about creating loop and iterate over Artist.objects.count() but I couldn't find a solid solution to maintain all this queries.
Is there any other, maybe easier way to solve this solution?
You can solve this issue from Serializer by using SerializerMethodField. Get all events in each Artist, the example below:
class ArtistSerializer(serializers.ModelSerializer):
class Meta:
model = Artist
fields = ('id', 'name', 'music_type', 'events')
events = serializers.SerializerMethodField()
def get_events(self, obj):
events_qs = Event.objects.filter(artists__in=[obj.id])
events = EventSerializer(
events_qs, many=True, context=self.context).data
return events
To avoid the error by the circle imports, you should use import in the function

Cannot generate post request for multiple data

I am trying to take input multiple data object in post request, but getting such error.
non_field_errors: [ Invalid data. Expected a dictionary, but got a list. ]
models.py
class OrderProduct(BaseModel):
product = models.ForeignKey(Product,on_delete=models.CASCADE)
order = models.ForeignKey(Order,on_delete=models.CASCADE)
order_product_price = models.FloatField(blank=False,null=False,default=0) # product may belong to offer do the price
order_product_qty = models.FloatField(default=1)
serializers.py
class OrderProductSerializer(serializers.ModelSerializer):
def update(self,instance,validated_data):
product = self.validated_data.pop('product')
order = self.validated_data.pop('order')
instance.orderproduct_qty =
self.validated_data.get('orderproduct_qty',instance.orderproduct_qty)
instance.product = product
instance.order = order
instance.save()
return instance
class Meta:
model = OrderProduct
fields = '__all__'
views.py
def post(self,request,*args,**kwargs):
if request.data['contact_number'] == '':
request.POST._mutable =True
request.data['contact_number'] = request.user.mobile_number
request.POST._mutable = False
serializer = OrderSerializer(data=request.data,many=isinstance(request.data,list),context={'request': request})
print(serializer)
if serializer.is_valid():
serializer.save(user = request.user,created_by = request.user)
return Response(serializer.data,status=status.HTTP_200_OK)
else:
return Response(serializer.errors,status=status.HTTP_400_BAD_REQUEST)
urls.py
path('orderproduct/',views.OrderProductList.as_view()),
When you call serializer.save(). It's only perform create() action which is only create one and accept dictionary data type only. If you want to save multiple data like that, you will have to override the create function of the serializer class. You can do something similar like this or run a for loop.
serializers.py
def create(self, validate_data):
# Get the data objects you need to perform bulk create
order_products = OrderProduct.objects.bulk_create(validate_data)
return order_products
views.py
if serializer.is_valid(raise_exception=True):
# Replace the serializer.save() by this line to trigger the create method in serializer
self.perform_create(serializer)
return Response(...)

How to search with django_tables2 when using filters

My problem is that I can not take back any data after filtering.
My search fields are : id name and surname. The two last taken from the Client which is foreign key.
filters.py
class OrderFilter(django_filters.FilterSet):
client__name = django_filters.CharFilter(lookup_expr='icontains')
client__surname = django_filters.CharFilter(lookup_expr='icontains')
class Meta:
model = Order
fields = ['id']
models.py
class Order(models.Model):
client = models.ForeignKey(Client,verbose_name=u'Client')
tables.py
class OrderTable(tables.Table):
#CUSTOM COLUMN EXAMPLE
order_id=tables.Column(verbose_name= 'ID Order',orderable=False,empty_values=())
class Meta:
#define the model
model = Order
exclude=('id')
template_name = 'django_tables2/bootstrap.html'
sequence = ("order_id")
views.py
class OrderListView(SingleTableMixin,FilterView):
table_class = OrderTable
model = Order
template_name='orders/orde_list.html'
filterset_class = OrderFilter
def get_context_data(self, **kwargs):
context = super(OrderListView, self).get_context_data(**kwargs)
##filter the orders of the past 4 months.
last_four_months=date.today() - timedelta(120)
object_list=Order.objects.filter(order_created__gte=last_four_months,ays=1).order_by('-invoice_date')
table=self.table_class(object_list)
RequestConfig(self.request).configure(table)
context['table'] = table
#clear all fields
has_filter = any(field in self.request.GET for field in set(self.filterset_class.get_fields()))
context['has_filter'] = has_filter
return context
I noticed that when I create a custom queryset to fill my table, for ex: object_list=Order.objects.filter(order_created__gte=last_four_months).order_by('-invoice_date') the filtering is not working.
When I put nothing it works properly.
Any idea why this happening?
The issue was that I have not defined that my custom queryset must be inserted in the custom table(tables.py) and more important to be filtered by the custom filter (filters.py).
After doing that the custom queryset filtered correctly.
class OrderAYSListView(LoginRequiredMixin,SingleTableMixin,FilterView):
login_url = '/login/'
table_class = OrderTable2
model = Order
template_name='orders/order_ays_list.html'
filterset_class = OrderFilter
def get_context_data(self, **kwargs):
context = super(OrderAYSListView, self).get_context_data(**kwargs)
##filter the orders of the past 4 months.
last_four_months=date.today() - timedelta(120)
object_list=Order.objects.filter(order_created__gte=last_four_months,ays=1).order_by('-invoice_date')
f = self.filterset_class(self.request.GET, queryset=object_list)
context['filter'] = f
table = self.table_class(f.qs)
RequestConfig(self.request).configure(table)
context['table'] = table
#clear all fields
has_filter = any(field in self.request.GET for field in set(self.filterset_class.get_fields()))
context['has_filter'] = has_filter
return context

Django Rest Framework - return reverse foreign key property?

I think this is simple and probably a duplicate, but I cannot figure it out by looking at the documentation.
I have Django models as follows:
class Image(models.Model):
manor = models.ForeignKey(Manor, related_name='image_for_manor')
filename = models.CharField(max_length=30, null=True, blank=True)
class Manor(models.Model):
id = models.IntegerField(primary_key=True)
I want the user to be able to query the Manor and see the related Image. I'd like this JSON to be returned:
{
id: 572,
image: 'my/filepath.png'
}
This is my view:
#api_view(['GET'])
def manor(request, id):
mymanor = Manor.objects.get(id=id)
serializer = ManorSerializer(mymanor)
return JSONResponse(serializer.data)
And these are my serializers:
class ImageFilePathSerializer(serializers.ModelSerializer):
class Meta:
model = Image
fields = ('filename',)
class ManorSerializer(serializers.ModelSerializer):
image = ImageFilePathSerializer(source="image_for_manor")
class Meta:
model = Manor
fields = ('id', 'image')
But this doesn't work: I get an empty dictionary for image. (Even if it weren't empty, I realise it wouldn't be right, because I don't want the image property to be a dictionary: I want it to be a string.)
How can I change this to be correct? I cannot work it out.
As Kevin suggested , why dont you use ImageField which will give you url where your image is uploaded. although if you dont want to do that , here are some changes you have to do to get the result format you wanted.(Following solution assumes that only one image will be for one minor)
views.py ( why dont you ImageFilePathSerializer instead of another one as it also contains all the data you wanted)
#api_view(['GET'])
def manor(request, id):
mymanor = Image.objects.get(manor__id=id)
serializer = ImageFilePathSerializer(mymanor)
return Response(serializer.data)
serializers.py (add Id with filename in ImageFilePathSerializer)
class ImageFilePathSerializer(serializers.ModelSerializer):
class Meta:
model = Image
fields = ('id', 'filename',)
class ManorSerializer(serializers.ModelSerializer):
filename = serializers.ImageField(source="image_for_manor")
class Meta:
model = Manor
fields = ('id', 'filename')

Django Ajax field help

I have a Django application where I'm trying to have a form that populates a drop down dynamically based on a previous dropdown.
simplified Models:
class VehicleMake(models.Model):
make = models.CharField(max_length = 30)
class VehicleModel(models.Model):
model = models.CharField(max_length = 80)
make = models.ForeignKey(VehicleMake)
class Listing(models.Model):
make = models.ForeignKey(VehicleMake)
model = models.ForeignKey(VehicleModel)
Form:
class DynamicChoiceField(ModelChoiceField):
def clean(self, value):
return value
class MyForm(ModelForm):
category = ModelChoiceField(VehicleCategory.objects, widget=forms.Select(attrs={'onchange':'FilterMakes();'}))
make = DynamicChoiceField(VehicleMake.objects,widget=forms.Select(attrs={'disabled':'true','onchange':'FilterModels();'}), empty_label="Select Model")
model = DynamicChoiceField(VehicleModel.objects,widget=forms.Select(attrs={'disabled':'true'}), empty_label="Select Make")
class Meta:
model = Listing
View:
def new_listing(request):
if request.method == 'POST':
form = MyForm(request.POST)
if form.is_valid():
form.save()
else:
form = MyForm()
return render_to_response("newlisting.html", {
"form": form,'model_id':model_id,'make_id':make_id
})
I also have some ajax defined for the auto-populate but this is not the problem
When I submit the form I get the following:
Cannot assign "u'2'": "Listing.make" must be a "VehicleMake" instance.
if I try
make=VehicleMake.objects.get(pk=request.POST['make'])
form.fields['make'] = make
then I get
'VehicleMake' object has no attribute 'widget'
After the suggestion of one of the commenter's that the DynamicChoiceField class was the culprit I removed it and set the form objects for ModelChoiceFields with the exact same other parameters. The object appears to pass and validate correctly as well. The extra class existed based on an old tutorial I found. it appears that what the author did there works with the forms.ChoiceField but is not required for using a ModelChoiceField
thanks everyone for the help

Resources