Sending instance to ModelForm with custom fields - django-forms

I have a form for managing users, a ModelForm type. But for two fields I need a RegexField to validate my data. Because of that I needed to override those fields. But now when I open the form in edit mode (when sending instance of my user) I get no data loaded in both fields. How to avoid it ? Should I forget about regex field and create a custem clean method for them ?
class UserForm(forms.ModelForm):
pid = forms.RegexField(regex=r'^\d{11}', max_length=11 ,widget=forms.TextInput(attrs=dict(attrs_dict, maxlength=50)), error_messages=my_default_errors)
code = forms.RegexField(regex=r'^\d{2}[-]\d{3}', max_length=6, widget=forms.TextInput(attrs=attrs_dict), label="Postal code", error_messages=my_default_errors)
class Meta:
model = UserProfile
exclude = ( 'user', 'image', 'pid' , 'code')
model :
class UserProfile(models.Model):
def upload_path(self, field_attname):
filename = hashlib.md5(field_attname).hexdigest()[:4] + "_" + field_attname
return settings.MEDIA_ROOT + "/uploads/users/%s" % (filename,)
first_name = models.CharField("Name", max_length=50, blank=True, null=True)
last_name = models.CharField("Last name", max_length=50, blank=True, null=True)
pid = models.CharField("PESEL", max_length=11, blank=True, null=True)
street = models.CharField("Street", max_length=50, blank=True, null=True)
number = models.CharField("Flat/house number", max_length=10, blank=True, null=True)
code = models.CharField("Zip ", max_length=6, blank=True, null=True)
city = models.CharField("City", max_length=50, blank=True, null=True)
user = models.ForeignKey(User, unique=True, related_name='profile')
image = models.ImageField(upload_to=upload_path, verbose_name="Image", blank=True, null=True)

You set the new field type, which is correct, but then you exclude them from being handled for the model, which is not. Remove them from Meta.exclude.

Related

Either provide a url or define a get_absolute_url method on the Model

Trying to have the user who wants to update a product that they already created, to be able to update and be redirected to a page.
HERE IS THE ERROR I'M RUNNING INTO:
Exception Type: NoReverseMatch
Exception Value:
Reverse for 'updatelisting' not found. 'updatelisting' is not a valid view function or pattern name.
HERE IS MY FORMS.PY FILE:
class ProductForm(ModelForm):
class Meta:
model = listing
fields = '__all__'
HERE IS MY VIEWS.PY FILE WITH THE RELATED VIEW:
from django.views.generic import UpdateView
class UpdateListing(UpdateView):
model = listing
template_name = 'update_listing.html'
fields = '__all__'
HERE IS MY URLS.PY FILE WITH THE RELATED URLS TO THE RELATED VIEWS:
I have set the urls main name to vendor.
app_name = 'vendor'
path('createlisting/', views.index, name='index'),
path('renderindex/', views.renderindex, name='renderindex'),
path('listing/edit/<int:pk>', views.UpdateListing.as_view(), name='updatelisting'),
HERE IS MY MODELS.PY FILE WITH THE RELATED MODEL TO THIS PROBLEM:
class listing(models.Model):
image = models.ImageField(blank=True, null=True)
name = models.CharField(max_length=255)
description = models.TextField()
unit_price = models.DecimalField(max_digits=6, decimal_places=2, validators=[MinValueValidator(1)])
inventory = models.IntegerField()
last_update = models.DateTimeField(auto_now=True)
collection = models.ForeignKey(Collection, on_delete=models.PROTECT, blank=True, null=True)
vendors = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=False)
def get_absolute_url(self):
return reverse('updatelisting', args=(str(self.id)))
It's funny because when I refresh the page it then says that the 'updatelisting' is not a pattern name or view name but it is a pattern name, I'm not sure why it is not identifying the pattern name which is ( updatelisting ). If you need anymore info let me know please. I thankyou for the help!

filter API response based on URL parameters that both exactly matches and also the substring of the parameter matches in Django

I need to filter API response based on URL parameters that both exact match and also the substring of the parameter matches in Django.
The API call would be : "http://127.0.0.1:8000/showjoineduserdata?phonenumber=3349279_copy&firstname=Olivier_copy"
**models.py**
from django.db import models
class Joineduserdatanew(models.Model):
surname = models.TextField(db_column='Surname', blank=True, null=True) # Field name made lowercase.
firstname = models.TextField(db_column='Firstname', blank=True, null=True) # Field name made lowercase.
phonenumber = models.TextField(db_column='PhoneNumber', blank=True, null=True) # Field name made lowercase.
email = models.TextField(db_column='Email', blank=True, null=True) # Field name made lowercase.
login = models.TextField(db_column='Login', blank=True, null=True) # Field name made lowercase.
racfid = models.TextField(db_column='RACFid', blank=True, null=True) # Field name made lowercase.
assignee = models.TextField(db_column='Assignee', blank=True, null=True) # Field name made lowercase.
company_or_group = models.TextField(db_column='Company_or_Group', blank=True, null=True) # Field name made lowercase.
groupname = models.TextField(db_column='GroupName', blank=True, null=True) # Field name made lowercase.
admin = models.TextField(db_column='Admin', blank=True, null=True) # Field name made lowercase.
usertype = models.TextField(db_column='UserType', blank=True, null=True) # Field name made lowercase.
segid = models.TextField(blank=True, null=True)
roleid = models.IntegerField(blank=True, null=True)
segment = models.TextField(blank=True, null=True)
role = models.TextField(blank=True, null=True)
sno = models.AutoField(primary_key=True)
class Meta:
managed = False
db_table = 'joineduserdatanew'
**serialize.py**
from dataclasses import field
from rest_framework import serializer
from usersearch_api.models import Joineduserdatanew
class JoineduserdatanewSerialization(serializers.ModelSerializer):
class Meta:
model=Joineduserdatanew
fields=('surname','firstname','phonenumber','email','login','racfid','assignee','company_or_group','groupname','segment','role','admin','usertype')
**views.py**
from usersearch_api.serialization import JoineduserdatanewSerialization
from rest_framework.response import Response
from rest_framework.decorators import api_view
from usersearch_api.models import Joineduserdatanew
from rest_framework.generics import ListAPIView
from rest_framework.viewsets import ModelViewSet
class UserSearchAPIView(ListAPIView):
serializer_class=JoineduserdatanewSerialization
queryset=Joineduserdatanew.objects.all()
#filter_class = UserDataFilter
filter_backends = [DjangoFilterBackend]
filterset_fields = ['surname','firstname','login','racfid','assignee','phonenumber','company_or_group','email','segment']
please install django-filter library, for installation follow this procedure
https://django-filter.readthedocs.io/en/stable/guide/install.html
import django_filters
class PostFilter(django_filters.FilterSet):
class Meta:
model = Post
fields = {
'title': ["exact"], # for exact match
"desc" : ["contains"] # partial match
# similarly you can add your new fields with filtering condition...
}
class PostList(ListAPIView):
queryset = Post.objects.all()
serializer_class = PostSerializer
filter_backends = [DjangoFilterBackend]
filter_class = PostFilter
class UserSearchFilterAPIView(APIView):
def get(self,request,*args,**kargs):
queryset=Joineduserdatanew.objects.all()
#Custom filter
surname=self.request.query_params.get('surname',None)
firstname=self.request.query_params.get('firstname',None)
login=self.request.query_params.get('login',None)
racfid=self.request.query_params.get('racfid',None)
assignee=self.request.query_params.get('assignee',None)
phonenumber=self.request.query_params.get('phonenumber',None)
company_or_group=self.request.query_params.get('company_or_group',None)
email=self.request.query_params.get('email',None)
segment=self.request.query_params.get('segment',None)
if surname:
queryset=queryset.filter(surname__icontains=surname)
if firstname:
queryset=queryset.filter(firstname__icontains=firstname)
if login:
queryset=queryset.filter(login__icontains=login)
if racfid:
queryset=queryset.filter(racfid__icontains=racfid)
if assignee:
queryset=queryset.filter(assignee__icontains=assignee)
if phonenumber:
queryset=queryset.filter(phonenumber__icontains=phonenumber)
if company_or_group:
queryset=queryset.filter(company_or_group__icontains=company_or_group)
if email:
queryset=queryset.filter(email__icontains=email)
if segment:
queryset=queryset.filter(segment__icontains=segment)
serializer=JoineduserdatanewSerialization(queryset,many=True)
return Response(serializer.data)
Here the necessary fields are got and on each of them filters are applied, so if the API endpoint contains at least any of the parameters it filters based on it, and multiple parameters are added as 'and'.This is how I filtered the API response as needed.

DRF read_only fields not being ignored when saving

I am using Django 2.2.23 and Django Rest Framework 3.7.7. I have models and serialisers as follows:
class PurchaseOrder(models.Model):
uid = models.UUIDField(primary_key=True, default=uuid4, editable=False)
order_number = models.IntegerField(null=True, blank=True)
contact = models.ForeignKey(SupplierContact, on_delete=models.SET_NULL, null=True)
class SupplierContact(models.Model):
uid = models.UUIDField(primary_key=True, default=uuid4, editable=False)
name = models.CharField(max_length=100, null=True, blank=True)
class PurchaseOrderSerializer(serializers.ModelSerializer):
contact_name = serializers.CharField(read_only=True, source='contact.name', default='')
class Meta:
model = PurchaseOrder
fields = ['uid', 'order_number', 'contact_name']
Doing
serializer = PurchaseOrderSerializer({'order_number': 1234})
serializer.save()
results in *** ValueError: Cannot assign "{'name': ''}": "PurchaseOrder.contact" must be a "SupplierContact" instance.
where I would've thought the read_only=True on the contact_name field would exclude it from saving. What am I missing?

DRF - Add User to a model with ManyToManyField

I am trying to implement a feature to my backend and allow the owner of private "Group" to add other users by their usernames instead of ID's and allow them to add their images to FileField only once after they were added to the model. The code I have so far:
models.py
class Group(models.Model):
group_name = models.CharField(max_length=255)
group_text = models.TextField(max_length=360, blank=True)
owner = models.ForeignKey(
settings.AUTH_USER_MODEL, related_name='owner_user', on_delete=models.SET(get_deleted_user), default=1)
created_on = models.DateTimeField(auto_now_add=True, null=True)
shared_to = models.ManyToManyField(UserProfile, blank=True, related_name='shared_to_user', null=True)
def __str__(self):
return self.group_name
def save(self, *args, **kwargs):
super(Group, self).save(*args, **kwargs)
class GroupImage(models.Model):
group_file = models.FileField(blank=True, null=True,
upload_to='media/covers/%Y/%m/%D/')
gallery_group = models.ForeignKey(Group, related_name='images', on_delete=models.CASCADE)
serializers.py
class GroupImageSerializer(serializers.ModelSerializer):
class Meta:
model = models.GroupImage
fields = ('group_file', )
class SharedToSerializer(serializers.ModelSerializer):
class Meta:
model = models.Group
fields = ('shared_to', )
class GroupSerializer(serializers.ModelSerializer):
images = GroupImageSerializer(many=True, read_only=True)
person = SharedToSerializer(many=True, read_only=True)
class Meta:
model = models.Group
fields = ('id', 'group_name', 'group_text', 'person', 'images')
def create(self, validated_data):
images_data = self.context.get('view').request.FILES
owner_id = self.context['request'].user.id
gallery_group = models.Group.objects.create(group_name=validated_data.get('group_name', 'no-
group_name'), group_text=validated_data.get('group_text'), owner_id=1)
for image_data in images_data.values():
models.GroupImage.objects.create(gallery_group=gallery_group,
group_file=image_data)
return gallery_group
views.py
class GroupCreateAPIView(generics.CreateAPIView):
queryset = models.Group.objects.all()
serializer_class = serializers.GroupSerializer
permission_classes = [AllowAny]
So if your only requirement is how to add users by their username and not their id. You should use SlugRelatedField. I also feel your serializer naming convention is quite confusing. Below is the serializer for Group model that can add users to a group.
class GroupSerializer(Serializer):
... other fields here
shared_to = models.SlugRelatedField(queryset = UserProfile.objects.all(), many=True, slug_field="username", allow_empty=True)
So first checkout SlugRelatedField. This basically is used to map to objects using a specific field of that object(username in this case). You will then get all the UserProfile instances in the shared_to field of the validated_data
property of the serializer which you can fetch in create method and add to you group. And then in the file upload api for your group you can check whether this user belongs to the group or not for permission checking.

autocomplete-light for adding popup outside the admin

I'm using django-crispy-forms and would like to use autocomplete-light but can't get it going. I need users to be able to create a new facility if the one they want doesn't exist.
I just have no idea how to use autocomplete-light and I've been struggling for days. Can someone please point me in the right direction??
models.py
class CollectionFacility(TimeStampedModel):
"""
Data collection facility.
"""
facility_name = models.CharField(max_length=256, blank=False)
address_line1 = models.CharField("Address line 1", max_length=45)
address_line2 = models.CharField("Address line 2", max_length=45, blank=True)
country = models.CharField(max_length=50, blank=False)
state_province = models.CharField(max_length=100, blank=True)
city = models.CharField(max_length=100, blank=False)
postal_code = models.CharField("Postal Code", max_length=20, blank=True)
facility_contact = models.ForeignKey('FacilityContact', related_name='collection_facilities', null=True, blank=True)
def __unicode__(self):
return "%s, %s" % (self.facility_name, self.country)
class Meta:
ordering = ['country', 'facility_name', 'city', 'state_province']
verbose_name = "Collection Facility"
verbose_name_plural = "Collection Facilities"
class FacilityContact(TimeStampedModel):
TITLES = (
('Mrs.', 'Mrs.'),
('Ms.', 'Ms.'),
('Mr.', 'Mr.'),
('Dr.', 'Dr.'),
)
first_name = models.CharField(max_length=256, blank=False)
middle_initial = models.CharField(max_length=4, blank=True)
last_name = models.CharField(max_length=256, blank=False)
title = models.CharField(max_length=4, choices=TITLES, blank=True)
email = models.EmailField(blank=False)
def __unicode__(self):
return "%s, %s" % (self.last_name, self.first_name)
class Meta:
ordering = ['last_name', 'first_name']
verbose_name = "Facility Contact"
verbose_name_plural = "Facility Contacts"
forms.py
class FacilityForm(autocomplete_light.ModelForm):
class Meta:
model = CollectionFacility
views.py
facility_form = FacilityForm()
# pass it in the context to template
....
template.html
{% crispy facility_form %}
Did you check the non_admin_add_another example app ?
Docs about that one have not yet been ported to v2 which mean the code in the docs might not work. However note that autocomplete_light.example_apps.non_admin_add_another should work.
I recommend you start fiddling with that example directly in autocomplete_light's test_project, see: http://django-autocomplete-light.readthedocs.org/en/stable-2.x.x/demo.html

Resources